feat: WIP
This commit is contained in:
72
module/oc_telegram_shop/upload/catalog/controller/tgshop/handle.php
Executable file
72
module/oc_telegram_shop/upload/catalog/controller/tgshop/handle.php
Executable file
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
use App\ApplicationFactory;
|
||||
use Cart\Currency;
|
||||
use Cart\Tax;
|
||||
|
||||
$sysLibPath = rtrim(DIR_SYSTEM, '/') . '/library/oc_telegram_shop';
|
||||
$basePath = rtrim(DIR_APPLICATION, '/') . '/..';
|
||||
if (is_readable($sysLibPath . '/oc_telegram_shop.phar')) {
|
||||
require_once "phar://{$sysLibPath}/oc_telegram_shop.phar/vendor/autoload.php";
|
||||
} elseif (is_dir("$basePath/oc_telegram_shop")) {
|
||||
require_once "$basePath/oc_telegram_shop/vendor/autoload.php";
|
||||
} else {
|
||||
throw new RuntimeException('Unable to locate bulk products directory.');
|
||||
}
|
||||
|
||||
class Controllertgshophandle extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$app = ApplicationFactory::create([
|
||||
'oc_config_tax' => $this->config->get('config_tax'),
|
||||
'oc_currency' => $this->session->data['currency'],
|
||||
'timezone' => $this->config->get('config_timezone', 'UTC'),
|
||||
'lang' => $this->config->get('config_admin_language'),
|
||||
'language_id' => (int)$this->config->get('config_language_id'),
|
||||
'shop_base_url' => HTTPS_SERVER,
|
||||
'dir_image' => DIR_IMAGE,
|
||||
'db' => [
|
||||
'host' => DB_HOSTNAME,
|
||||
'database' => DB_DATABASE,
|
||||
'username' => DB_USERNAME,
|
||||
'password' => DB_PASSWORD,
|
||||
'prefix' => DB_PREFIX,
|
||||
],
|
||||
'logs' => [
|
||||
'path' => DIR_LOGS,
|
||||
],
|
||||
]);
|
||||
|
||||
$app->bind(Url::class, function () {
|
||||
return $this->url;
|
||||
});
|
||||
|
||||
$app->bind(Currency::class, function () { return $this->currency; });
|
||||
$app->bind(Tax::class, function () { return $this->tax; });
|
||||
|
||||
$this->load->model('tool/image');
|
||||
$app->bind('image_resize', function () {
|
||||
return function ($path, $width, $height) {
|
||||
if (is_file(DIR_IMAGE . $path)) {
|
||||
return $this->model_tool_image->resize($path, $width, $height);
|
||||
}
|
||||
|
||||
return $this->model_tool_image->resize('no_image.png', $width, $height);
|
||||
};
|
||||
});
|
||||
|
||||
$this->load->model('checkout/order');
|
||||
|
||||
$app->bind('model_checkout_order', function () {
|
||||
return $this->model_checkout_order;
|
||||
});
|
||||
|
||||
$app->bootAndHandleRequest();
|
||||
}
|
||||
|
||||
public function spa()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
27
module/oc_telegram_shop/upload/oc_telegram_shop/composer.json
Executable file
27
module/oc_telegram_shop/upload/oc_telegram_shop/composer.json
Executable file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": "nikitakiselev/oc_telegram_shop",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Openguru\\OpenCartFramework\\": "framework/",
|
||||
"App\\": "src/"
|
||||
},
|
||||
"files": [
|
||||
"framework/Support/helpers.php"
|
||||
]
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nikita Kiselev",
|
||||
"email": "mail@nikitakiselev.ru"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": "^7.4",
|
||||
"ext-pdo": "*",
|
||||
"psr/container": "^2.0",
|
||||
"ext-json": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"roave/security-advisories": "dev-latest"
|
||||
}
|
||||
}
|
||||
1033
module/oc_telegram_shop/upload/oc_telegram_shop/composer.lock
generated
Executable file
1033
module/oc_telegram_shop/upload/oc_telegram_shop/composer.lock
generated
Executable file
File diff suppressed because it is too large
Load Diff
113
module/oc_telegram_shop/upload/oc_telegram_shop/framework/Application.php
Executable file
113
module/oc_telegram_shop/upload/oc_telegram_shop/framework/Application.php
Executable file
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Openguru\OpenCartFramework\Config\Settings;
|
||||
use Openguru\OpenCartFramework\Container\Container;
|
||||
use Openguru\OpenCartFramework\Http\JsonResponse;
|
||||
use Openguru\OpenCartFramework\Http\Request;
|
||||
use Openguru\OpenCartFramework\Logger\Logger;
|
||||
use Openguru\OpenCartFramework\Router\Router;
|
||||
use Openguru\OpenCartFramework\Support\ExecutionTimeProfiler;
|
||||
|
||||
class Application extends Container
|
||||
{
|
||||
private static Application $instance;
|
||||
private static array $events = [];
|
||||
private array $serviceProviders = [];
|
||||
|
||||
/**
|
||||
* @var ExecutionTimeProfiler
|
||||
*/
|
||||
private ExecutionTimeProfiler $profiler;
|
||||
|
||||
public static function getInstance(): Application
|
||||
{
|
||||
return static::$instance;
|
||||
}
|
||||
|
||||
private function bootKernelServices(): void
|
||||
{
|
||||
$this->singleton(ExecutionTimeProfiler::class, function () {
|
||||
return new ExecutionTimeProfiler();
|
||||
});
|
||||
|
||||
$this->profiler = $this->get(ExecutionTimeProfiler::class);
|
||||
$this->profiler->start();
|
||||
|
||||
$this->singleton(Container::class, function (Container $container) {
|
||||
return $container;
|
||||
});
|
||||
|
||||
$this->singleton(Logger::class, function (Container $container) {
|
||||
$path = $container->getConfigValue('logs.path') . '/oc_telegram_shop.log';
|
||||
return new Logger($path, Logger::LEVEL_INFO);
|
||||
});
|
||||
|
||||
$this->singleton(Settings::class, function (Container $container) {
|
||||
return new Settings($container->getConfigValue());
|
||||
});
|
||||
|
||||
$errorHandler = new ErrorHandler(
|
||||
$this->get(Logger::class)
|
||||
);
|
||||
|
||||
$errorHandler->register();
|
||||
}
|
||||
|
||||
public function boot(): Application
|
||||
{
|
||||
$this->bootKernelServices();
|
||||
|
||||
$this->initializeEventDispatcher(static::$events);
|
||||
|
||||
DependencyRegistration::register($this, $this->serviceProviders);
|
||||
|
||||
static::$instance = $this;
|
||||
|
||||
$this->profiler->addCheckpoint('Bootstrap Application');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function handleRequest(Request $request): JsonResponse
|
||||
{
|
||||
$this->bind(Request::class, function () use ($request) {
|
||||
return $request;
|
||||
});
|
||||
|
||||
$router = $this->get(Router::class);
|
||||
$apiAction = $request->get('api_action');
|
||||
$action = $router->resolve($apiAction);
|
||||
|
||||
[$controller, $method] = $action;
|
||||
|
||||
if (!class_exists($controller) || !method_exists($controller, $method)) {
|
||||
throw new InvalidArgumentException('Invalid action: ' . $controller . '->' . $method);
|
||||
}
|
||||
|
||||
$this->profiler->addCheckpoint('Handle Router.');
|
||||
|
||||
$response = $this->call($controller, $method);
|
||||
|
||||
$this->profiler->addCheckpoint('Handle HTTP request.');
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
public function bootAndHandleRequest(): void
|
||||
{
|
||||
$this->boot();
|
||||
$request = Request::createFromGlobals();
|
||||
$response = $this->handleRequest($request);
|
||||
$response->send();
|
||||
}
|
||||
|
||||
public function withServiceProviders(array $serviceProviders): Application
|
||||
{
|
||||
$this->serviceProviders = $serviceProviders;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework\Cache;
|
||||
|
||||
interface CacheInterface
|
||||
{
|
||||
public function get(string $key);
|
||||
public function set(string $key, $value, ?int $ttlSeconds = null): void;
|
||||
public function delete(string $key): void;
|
||||
public function clear(): void;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework\Cache;
|
||||
|
||||
use Openguru\OpenCartFramework\Config\Settings;
|
||||
use Openguru\OpenCartFramework\Container\Container;
|
||||
use Openguru\OpenCartFramework\Container\ServiceProvider;
|
||||
use Openguru\OpenCartFramework\QueryBuilder\Connections\ConnectionInterface;
|
||||
|
||||
class CacheServiceProvider extends ServiceProvider
|
||||
{
|
||||
public function register(): void
|
||||
{
|
||||
$this->container->singleton(CacheInterface::class, function (Container $container) {
|
||||
return new DatabaseCache(
|
||||
$container->get(ConnectionInterface::class),
|
||||
$container->get(Settings::class)->get('tables.cache'),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework\Cache;
|
||||
|
||||
use Openguru\OpenCartFramework\QueryBuilder\Connections\ConnectionInterface;
|
||||
use Openguru\BulkProducts\Modules\Shared\Cache\CacheInterface;
|
||||
|
||||
class DatabaseCache implements CacheInterface
|
||||
{
|
||||
private $connection;
|
||||
private $table;
|
||||
|
||||
public function __construct(ConnectionInterface $connection, string $table)
|
||||
{
|
||||
$this->connection = $connection;
|
||||
$this->table = $table;
|
||||
}
|
||||
|
||||
public function get(string $key)
|
||||
{
|
||||
$cache = $this->connection->select(
|
||||
"
|
||||
SELECT result
|
||||
FROM $this->table
|
||||
WHERE cache_key = :key AND (expires_at IS NULL OR expires_at > NOW())
|
||||
",
|
||||
[':key' => $key]
|
||||
);
|
||||
|
||||
return $cache ? unserialize($cache[0]['result'], ['allowed_classes' => true]) : null;
|
||||
}
|
||||
|
||||
public function set(string $key, $value, ?int $ttlSeconds = null): void
|
||||
{
|
||||
$this->connection->statement("DELETE FROM $this->table WHERE expires_at IS NOT NULL AND expires_at <= NOW()");
|
||||
|
||||
$expiresAt = $ttlSeconds ? date('Y-m-d H:i:s', time() + $ttlSeconds) : null;
|
||||
|
||||
$sql = <<<SQL
|
||||
INSERT INTO $this->table (cache_key, result, expires_at)
|
||||
VALUES (:key, :result, :expiresAt)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
result = VALUES(result),
|
||||
expires_at = VALUES(expires_at)
|
||||
SQL;
|
||||
|
||||
$this->connection->statement($sql, [
|
||||
':key' => $key,
|
||||
':result' => serialize($value),
|
||||
':expiresAt' => $expiresAt,
|
||||
]);
|
||||
}
|
||||
|
||||
public function delete(string $key): void
|
||||
{
|
||||
$this->connection->statement("DELETE FROM $this->table WHERE cache_key = :key", [':key' => $key]);
|
||||
}
|
||||
|
||||
public function clear(): void
|
||||
{
|
||||
$this->connection->truncateTable($this->table);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework\Config;
|
||||
|
||||
use Openguru\OpenCartFramework\Support\Arr;
|
||||
|
||||
class Settings
|
||||
{
|
||||
private $settings;
|
||||
|
||||
public function __construct(array $initialSettings = [])
|
||||
{
|
||||
$this->settings = $initialSettings;
|
||||
}
|
||||
|
||||
public function get(string $key, $default = null)
|
||||
{
|
||||
return Arr::get($this->settings, $key, $default);
|
||||
}
|
||||
|
||||
public function set(string $key, $value): void
|
||||
{
|
||||
Arr::set($this->settings, $key, $value);
|
||||
}
|
||||
|
||||
public function has(string $key): bool
|
||||
{
|
||||
return Arr::get($this->settings, $key) !== null;
|
||||
}
|
||||
|
||||
public function remove(string $key): void
|
||||
{
|
||||
Arr::unset($this->settings, $key);
|
||||
}
|
||||
|
||||
public function getAll(): array
|
||||
{
|
||||
return $this->settings;
|
||||
}
|
||||
|
||||
public function setAll(array $settings): void
|
||||
{
|
||||
$this->settings = $settings;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework\Container;
|
||||
|
||||
use Openguru\OpenCartFramework\Events\EventDispatcher;
|
||||
use Openguru\OpenCartFramework\Exceptions\ContainerDependencyResolutionException;
|
||||
use Openguru\OpenCartFramework\Http\JsonResponse;
|
||||
use Openguru\OpenCartFramework\Support\Arr;
|
||||
use Phar;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use ReflectionClass;
|
||||
use ReflectionException;
|
||||
use ReflectionMethod;
|
||||
use ReflectionNamedType;
|
||||
use RuntimeException;
|
||||
|
||||
if (!defined('BP_BASE_PATH')) {
|
||||
$phar = Phar::running(false);
|
||||
define('BP_BASE_PATH', $phar ? "phar://$phar" : dirname(__DIR__) . '/..');
|
||||
}
|
||||
|
||||
class Container implements ContainerInterface
|
||||
{
|
||||
private array $factories = [];
|
||||
private array $instances = [];
|
||||
private array $config;
|
||||
private $taggedAbstracts = [];
|
||||
|
||||
public function __construct(array $config)
|
||||
{
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
public function getConfigValue(?string $key = null, $default = null)
|
||||
{
|
||||
if ($key === null) {
|
||||
return $this->config;
|
||||
}
|
||||
|
||||
return Arr::get($this->config, $key, $default);
|
||||
}
|
||||
|
||||
public function has(string $id): bool
|
||||
{
|
||||
return array_key_exists($id, $this->factories);
|
||||
}
|
||||
|
||||
public function bind(string $abstract, callable $concrete, bool $singleton = false): void
|
||||
{
|
||||
$this->factories[$abstract] = [
|
||||
'concrete' => $concrete,
|
||||
'singleton' => $singleton,
|
||||
];
|
||||
}
|
||||
|
||||
public function singleton(string $abstract, callable $concrete): void
|
||||
{
|
||||
$this->bind($abstract, $concrete, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @param string $id
|
||||
* @return T
|
||||
* @psalm-param class-string<T>|string $id
|
||||
* @psalm-suppress MoreSpecificImplementedParamType
|
||||
*/
|
||||
public function get(string $id)
|
||||
{
|
||||
try {
|
||||
if ($this->has($id)) {
|
||||
if ($this->factories[$id]['singleton']) {
|
||||
if (!array_key_exists($id, $this->instances)) {
|
||||
$this->instances[$id] = $this->factories[$id]['concrete']($this);
|
||||
}
|
||||
|
||||
return $this->instances[$id];
|
||||
}
|
||||
|
||||
return $this->factories[$id]['concrete']($this);
|
||||
}
|
||||
|
||||
if (class_exists($id)) {
|
||||
$reflection = new ReflectionClass($id);
|
||||
$constructor = $reflection->getConstructor();
|
||||
|
||||
$arguments = [];
|
||||
|
||||
if ($constructor && $parameters = $constructor->getParameters()) {
|
||||
foreach ($parameters as $parameter) {
|
||||
if ($parameter->getType() instanceof ReflectionNamedType) {
|
||||
$parameterType = $parameter->getType()->getName();
|
||||
/** @psalm-suppress ArgumentTypeCoercion */
|
||||
$arguments[] = $this->get($parameterType);
|
||||
} else {
|
||||
$arguments[] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @var T $instance */
|
||||
$instance = $reflection->newInstanceArgs($arguments);
|
||||
|
||||
return $instance;
|
||||
}
|
||||
} catch (ReflectionException $exception) {
|
||||
throw new ContainerDependencyResolutionException(
|
||||
'Could not resolve the concrete: ' . $id . '. ' . $exception->getMessage()
|
||||
);
|
||||
}
|
||||
|
||||
throw new ContainerDependencyResolutionException(
|
||||
'Could not resolve the concrete: ' . $id . ' (class does not exist)'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param class-string $abstract
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
public function call(string $abstract, string $method): JsonResponse
|
||||
{
|
||||
if (!class_exists($abstract)) {
|
||||
throw new ContainerDependencyResolutionException('Could not resolve the concrete: ' . $abstract);
|
||||
}
|
||||
|
||||
if (!method_exists($abstract, $method)) {
|
||||
throw new ContainerDependencyResolutionException('Method not found: ' . $abstract . '@' . $method);
|
||||
}
|
||||
|
||||
$instance = $this->get($abstract);
|
||||
|
||||
$reflection = new ReflectionMethod($instance, $method);
|
||||
|
||||
$arguments = [];
|
||||
foreach ($reflection->getParameters() as $parameter) {
|
||||
if ($parameter->getType() instanceof ReflectionNamedType) {
|
||||
$parameterType = $parameter->getType()->getName();
|
||||
/** @psalm-suppress ArgumentTypeCoercion */
|
||||
$arguments[] = $this->get($parameterType);
|
||||
} else {
|
||||
$arguments[] = null;
|
||||
}
|
||||
}
|
||||
|
||||
return $instance->{$method}(...$arguments);
|
||||
}
|
||||
|
||||
public function registerEventListener(string $eventClass, string $listenerClass): void
|
||||
{
|
||||
$dispatcher = $this->get(EventDispatcher::class);
|
||||
|
||||
$dispatcher->registerListener($eventClass, $listenerClass);
|
||||
}
|
||||
|
||||
public function initializeEventDispatcher(array $listeners): void
|
||||
{
|
||||
$this->singleton(EventDispatcher::class, function (Container $container) {
|
||||
return new EventDispatcher($container);
|
||||
});
|
||||
|
||||
foreach ($listeners as $eventClass => $listenerClasses) {
|
||||
foreach ($listenerClasses as $listenerClass) {
|
||||
$this->registerEventListener($eventClass, $listenerClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function tag(string $tag, array $abstracts): void
|
||||
{
|
||||
if (array_key_exists($tag, $this->taggedAbstracts)) {
|
||||
throw new RuntimeException('Tag already exists: ' . $tag);
|
||||
}
|
||||
|
||||
$this->taggedAbstracts[$tag] = $abstracts;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework\Container;
|
||||
|
||||
abstract class ServiceProvider
|
||||
{
|
||||
/** @var Container $container */
|
||||
protected $container;
|
||||
|
||||
public function __construct(Container $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
abstract public function register(): void;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework\Contracts;
|
||||
|
||||
interface Arrayable
|
||||
{
|
||||
/**
|
||||
* Convert the object to an array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toArray(): array;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework;
|
||||
|
||||
use Openguru\OpenCartFramework\Container\Container;
|
||||
use Openguru\OpenCartFramework\Container\ServiceProvider;
|
||||
use Openguru\OpenCartFramework\Settings\DatabaseUserSettings;
|
||||
use Openguru\OpenCartFramework\Settings\UserSettingsInterface;
|
||||
use RuntimeException;
|
||||
|
||||
class DependencyRegistration
|
||||
{
|
||||
public static function register(Container $container, array $serviceProviders = []): void
|
||||
{
|
||||
$container->singleton(UserSettingsInterface::class, function (Container $container) {
|
||||
return $container->get(DatabaseUserSettings::class);
|
||||
});
|
||||
|
||||
static::registerServiceProviders($container, $serviceProviders);
|
||||
}
|
||||
|
||||
private static function registerServiceProviders(Container $container, array $serviceProviders): void
|
||||
{
|
||||
foreach ($serviceProviders as $serviceProvider) {
|
||||
$provider = $container->get($serviceProvider);
|
||||
if (!$provider instanceof ServiceProvider) {
|
||||
throw new RuntimeException('ServiceProvider must extend ServiceProvider');
|
||||
}
|
||||
|
||||
$provider->register();
|
||||
}
|
||||
}
|
||||
}
|
||||
93
module/oc_telegram_shop/upload/oc_telegram_shop/framework/ErrorHandler.php
Executable file
93
module/oc_telegram_shop/upload/oc_telegram_shop/framework/ErrorHandler.php
Executable file
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework;
|
||||
|
||||
use ErrorException;
|
||||
use Openguru\OpenCartFramework\Exceptions\NonLoggableExceptionInterface;
|
||||
use Openguru\OpenCartFramework\Http\JsonResponse;
|
||||
use Openguru\OpenCartFramework\Http\Response;
|
||||
use Openguru\OpenCartFramework\Logger\Logger;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
class ErrorHandler
|
||||
{
|
||||
private $logger;
|
||||
|
||||
public function __construct(Logger $logger)
|
||||
{
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
public function register(): void
|
||||
{
|
||||
set_error_handler([$this, 'handleError']);
|
||||
set_exception_handler([$this, 'handleException']);
|
||||
register_shutdown_function([$this, 'handleShutdown']);
|
||||
}
|
||||
|
||||
public function handleError(int $severity, string $message, string $file, int $line): bool
|
||||
{
|
||||
$this->logger->error('Handled PHP error: ' . implode(', ', compact('severity', 'message', 'file', 'line')));
|
||||
|
||||
// Convert warnings and notices to ErrorException
|
||||
if (!(error_reporting() & $severity)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
throw new ErrorException($message, 0, $severity, $file, $line);
|
||||
}
|
||||
|
||||
public function handleException(Throwable $exception): void
|
||||
{
|
||||
if (!$exception instanceof NonLoggableExceptionInterface) {
|
||||
$this->logger->logException($exception);
|
||||
}
|
||||
|
||||
if (PHP_SAPI === 'cli') {
|
||||
echo $exception->getMessage() . PHP_EOL;
|
||||
} else {
|
||||
(new JsonResponse([
|
||||
'exception' => get_class($exception),
|
||||
'message' => $exception->getMessage(),
|
||||
'file' => $exception->getFile(),
|
||||
'line' => $exception->getLine(),
|
||||
'trace' => $exception->getTrace(),
|
||||
], Response::HTTP_INTERNAL_SERVER_ERROR))->send();
|
||||
}
|
||||
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
public function handleShutdown(): void
|
||||
{
|
||||
$error = error_get_last();
|
||||
|
||||
if ($error !== null && in_array($error['type'], [E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR], true)) {
|
||||
$message = sprintf(
|
||||
"[%s] Fatal error: %s in %s:%d",
|
||||
date('Y-m-d H:i:s'),
|
||||
$error['message'],
|
||||
$error['file'],
|
||||
$error['line']
|
||||
);
|
||||
|
||||
$this->logger->error($message);
|
||||
|
||||
if (PHP_SAPI === 'cli') {
|
||||
echo $message . PHP_EOL;
|
||||
} else {
|
||||
(new JsonResponse([
|
||||
'message' => $message,
|
||||
'file' => $error['file'],
|
||||
'line' => $error['line'],
|
||||
], Response::HTTP_INTERNAL_SERVER_ERROR))->send();
|
||||
}
|
||||
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework\Events;
|
||||
|
||||
interface Event
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework\Events;
|
||||
|
||||
use Openguru\OpenCartFramework\Container\Container;
|
||||
|
||||
class EventDispatcher
|
||||
{
|
||||
private $listeners = [];
|
||||
private $container;
|
||||
|
||||
public function __construct(Container $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
public function registerListener(string $eventClass, string $listenerClass): void
|
||||
{
|
||||
$this->listeners[$eventClass][] = $listenerClass;
|
||||
}
|
||||
|
||||
public function dispatch(Event $event): void
|
||||
{
|
||||
$eventClass = get_class($event);
|
||||
if (isset($this->listeners[$eventClass])) {
|
||||
foreach ($this->listeners[$eventClass] as $listenerClass) {
|
||||
$listener = $this->container->get($listenerClass);
|
||||
$listener->handle($event);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework\Events;
|
||||
|
||||
interface Listener
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework\Exceptions;
|
||||
|
||||
use Exception;
|
||||
|
||||
class ActionNotFoundException extends Exception implements NonLoggableExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework\Exceptions;
|
||||
|
||||
use Exception;
|
||||
|
||||
class ApplicationNotInstalledException extends Exception
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework\Exceptions;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
class ContainerDependencyResolutionException extends RuntimeException
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework\Exceptions;
|
||||
|
||||
interface NonLoggableExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework\Http;
|
||||
|
||||
class JsonResponse extends Response
|
||||
{
|
||||
private array $data;
|
||||
private int $code;
|
||||
|
||||
public function __construct(array $data, int $code = self::HTTP_OK)
|
||||
{
|
||||
$this->data = $data;
|
||||
$this->code = $code;
|
||||
}
|
||||
|
||||
public function getData(): array
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
public function getCode(): int
|
||||
{
|
||||
return $this->code;
|
||||
}
|
||||
|
||||
public function send(): void
|
||||
{
|
||||
$this->sendHeaders();
|
||||
$this->sendContent();
|
||||
}
|
||||
|
||||
private function sendContent(): void
|
||||
{
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
|
||||
http_response_code(204);
|
||||
exit;
|
||||
}
|
||||
|
||||
echo json_encode($this->getData(), JSON_THROW_ON_ERROR);
|
||||
}
|
||||
|
||||
private function sendHeaders(): void
|
||||
{
|
||||
http_response_code($this->getCode());
|
||||
header('Content-Type: application/json');
|
||||
}
|
||||
}
|
||||
72
module/oc_telegram_shop/upload/oc_telegram_shop/framework/Http/Request.php
Executable file
72
module/oc_telegram_shop/upload/oc_telegram_shop/framework/Http/Request.php
Executable file
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework\Http;
|
||||
|
||||
use Openguru\OpenCartFramework\Support\Arr;
|
||||
use Openguru\OpenCartFramework\Support\Utils;
|
||||
|
||||
class Request
|
||||
{
|
||||
private $query;
|
||||
private $request;
|
||||
private $cookies;
|
||||
private $files;
|
||||
private $server;
|
||||
private $content;
|
||||
|
||||
public function __construct(
|
||||
array $query,
|
||||
array $request,
|
||||
array $cookies,
|
||||
array $files,
|
||||
array $server,
|
||||
string $content = null
|
||||
) {
|
||||
$this->query = $query;
|
||||
$this->request = $request;
|
||||
$this->cookies = $cookies;
|
||||
$this->files = $files;
|
||||
$this->server = $server;
|
||||
$this->content = $content;
|
||||
}
|
||||
|
||||
public static function createFromGlobals(): Request
|
||||
{
|
||||
return new static($_GET, $_POST, $_COOKIE, $_FILES, $_SERVER);
|
||||
}
|
||||
|
||||
public function getContent(): string
|
||||
{
|
||||
if ($this->content === null || $this->content === '') {
|
||||
$this->content = (string)file_get_contents('php://input');
|
||||
}
|
||||
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
public function json(string $key = null, $default = null)
|
||||
{
|
||||
$content = $this->getContent();
|
||||
|
||||
if (!$content) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
$decoded = Utils::safeJsonDecode($content);
|
||||
|
||||
if ($key === null) {
|
||||
return $decoded;
|
||||
}
|
||||
|
||||
return Arr::get($decoded, $key, $default);
|
||||
}
|
||||
|
||||
public function get(string $key = null, $default = null)
|
||||
{
|
||||
if ($key === null) {
|
||||
return $this->query;
|
||||
}
|
||||
|
||||
return $this->query[$key] ?? $default;
|
||||
}
|
||||
}
|
||||
70
module/oc_telegram_shop/upload/oc_telegram_shop/framework/Http/Response.php
Executable file
70
module/oc_telegram_shop/upload/oc_telegram_shop/framework/Http/Response.php
Executable file
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework\Http;
|
||||
|
||||
class Response
|
||||
{
|
||||
public const HTTP_CONTINUE = 100;
|
||||
public const HTTP_SWITCHING_PROTOCOLS = 101;
|
||||
public const HTTP_PROCESSING = 102; // RFC2518
|
||||
public const HTTP_EARLY_HINTS = 103; // RFC8297
|
||||
public const HTTP_OK = 200;
|
||||
public const HTTP_CREATED = 201;
|
||||
public const HTTP_ACCEPTED = 202;
|
||||
public const HTTP_NON_AUTHORITATIVE_INFORMATION = 203;
|
||||
public const HTTP_NO_CONTENT = 204;
|
||||
public const HTTP_RESET_CONTENT = 205;
|
||||
public const HTTP_PARTIAL_CONTENT = 206;
|
||||
public const HTTP_MULTI_STATUS = 207; // RFC4918
|
||||
public const HTTP_ALREADY_REPORTED = 208; // RFC5842
|
||||
public const HTTP_IM_USED = 226; // RFC3229
|
||||
public const HTTP_MULTIPLE_CHOICES = 300;
|
||||
public const HTTP_MOVED_PERMANENTLY = 301;
|
||||
public const HTTP_FOUND = 302;
|
||||
public const HTTP_SEE_OTHER = 303;
|
||||
public const HTTP_NOT_MODIFIED = 304;
|
||||
public const HTTP_USE_PROXY = 305;
|
||||
public const HTTP_RESERVED = 306;
|
||||
public const HTTP_TEMPORARY_REDIRECT = 307;
|
||||
public const HTTP_PERMANENTLY_REDIRECT = 308; // RFC7238
|
||||
public const HTTP_BAD_REQUEST = 400;
|
||||
public const HTTP_UNAUTHORIZED = 401;
|
||||
public const HTTP_PAYMENT_REQUIRED = 402;
|
||||
public const HTTP_FORBIDDEN = 403;
|
||||
public const HTTP_NOT_FOUND = 404;
|
||||
public const HTTP_METHOD_NOT_ALLOWED = 405;
|
||||
public const HTTP_NOT_ACCEPTABLE = 406;
|
||||
public const HTTP_PROXY_AUTHENTICATION_REQUIRED = 407;
|
||||
public const HTTP_REQUEST_TIMEOUT = 408;
|
||||
public const HTTP_CONFLICT = 409;
|
||||
public const HTTP_GONE = 410;
|
||||
public const HTTP_LENGTH_REQUIRED = 411;
|
||||
public const HTTP_PRECONDITION_FAILED = 412;
|
||||
public const HTTP_REQUEST_ENTITY_TOO_LARGE = 413;
|
||||
public const HTTP_REQUEST_URI_TOO_LONG = 414;
|
||||
public const HTTP_UNSUPPORTED_MEDIA_TYPE = 415;
|
||||
public const HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
|
||||
public const HTTP_EXPECTATION_FAILED = 417;
|
||||
public const HTTP_I_AM_A_TEAPOT = 418; // RFC2324
|
||||
public const HTTP_MISDIRECTED_REQUEST = 421; // RFC7540
|
||||
public const HTTP_UNPROCESSABLE_ENTITY = 422; // RFC4918
|
||||
public const HTTP_LOCKED = 423; // RFC4918
|
||||
public const HTTP_FAILED_DEPENDENCY = 424; // RFC4918
|
||||
public const HTTP_TOO_EARLY = 425; // RFC-ietf-httpbis-replay-04
|
||||
public const HTTP_UPGRADE_REQUIRED = 426; // RFC2817
|
||||
public const HTTP_PRECONDITION_REQUIRED = 428; // RFC6585
|
||||
public const HTTP_TOO_MANY_REQUESTS = 429; // RFC6585
|
||||
public const HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE = 431; // RFC6585
|
||||
public const HTTP_UNAVAILABLE_FOR_LEGAL_REASONS = 451; // RFC7725
|
||||
public const HTTP_INTERNAL_SERVER_ERROR = 500;
|
||||
public const HTTP_NOT_IMPLEMENTED = 501;
|
||||
public const HTTP_BAD_GATEWAY = 502;
|
||||
public const HTTP_SERVICE_UNAVAILABLE = 503;
|
||||
public const HTTP_GATEWAY_TIMEOUT = 504;
|
||||
public const HTTP_VERSION_NOT_SUPPORTED = 505;
|
||||
public const HTTP_VARIANT_ALSO_NEGOTIATES_EXPERIMENTAL = 506; // RFC2295
|
||||
public const HTTP_INSUFFICIENT_STORAGE = 507; // RFC4918
|
||||
public const HTTP_LOOP_DETECTED = 508; // RFC5842
|
||||
public const HTTP_NOT_EXTENDED = 510; // RFC2774
|
||||
public const HTTP_NETWORK_AUTHENTICATION_REQUIRED = 511; // RFC6585
|
||||
}
|
||||
88
module/oc_telegram_shop/upload/oc_telegram_shop/framework/Logger/Logger.php
Executable file
88
module/oc_telegram_shop/upload/oc_telegram_shop/framework/Logger/Logger.php
Executable file
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework\Logger;
|
||||
|
||||
use Throwable;
|
||||
|
||||
class Logger
|
||||
{
|
||||
private $logFile;
|
||||
private $logLevel;
|
||||
private $maxFileSize; // Максимальный размер файла в байтах
|
||||
|
||||
public const LEVEL_INFO = 1;
|
||||
public const LEVEL_WARNING = 2;
|
||||
public const LEVEL_ERROR = 3;
|
||||
|
||||
public function __construct($logFile, $logLevel = self::LEVEL_INFO, $maxFileSize = 1048576)
|
||||
{
|
||||
$this->logFile = $logFile;
|
||||
$this->logLevel = $logLevel;
|
||||
$this->maxFileSize = $maxFileSize;
|
||||
}
|
||||
|
||||
public function log($message, $level = self::LEVEL_INFO)
|
||||
{
|
||||
if ($level < $this->logLevel) {
|
||||
return; // Не логируем, если уровень ниже установленного
|
||||
}
|
||||
|
||||
$this->rotateLogs();
|
||||
|
||||
$timestamp = date('Y-m-d H:i:s');
|
||||
$levelStr = $this->getLevelString($level);
|
||||
$logMessage = "[$timestamp] [$levelStr] $message\n";
|
||||
|
||||
file_put_contents($this->logFile, $logMessage, FILE_APPEND);
|
||||
}
|
||||
|
||||
private function getLevelString($level): string
|
||||
{
|
||||
switch ($level) {
|
||||
case self::LEVEL_INFO:
|
||||
return 'INFO';
|
||||
case self::LEVEL_WARNING:
|
||||
return 'WARNING';
|
||||
case self::LEVEL_ERROR:
|
||||
return 'ERROR';
|
||||
default:
|
||||
return 'UNKNOWN';
|
||||
}
|
||||
}
|
||||
|
||||
public function info(string $message): void
|
||||
{
|
||||
$this->log($message, self::LEVEL_INFO);
|
||||
}
|
||||
|
||||
public function warning(string $message): void
|
||||
{
|
||||
$this->log($message, self::LEVEL_WARNING);
|
||||
}
|
||||
|
||||
public function error(string $message): void
|
||||
{
|
||||
$this->log($message, self::LEVEL_ERROR);
|
||||
}
|
||||
|
||||
private function rotateLogs(): void
|
||||
{
|
||||
if (is_file($this->logFile) && filesize($this->logFile) >= $this->maxFileSize) {
|
||||
$newLogFile = $this->logFile . '.' . date('YmdHis');
|
||||
rename($this->logFile, $newLogFile);
|
||||
}
|
||||
}
|
||||
|
||||
public function logException(Throwable $exception): void
|
||||
{
|
||||
$this->error(
|
||||
sprintf(
|
||||
"Fatal error %s in %s on line %d\n%s",
|
||||
$exception->getMessage(),
|
||||
$exception->getFile(),
|
||||
$exception->getLine(),
|
||||
$exception->getTraceAsString()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,429 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework\QueryBuilder;
|
||||
|
||||
use Closure;
|
||||
use Openguru\OpenCartFramework\QueryBuilder\Connections\ConnectionInterface;
|
||||
use Openguru\OpenCartFramework\QueryBuilder\Grammars\Grammar;
|
||||
use Openguru\OpenCartFramework\Support\Utils;
|
||||
use InvalidArgumentException;
|
||||
|
||||
class Builder
|
||||
{
|
||||
private $connection;
|
||||
private $grammar;
|
||||
|
||||
public $columns = '*';
|
||||
public $from;
|
||||
public $joins = [];
|
||||
public $wheres = [];
|
||||
public $orders = [];
|
||||
public $limit;
|
||||
public $offset;
|
||||
public $distinct = false;
|
||||
|
||||
public $bindings = [
|
||||
'select' => [],
|
||||
'from' => [],
|
||||
'join' => [],
|
||||
'where' => [],
|
||||
'order' => [],
|
||||
];
|
||||
|
||||
public function __construct(ConnectionInterface $connection, Grammar $grammar)
|
||||
{
|
||||
$this->connection = $connection;
|
||||
$this->grammar = $grammar;
|
||||
}
|
||||
|
||||
public function newQuery(): Builder
|
||||
{
|
||||
return new self($this->getConnection(), $this->getGrammar());
|
||||
}
|
||||
|
||||
public function select(array $columns): Builder
|
||||
{
|
||||
$this->columns = [];
|
||||
$this->bindings['select'] = [];
|
||||
|
||||
if (!$columns) {
|
||||
throw new InvalidArgumentException('Select columns not provided');
|
||||
}
|
||||
|
||||
foreach ($columns as $key => $value) {
|
||||
if ($value instanceof RawExpression) {
|
||||
$this->columns[] = $value;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_string($key)) {
|
||||
$this->columns[] = [
|
||||
'column' => $key,
|
||||
'as' => $value,
|
||||
];
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->columns[] = [
|
||||
'column' => $value,
|
||||
'as' => null,
|
||||
];
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function from(string $table, ?string $as = null): Builder
|
||||
{
|
||||
$this->from = compact('table', 'as');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function whereNull($column, $boolean = 'and'): Builder
|
||||
{
|
||||
$this->wheres[] = [
|
||||
'type' => 'Null',
|
||||
'column' => $column,
|
||||
'boolean' => $boolean,
|
||||
];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function whereNotNull($column, $boolean = 'and'): Builder
|
||||
{
|
||||
$this->wheres[] = [
|
||||
'type' => 'NotNull',
|
||||
'column' => $column,
|
||||
'boolean' => $boolean,
|
||||
];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function whereNested(Closure $callback, $boolean = 'and'): Builder
|
||||
{
|
||||
$callback($nestedQuery = $this->newQuery());
|
||||
|
||||
$this->wheres[] = [
|
||||
'type' => 'Nested',
|
||||
'query' => $nestedQuery,
|
||||
'boolean' => $boolean,
|
||||
];
|
||||
|
||||
$this->bindings['where'] = array_merge(
|
||||
$this->bindings['where'],
|
||||
$nestedQuery->getBindings('where')
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function whereRaw(string $expression, $boolean = 'and'): Builder
|
||||
{
|
||||
$this->wheres[] = [
|
||||
'type' => 'Raw',
|
||||
'expression' => $expression,
|
||||
'boolean' => $boolean,
|
||||
];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function where($column, $operator, $value, $boolean = 'and'): Builder
|
||||
{
|
||||
$this->wheres[] = [
|
||||
'type' => 'Basic',
|
||||
'column' => $column,
|
||||
'operator' => $operator,
|
||||
'value' => $value,
|
||||
'boolean' => $boolean,
|
||||
];
|
||||
|
||||
$this->addBinding($value);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function whereIn($column, array $values, $not = false, $boolean = 'and'): Builder
|
||||
{
|
||||
$this->wheres[] = [
|
||||
'type' => 'In',
|
||||
'column' => $column,
|
||||
'operator' => $not ? 'NOT IN' : 'IN',
|
||||
'value' => $values,
|
||||
'boolean' => $boolean,
|
||||
];
|
||||
|
||||
$this->addBinding($values);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function whereNotIn($column, array $values, $boolean = 'and'): Builder
|
||||
{
|
||||
$this->wheres[] = [
|
||||
'type' => 'In',
|
||||
'column' => $column,
|
||||
'operator' => 'NOT IN',
|
||||
'value' => $values,
|
||||
'boolean' => $boolean,
|
||||
];
|
||||
|
||||
$this->addBinding($values);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function whereBetween(string $column, array $values, $boolean = 'and'): Builder
|
||||
{
|
||||
if (count($values) !== 2) {
|
||||
throw new InvalidArgumentException('Invalid number of values provided.');
|
||||
}
|
||||
|
||||
$this->wheres[] = [
|
||||
'type' => 'Between',
|
||||
'column' => $column,
|
||||
'values' => $values,
|
||||
'boolean' => $boolean,
|
||||
];
|
||||
|
||||
$this->addBinding($values[0]);
|
||||
$this->addBinding($values[1]);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function orWhere($column, $operator, $value): Builder
|
||||
{
|
||||
return $this->where($column, $operator, $value, 'or');
|
||||
}
|
||||
|
||||
public function limit(int $limit): Builder
|
||||
{
|
||||
$this->limit = $limit;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function offset(int $offset): Builder
|
||||
{
|
||||
$this->offset = $offset;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function forPage(int $page = 0, int $perPage = 10): Builder
|
||||
{
|
||||
$offset = ($page - 1) * $perPage;
|
||||
|
||||
return $this->offset($offset)->limit($perPage);
|
||||
}
|
||||
|
||||
public function orderBy(string $column, string $direction = 'ASC'): Builder
|
||||
{
|
||||
$direction = strtoupper($direction);
|
||||
|
||||
if (!in_array($direction, ['ASC', 'DESC'], true)) {
|
||||
throw new InvalidArgumentException('Order direction must be "ASC" or "DESC".');
|
||||
}
|
||||
|
||||
$this->orders[] = [
|
||||
'column' => $column,
|
||||
'direction' => $direction,
|
||||
];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function toSql(): string
|
||||
{
|
||||
return $this->grammar->compileComponents($this);
|
||||
}
|
||||
|
||||
public function toRawSql(): string
|
||||
{
|
||||
return $this->substituteBindingsIntoRawSql(
|
||||
$this->toSql(),
|
||||
$this->getBindings()
|
||||
);
|
||||
}
|
||||
|
||||
public function substituteBindingsIntoRawSql(string $sql, array $bindings): string
|
||||
{
|
||||
$bindings = array_map(function ($value) {
|
||||
return $this->connection->escape($value);
|
||||
}, $bindings);
|
||||
|
||||
$query = '';
|
||||
|
||||
$isStringLiteral = false;
|
||||
|
||||
$sqlLen = strlen($sql);
|
||||
|
||||
for ($i = 0; $i < $sqlLen; $i++) {
|
||||
$char = $sql[$i];
|
||||
$nextChar = $sql[$i + 1] ?? null;
|
||||
|
||||
// Single quotes can be escaped as '' according to the SQL standard while
|
||||
// MySQL uses \'. Postgres has operators like ?| that must get encoded
|
||||
// in PHP like ??|. We should skip over the escaped characters here.
|
||||
if (in_array($char . $nextChar, ["\'", "''", '??'])) {
|
||||
$query .= $char . $nextChar;
|
||||
++$i;
|
||||
} elseif ($char === "'") { // Starting / leaving string literal...
|
||||
$query .= $char;
|
||||
$isStringLiteral = !$isStringLiteral;
|
||||
} elseif ($char === '?' && !$isStringLiteral) { // Substitutable binding...
|
||||
$query .= array_shift($bindings) ?? '?';
|
||||
} else { // Normal character...
|
||||
$query .= $char;
|
||||
}
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
public function get(): array
|
||||
{
|
||||
return $this->runSelect();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|null
|
||||
*/
|
||||
public function firstOrNull(): ?array
|
||||
{
|
||||
$rows = $this->limit(1)->get();
|
||||
|
||||
return $rows[0] ?? null;
|
||||
}
|
||||
|
||||
public function value(string $field)
|
||||
{
|
||||
$rows = $this->limit(1)->get();
|
||||
|
||||
return $rows[0][$field] ?? null;
|
||||
}
|
||||
|
||||
public function pluck(string $column, string $index = null): array
|
||||
{
|
||||
$items = $this->runSelect();
|
||||
|
||||
return array_column($items, $column, $index);
|
||||
}
|
||||
|
||||
public function storeResultsToTable(string $destinationTable): bool
|
||||
{
|
||||
$sql = "INSERT INTO `$destinationTable` {$this->toSql()}";
|
||||
|
||||
$this->connection->truncateTable($destinationTable);
|
||||
|
||||
return $this->connection->statement($sql, $this->getBindings());
|
||||
}
|
||||
|
||||
public function runSelect(): array
|
||||
{
|
||||
return $this->connection->select(
|
||||
$this->toSql(),
|
||||
$this->getBindings()
|
||||
);
|
||||
}
|
||||
|
||||
public function getBindings(string $type = null): array
|
||||
{
|
||||
if ($type === null) {
|
||||
return Utils::arrayFlatten($this->bindings);
|
||||
}
|
||||
|
||||
return $this->bindings[$type];
|
||||
}
|
||||
|
||||
public function addBinding($value, $type = 'where'): Builder
|
||||
{
|
||||
if (!array_key_exists($type, $this->bindings)) {
|
||||
throw new InvalidArgumentException("Invalid binding type: {$type}.");
|
||||
}
|
||||
|
||||
$this->bindings[$type][] = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function dd(): void
|
||||
{
|
||||
Utils::dd($this->toSql(), $this->getBindings());
|
||||
}
|
||||
|
||||
public function join(string $table, Closure $joinClosure, $type = 'inner'): Builder
|
||||
{
|
||||
$joinClause = new JoinClause($this, $type, $table);
|
||||
|
||||
$joinClosure($joinClause);
|
||||
|
||||
$this->joins[] = $joinClause;
|
||||
$this->bindings['join'][] = $joinClause->getBindings();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function leftJoin(string $table, Closure $joinClosure): Builder
|
||||
{
|
||||
return $this->join($table, $joinClosure, 'left');
|
||||
}
|
||||
|
||||
public function getConnection(): ConnectionInterface
|
||||
{
|
||||
return $this->connection;
|
||||
}
|
||||
|
||||
public function getGrammar(): Grammar
|
||||
{
|
||||
return $this->grammar;
|
||||
}
|
||||
|
||||
public function count(): int
|
||||
{
|
||||
$sql = 'SELECT COUNT(*) AS total_count FROM (' . $this->toSql() . ') AS x';
|
||||
|
||||
$result = $this->connection->select($sql, $this->getBindings());
|
||||
|
||||
return $result[0]['total_count'] ?? 0;
|
||||
}
|
||||
|
||||
public function distinct(): Builder
|
||||
{
|
||||
$this->distinct = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a callback to the query if the given condition is true.
|
||||
*
|
||||
* @param bool $condition
|
||||
* @param Closure $callback
|
||||
* @param Closure|null $default
|
||||
* @return $this
|
||||
*/
|
||||
public function when(bool $condition, Closure $callback, Closure $default = null): Builder
|
||||
{
|
||||
if ($condition) {
|
||||
$callback($this);
|
||||
} elseif ($default) {
|
||||
$default($this);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function hasJoinAlias(string $joinAlias): bool
|
||||
{
|
||||
$join = array_filter($this->joins, static function (JoinClause $join) use ($joinAlias) {
|
||||
return strpos($join->table, $joinAlias) !== false;
|
||||
});
|
||||
|
||||
return count($join) > 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework\QueryBuilder\Connections;
|
||||
|
||||
interface ConnectionInterface
|
||||
{
|
||||
public function select(string $sql, array $bindings = []): array;
|
||||
|
||||
public function createTableFromSql(string $table, string $sql, array $bindings = []): bool;
|
||||
|
||||
public function insertIntoTableFromSql(string $table, string $sql, array $bindings = []): bool;
|
||||
|
||||
public function dropTable(string $table): bool;
|
||||
|
||||
public function dropTableIfExists(string $table): bool;
|
||||
|
||||
public function tableExists(string $table): bool;
|
||||
|
||||
public function escape($value): string;
|
||||
|
||||
public function statement(string $sql, array $bindings = []): bool;
|
||||
|
||||
public function beginTransaction(): bool;
|
||||
|
||||
public function commitTransaction(): bool;
|
||||
|
||||
public function rollBackTransaction(): bool;
|
||||
|
||||
public function truncateTable(string $table): bool;
|
||||
|
||||
public function lastInsertId($name = null): int;
|
||||
|
||||
public function getVersion(): string;
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework\QueryBuilder\Connections;
|
||||
|
||||
use Openguru\OpenCartFramework\Support\Utils;
|
||||
use PDO;
|
||||
use RuntimeException;
|
||||
|
||||
class MySqlConnection implements ConnectionInterface
|
||||
{
|
||||
private $pdo;
|
||||
|
||||
public function __construct(PDO $pdo)
|
||||
{
|
||||
$this->pdo = $pdo;
|
||||
|
||||
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
|
||||
$this->pdo->exec("SET NAMES 'utf8'");
|
||||
$this->pdo->exec("SET CHARACTER SET utf8");
|
||||
$this->pdo->exec("SET CHARACTER_SET_CONNECTION=utf8");
|
||||
$this->pdo->exec("SET SQL_MODE = ''");
|
||||
}
|
||||
|
||||
public function select(string $sql, array $bindings = []): array
|
||||
{
|
||||
$statement = $this->pdo->prepare($sql);
|
||||
$statement->execute($bindings);
|
||||
|
||||
return $statement->fetchAll(PDO::FETCH_ASSOC);
|
||||
}
|
||||
|
||||
public function escape($value): string
|
||||
{
|
||||
switch (true) {
|
||||
case $value === null:
|
||||
return 'null';
|
||||
|
||||
case is_int($value) || is_float($value):
|
||||
return (string)$value;
|
||||
|
||||
case is_bool($value):
|
||||
return $value ? '1' : '0';
|
||||
|
||||
case is_array($value):
|
||||
throw new RuntimeException('The database connection does not support escaping arrays.');
|
||||
|
||||
default:
|
||||
if (Utils::strContains($value, "\00")) {
|
||||
throw new RuntimeException(
|
||||
'Strings with null bytes cannot be escaped. Use the binary escape option.'
|
||||
);
|
||||
}
|
||||
|
||||
if (preg_match('//u', $value) === false) {
|
||||
throw new RuntimeException('Strings with invalid UTF-8 byte sequences cannot be escaped.');
|
||||
}
|
||||
|
||||
return $this->pdo->quote($value);
|
||||
}
|
||||
}
|
||||
|
||||
public function createTableFromSql(string $table, string $sql, array $bindings = []): bool
|
||||
{
|
||||
$createSql = "CREATE TABLE IF NOT EXISTS `$table` AS ($sql)";
|
||||
|
||||
return $this->pdo->prepare($createSql)->execute($bindings);
|
||||
}
|
||||
|
||||
public function dropTable(string $table): bool
|
||||
{
|
||||
return $this->pdo->prepare("DROP TABLE `$table`")->execute();
|
||||
}
|
||||
|
||||
public function dropTableIfExists(string $table): bool
|
||||
{
|
||||
return $this->pdo->prepare("DROP TABLE IF EXISTS `$table`")->execute();
|
||||
}
|
||||
|
||||
public function tableExists(string $table): bool
|
||||
{
|
||||
$statement = $this->pdo->prepare("SHOW TABLES LIKE ?;");
|
||||
$statement->execute([$table]);
|
||||
|
||||
return $statement->rowCount() > 0;
|
||||
}
|
||||
|
||||
public function statement(string $sql, array $bindings = []): bool
|
||||
{
|
||||
return $this->pdo->prepare($sql)->execute($bindings);
|
||||
}
|
||||
|
||||
public function beginTransaction(): bool
|
||||
{
|
||||
return $this->pdo->beginTransaction();
|
||||
}
|
||||
|
||||
public function commitTransaction(): bool
|
||||
{
|
||||
return $this->pdo->commit();
|
||||
}
|
||||
|
||||
public function rollBackTransaction(): bool
|
||||
{
|
||||
return $this->pdo->rollBack();
|
||||
}
|
||||
|
||||
public function insertIntoTableFromSql(string $table, string $sql, array $bindings = []): bool
|
||||
{
|
||||
$createSql = "INSERT INTO `{$table}` {$sql}";
|
||||
|
||||
return $this->pdo->prepare($createSql)->execute($bindings);
|
||||
}
|
||||
|
||||
public function truncateTable(string $table): bool
|
||||
{
|
||||
return $this->pdo->prepare("TRUNCATE TABLE {$table}")->execute();
|
||||
}
|
||||
|
||||
public function lastInsertId($name = null): int
|
||||
{
|
||||
return $this->pdo->lastInsertId($name);
|
||||
}
|
||||
|
||||
public function getVersion(): string
|
||||
{
|
||||
return $this->pdo
|
||||
->query('SELECT VERSION()')
|
||||
->fetch(PDO::FETCH_COLUMN);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework\QueryBuilder\Grammars;
|
||||
|
||||
use BadMethodCallException;
|
||||
use Openguru\OpenCartFramework\QueryBuilder\Builder;
|
||||
use Openguru\OpenCartFramework\QueryBuilder\JoinClause;
|
||||
use Openguru\OpenCartFramework\QueryBuilder\RawExpression;
|
||||
|
||||
abstract class Grammar
|
||||
{
|
||||
protected $compiled = [
|
||||
'columns' => [],
|
||||
'from' => [],
|
||||
'joins' => [],
|
||||
'wheres' => [],
|
||||
'orders' => [],
|
||||
'limit' => [],
|
||||
'offset' => [],
|
||||
];
|
||||
|
||||
private function resetCompiled(): void
|
||||
{
|
||||
$this->compiled = [
|
||||
'columns' => [],
|
||||
'from' => [],
|
||||
'joins' => [],
|
||||
'wheres' => [],
|
||||
'orders' => [],
|
||||
'limit' => [],
|
||||
'offset' => [],
|
||||
];
|
||||
}
|
||||
|
||||
public function compileComponents(Builder $builder): string
|
||||
{
|
||||
$this->resetCompiled();
|
||||
|
||||
foreach (array_keys($this->compiled) as $component) {
|
||||
$method = 'compile' . ucfirst($component);
|
||||
|
||||
if (!method_exists($this, $method)) {
|
||||
throw new BadMethodCallException("Method '{$method}' does not exist.");
|
||||
}
|
||||
|
||||
if (! empty($builder->{$component})) {
|
||||
$this->compiled[$component] = $this->{$method}(
|
||||
$builder,
|
||||
$builder->{$component},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->concatCompiled($this->compiled);
|
||||
}
|
||||
|
||||
public function concatCompiled(array $compiled): string
|
||||
{
|
||||
$array = [];
|
||||
|
||||
foreach (array_keys($this->compiled) as $component) {
|
||||
$array[] = $compiled[$component] ?? null;
|
||||
}
|
||||
|
||||
return implode(' ', array_filter($array));
|
||||
}
|
||||
|
||||
public function compileColumns(Builder $builder, $columns): string
|
||||
{
|
||||
if ($columns === '*' || count($columns) === 0) {
|
||||
return 'SELECT *';
|
||||
}
|
||||
|
||||
$columns = array_map(static function ($item) {
|
||||
if ($item instanceof RawExpression) {
|
||||
return $item->getValue();
|
||||
}
|
||||
|
||||
return $item['column'] . ($item['as'] !== null ? ' AS ' . $item['as'] : '');
|
||||
}, $columns);
|
||||
|
||||
$distinct = $builder->distinct ? 'DISTINCT ' : '';
|
||||
|
||||
return "SELECT {$distinct}" . implode(', ', $columns);
|
||||
}
|
||||
|
||||
public function compileWheres(Builder $builder, $wheres, string $prefix = 'WHERE '): string
|
||||
{
|
||||
if (!$wheres) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$compiledConditions = [];
|
||||
|
||||
$counter = 0;
|
||||
foreach ($wheres as $condition) {
|
||||
$compiledConditions[] = ($counter > 0 ? mb_strtoupper($condition['boolean']) . ' ' : '')
|
||||
. $this->{'where' . $condition['type']}($condition);
|
||||
$counter++;
|
||||
}
|
||||
|
||||
return $prefix . implode(' ', $compiledConditions);
|
||||
}
|
||||
|
||||
public function whereBasic($condition): string
|
||||
{
|
||||
return $condition['column'] . ' ' . $condition['operator'] . ' ?';
|
||||
}
|
||||
|
||||
public function whereRaw($condition): string
|
||||
{
|
||||
return $condition['expression'];
|
||||
}
|
||||
|
||||
public function whereNull($condition): string
|
||||
{
|
||||
return $condition['column'] . ' IS NULL';
|
||||
}
|
||||
|
||||
public function whereNotNull($condition): string
|
||||
{
|
||||
return $condition['column'] . ' IS NOT NULL';
|
||||
}
|
||||
|
||||
public function whereNested($condition): string
|
||||
{
|
||||
return '(' . $this->compileWheres($condition['query'], $condition['query']->wheres, '') . ')';
|
||||
}
|
||||
|
||||
public function whereBetween($condition): string
|
||||
{
|
||||
return $condition['column'] . ' BETWEEN ? AND ?';
|
||||
}
|
||||
|
||||
public function compileOrders(Builder $builder, array $orders): string
|
||||
{
|
||||
return 'ORDER BY ' . implode(
|
||||
', ',
|
||||
array_map(
|
||||
static function ($order) {
|
||||
return $order['column'] . ' ' . $order['direction'];
|
||||
},
|
||||
$orders
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public function compileFrom(Builder $builder, array $from): string
|
||||
{
|
||||
return 'FROM ' . $from['table'] . ($from['as'] !== null ? ' AS ' . $from['as'] : '');
|
||||
}
|
||||
|
||||
public function compileLimit(Builder $builder, $limit): string
|
||||
{
|
||||
return "LIMIT $limit";
|
||||
}
|
||||
|
||||
public function compileOffset(Builder $builder, $offset): string
|
||||
{
|
||||
return "OFFSET $offset";
|
||||
}
|
||||
|
||||
public function compileJoins(Builder $builder, $joins): string
|
||||
{
|
||||
return implode(' ', array_map(function (JoinClause $join) use ($builder) {
|
||||
$conditions = '';
|
||||
if ($join->wheres) {
|
||||
$conditions = ' AND ' . $this->compileWheres($builder, $join->wheres, '');
|
||||
}
|
||||
|
||||
return mb_strtoupper(
|
||||
$join->type
|
||||
) . " JOIN $join->table ON $join->first $join->operator $join->second" . $conditions;
|
||||
}, $joins));
|
||||
}
|
||||
|
||||
public function whereIn($condition): string
|
||||
{
|
||||
if (! $condition['value']) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$inValues = str_repeat('?, ', count($condition['value']) - 1) . '?';
|
||||
$inOperator = $condition['operator'];
|
||||
|
||||
return $condition['column'] . " $inOperator (" . $inValues . ')';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework\QueryBuilder\Grammars;
|
||||
|
||||
class MySqlGrammar extends Grammar
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework\QueryBuilder;
|
||||
|
||||
class JoinClause extends Builder
|
||||
{
|
||||
public $table;
|
||||
public $type;
|
||||
public $first;
|
||||
public $second;
|
||||
public $operator;
|
||||
|
||||
public $bindings = [
|
||||
'where' => [],
|
||||
];
|
||||
|
||||
public function __construct(Builder $parent, string $type, string $table)
|
||||
{
|
||||
$this->type = $type;
|
||||
$this->table = $table;
|
||||
|
||||
parent::__construct($parent->getConnection(), $parent->getGrammar());
|
||||
}
|
||||
|
||||
public function on($first, $operator, $second): JoinClause
|
||||
{
|
||||
$this->first = $first;
|
||||
$this->operator = $operator;
|
||||
$this->second = $second;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework\QueryBuilder;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
class QueryBuilderException extends RuntimeException
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework\QueryBuilder;
|
||||
|
||||
use Openguru\OpenCartFramework\Container\Container;
|
||||
use Openguru\OpenCartFramework\Container\ServiceProvider;
|
||||
use Openguru\OpenCartFramework\QueryBuilder\Connections\ConnectionInterface;
|
||||
use Openguru\OpenCartFramework\QueryBuilder\Connections\MySqlConnection;
|
||||
use Openguru\OpenCartFramework\QueryBuilder\Grammars\MySqlGrammar;
|
||||
use PDO;
|
||||
|
||||
class QueryBuilderServiceProvider extends ServiceProvider
|
||||
{
|
||||
public function register(): void
|
||||
{
|
||||
$this->container->bind(ConnectionInterface::class, function (Container $container) {
|
||||
$host = $container->getConfigValue('db.host');
|
||||
$username = $container->getConfigValue('db.username');
|
||||
$password = $container->getConfigValue('db.password');
|
||||
$port = $container->getConfigValue('db.port');
|
||||
$dbName = $container->getConfigValue('db.database');
|
||||
|
||||
$dsn = "mysql:host=$host;port=$port;dbname=$dbName";
|
||||
|
||||
return new MySqlConnection(
|
||||
new PDO($dsn, $username, $password)
|
||||
);
|
||||
});
|
||||
|
||||
$this->container->bind(Builder::class, function (Container $container) {
|
||||
return new Builder(
|
||||
$container->get(ConnectionInterface::class),
|
||||
$container->get(MySqlGrammar::class)
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework\QueryBuilder;
|
||||
|
||||
class QueryResult
|
||||
{
|
||||
private $row;
|
||||
private $rows;
|
||||
private $numRows;
|
||||
|
||||
public function __construct(
|
||||
$row,
|
||||
$rows,
|
||||
$numRows
|
||||
) {
|
||||
$this->row = $row;
|
||||
$this->rows = $rows;
|
||||
$this->numRows = $numRows;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getRow()
|
||||
{
|
||||
return $this->row;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getRows()
|
||||
{
|
||||
return $this->rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getNumRows(): int
|
||||
{
|
||||
return $this->numRows;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework\QueryBuilder;
|
||||
|
||||
class RawExpression
|
||||
{
|
||||
private $value;
|
||||
|
||||
public function __construct(string $value)
|
||||
{
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
public function getValue(): string
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework\Router;
|
||||
|
||||
use Openguru\OpenCartFramework\Container\Container;
|
||||
use Openguru\OpenCartFramework\Container\ServiceProvider;
|
||||
|
||||
class RouteServiceProvider extends ServiceProvider
|
||||
{
|
||||
public function register(): void
|
||||
{
|
||||
$this->container->singleton(Router::class, function (Container $container) {
|
||||
return new Router();
|
||||
});
|
||||
}
|
||||
}
|
||||
38
module/oc_telegram_shop/upload/oc_telegram_shop/framework/Router/Router.php
Executable file
38
module/oc_telegram_shop/upload/oc_telegram_shop/framework/Router/Router.php
Executable file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework\Router;
|
||||
|
||||
use Openguru\OpenCartFramework\Exceptions\ActionNotFoundException;
|
||||
|
||||
class Router
|
||||
{
|
||||
private array $routes;
|
||||
|
||||
public function __construct(array $routes = [])
|
||||
{
|
||||
$this->routes = $routes;
|
||||
}
|
||||
|
||||
public function loadRoutesFromFile(string $file): void
|
||||
{
|
||||
$this->routes = include $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $action
|
||||
* @return string[]
|
||||
* @throws ActionNotFoundException
|
||||
*/
|
||||
public function resolve($action): array
|
||||
{
|
||||
if (!$action) {
|
||||
throw new ActionNotFoundException('No action provided');
|
||||
}
|
||||
|
||||
if (isset($this->routes[$action])) {
|
||||
return $this->routes[$action];
|
||||
}
|
||||
|
||||
throw new ActionNotFoundException('Action "' . $action . '" not found.');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework\Settings;
|
||||
|
||||
use Exception;
|
||||
use Openguru\OpenCartFramework\QueryBuilder\Builder;
|
||||
use Openguru\OpenCartFramework\QueryBuilder\Connections\ConnectionInterface;
|
||||
use Openguru\OpenCartFramework\Support\Arr;
|
||||
use JsonException;
|
||||
use RuntimeException;
|
||||
|
||||
class DatabaseUserSettings implements UserSettingsInterface
|
||||
{
|
||||
private $builder;
|
||||
private $database;
|
||||
private $allSettings = [];
|
||||
|
||||
public function __construct(Builder $builder, ConnectionInterface $database)
|
||||
{
|
||||
$this->builder = $builder;
|
||||
$this->database = $database;
|
||||
}
|
||||
|
||||
public function getAll(): array
|
||||
{
|
||||
if ($this->allSettings) {
|
||||
return $this->allSettings;
|
||||
}
|
||||
|
||||
$row = $this->builder
|
||||
->select(['settings_json'])
|
||||
->from(config('tables.settings'))
|
||||
->where('id', '=', 1)
|
||||
->firstOrNull();
|
||||
|
||||
if (! $row || empty($row['settings_json'])) {
|
||||
throw new RuntimeException('Database settings not found. Please reinstall the module.');
|
||||
}
|
||||
|
||||
try {
|
||||
$decoded = json_decode($row['settings_json'], true, 512, JSON_THROW_ON_ERROR);
|
||||
} catch (JsonException $e) {
|
||||
throw new RuntimeException('Database settings invalid format: ' . $e->getMessage());
|
||||
}
|
||||
|
||||
$this->allSettings = $decoded;
|
||||
|
||||
return $decoded;
|
||||
}
|
||||
|
||||
public function update(array $userSettings): void
|
||||
{
|
||||
$settingsTable = config('tables.settings');
|
||||
try {
|
||||
$currentSettings = $this->getAll();
|
||||
$updatedSettings = array_replace_recursive($currentSettings, $userSettings);
|
||||
|
||||
$encoded = json_encode($updatedSettings, JSON_THROW_ON_ERROR);
|
||||
|
||||
$sql = <<<SQL
|
||||
INSERT INTO `{$settingsTable}`
|
||||
(id, settings_json)
|
||||
VALUES
|
||||
(1, '{$encoded}')
|
||||
ON DUPLICATE KEY UPDATE
|
||||
settings_json = VALUES(settings_json)
|
||||
SQL;
|
||||
|
||||
$this->database->statement($sql, [$encoded]);
|
||||
} catch (Exception $e) {
|
||||
throw new RuntimeException('Could not update settings: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function get(string $key, $default = null)
|
||||
{
|
||||
$all = $this->getAll();
|
||||
|
||||
return Arr::get($all, $key, $default);
|
||||
}
|
||||
|
||||
public function safeGet(string $key, $default = null)
|
||||
{
|
||||
try {
|
||||
return $this->get($key, $default);
|
||||
} catch (Exception $e) {
|
||||
return $default;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework\Settings;
|
||||
|
||||
interface UserSettingsInterface
|
||||
{
|
||||
public function get(string $key, $default = null);
|
||||
public function getAll(): array;
|
||||
public function update(array $userSettings): void;
|
||||
public function safeGet(string $key, $default = null);
|
||||
}
|
||||
131
module/oc_telegram_shop/upload/oc_telegram_shop/framework/Support/Arr.php
Executable file
131
module/oc_telegram_shop/upload/oc_telegram_shop/framework/Support/Arr.php
Executable file
@@ -0,0 +1,131 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework\Support;
|
||||
|
||||
use InvalidArgumentException;
|
||||
|
||||
class Arr
|
||||
{
|
||||
/**
|
||||
* Transform an array to use a specified field as keys.
|
||||
*
|
||||
* @param array $array Input array of items.
|
||||
* @param string $keyField Field name to be used as keys.
|
||||
* @return array Transformed array with specified field as keys.
|
||||
* @throws InvalidArgumentException If the key field is missing in any item.
|
||||
*/
|
||||
public static function keyByField(array $array, string $keyField): array
|
||||
{
|
||||
$result = [];
|
||||
foreach ($array as $item) {
|
||||
if (!array_key_exists($keyField, $item)) {
|
||||
throw new InvalidArgumentException("Key field '{$keyField}' is missing in one of the items.");
|
||||
}
|
||||
$result[$item[$keyField]] = $item;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Group array by a specific key and collect values into sub-arrays.
|
||||
*
|
||||
* @param array $data Array to group.
|
||||
* @param string $groupKey Key to group by.
|
||||
* @param string $valueKey Key to collect values from.
|
||||
* @return array Grouped array.
|
||||
*/
|
||||
public static function groupByKey(array $data, string $groupKey, string $valueKey): array
|
||||
{
|
||||
$result = [];
|
||||
|
||||
foreach ($data as $item) {
|
||||
$result[$item[$groupKey]][] = $item[$valueKey];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function get(array $items, string $key, $default = null)
|
||||
{
|
||||
if (!$items) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
if (array_key_exists($key, $items)) {
|
||||
return $items[$key];
|
||||
}
|
||||
|
||||
$segments = explode('.', $key);
|
||||
foreach ($segments as $segment) {
|
||||
if (!is_array($items) || !array_key_exists($segment, $items)) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
$items = &$items[$segment];
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
public static function set(array &$array, string $key, $value): void
|
||||
{
|
||||
$keys = explode('.', $key);
|
||||
foreach ($keys as $k) {
|
||||
if (!isset($array[$k]) || !is_array($array[$k])) {
|
||||
$array[$k] = [];
|
||||
}
|
||||
$array = &$array[$k];
|
||||
}
|
||||
$array = $value;
|
||||
}
|
||||
|
||||
public static function unset(array &$array, string $key): void
|
||||
{
|
||||
$keys = explode('.', $key);
|
||||
while (count($keys) > 1) {
|
||||
$k = array_shift($keys);
|
||||
if (!isset($array[$k]) || !is_array($array[$k])) {
|
||||
return;
|
||||
}
|
||||
$array = &$array[$k];
|
||||
}
|
||||
unset($array[array_shift($keys)]);
|
||||
}
|
||||
|
||||
public static function find(array $array, callable $callback)
|
||||
{
|
||||
foreach ($array as $key => $value) {
|
||||
if ($callback($value, $key) === true) {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static function pluck(array $value, string $field): array
|
||||
{
|
||||
return array_map(
|
||||
static function ($item) use ($field) {
|
||||
if (is_object($item)) {
|
||||
return $item->{$field};
|
||||
}
|
||||
|
||||
return $item[$field];
|
||||
},
|
||||
$value
|
||||
);
|
||||
}
|
||||
|
||||
public static function mergeArraysRecursively(array $base, array $override): array
|
||||
{
|
||||
foreach ($override as $key => $value) {
|
||||
if (isset($base[$key]) && is_array($base[$key]) && is_array($value)) {
|
||||
$base[$key] = static::mergeArraysRecursively($base[$key], $value);
|
||||
} else {
|
||||
$base[$key] = $value;
|
||||
}
|
||||
}
|
||||
return $base;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework\Support;
|
||||
|
||||
class ExecutionTimeProfiler
|
||||
{
|
||||
private $startTime;
|
||||
private $checkpoints = [];
|
||||
|
||||
public function start(): void
|
||||
{
|
||||
$this->startTime = microtime(true);
|
||||
$this->checkpoints = [['label' => 'start', 'time' => $this->startTime]];
|
||||
}
|
||||
|
||||
public function addCheckpoint(string $label): void
|
||||
{
|
||||
$currentTime = microtime(true);
|
||||
$this->checkpoints[] = [
|
||||
'label' => $label,
|
||||
'time' => $currentTime
|
||||
];
|
||||
}
|
||||
|
||||
public function stop(): array
|
||||
{
|
||||
$endTime = microtime(true);
|
||||
$this->checkpoints[] = ['label' => 'End', 'time' => $endTime];
|
||||
|
||||
$result = [
|
||||
'total_execution_time_ms' => round(($endTime - $this->startTime) * 1000, 2),
|
||||
'checkpoints' => []
|
||||
];
|
||||
|
||||
$total = count($this->checkpoints);
|
||||
|
||||
for ($i = 1; $i < $total; $i++) {
|
||||
$prev = $this->checkpoints[$i - 1];
|
||||
$current = $this->checkpoints[$i];
|
||||
|
||||
$result['checkpoints'][] = [
|
||||
'label' => $current['label'],
|
||||
'elapsed_since_previous_ms' => round(($current['time'] - $prev['time']) * 1000, 2)
|
||||
];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework\Support;
|
||||
|
||||
class PaginationHelper
|
||||
{
|
||||
public static function calculateLastPage(int $totalRecords, int $perPage): int
|
||||
{
|
||||
return (int)ceil($totalRecords / $perPage);
|
||||
}
|
||||
}
|
||||
69
module/oc_telegram_shop/upload/oc_telegram_shop/framework/Support/Utils.php
Executable file
69
module/oc_telegram_shop/upload/oc_telegram_shop/framework/Support/Utils.php
Executable file
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework\Support;
|
||||
|
||||
use InvalidArgumentException;
|
||||
|
||||
class Utils
|
||||
{
|
||||
/**
|
||||
* @return array|string[]
|
||||
*/
|
||||
public static function ucsplit(string $string): array
|
||||
{
|
||||
return preg_split('/(?=\p{Lu})/u', $string, -1, PREG_SPLIT_NO_EMPTY) ?? [];
|
||||
}
|
||||
|
||||
public static function safeJsonDecode(string $content)
|
||||
{
|
||||
$decoded = json_decode($content, true);
|
||||
|
||||
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||
throw new InvalidArgumentException('JSON error: ' . json_last_error_msg());
|
||||
}
|
||||
|
||||
return $decoded;
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-return list<mixed>
|
||||
*/
|
||||
public static function arrayFlatten(array $array, $depth = INF): array
|
||||
{
|
||||
$result = [];
|
||||
|
||||
foreach ($array as $item) {
|
||||
if (! is_array($item)) {
|
||||
$result[] = $item;
|
||||
} else {
|
||||
$values = $depth === 1
|
||||
? array_values($item)
|
||||
: static::arrayFlatten($item, $depth - 1);
|
||||
|
||||
foreach ($values as $value) {
|
||||
$result[] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return never
|
||||
*/
|
||||
public static function dd()
|
||||
{
|
||||
$args = func_get_args();
|
||||
echo '<pre>';
|
||||
/** @psalm-suppress ForbiddenCode */
|
||||
var_dump(...$args);
|
||||
echo '</pre>';
|
||||
die();
|
||||
}
|
||||
|
||||
public static function strContains(string $haystack, string $needle): bool
|
||||
{
|
||||
return $needle === '' || strpos($haystack, $needle) !== false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
use Openguru\OpenCartFramework\Application;
|
||||
use Openguru\OpenCartFramework\Config\Settings;
|
||||
use Openguru\OpenCartFramework\Support\Utils;
|
||||
|
||||
if (!function_exists('table')) {
|
||||
function db_table(string $name): string
|
||||
{
|
||||
$prefix = Application::getInstance()->getConfigValue('db.prefix');
|
||||
|
||||
return $prefix . $name;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('column')) {
|
||||
function db_column($column): string
|
||||
{
|
||||
if (strpos($column, '.') !== false) {
|
||||
[$table, $column] = explode('.', $column, 2);
|
||||
|
||||
if ($table === '' || $column === '') {
|
||||
throw new InvalidArgumentException('Invalid column reference: ' . $column);
|
||||
}
|
||||
|
||||
return db_table($table) . '.' . $column;
|
||||
}
|
||||
|
||||
return $column;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('resources_path')) {
|
||||
function resources_path(string $path = ''): string
|
||||
{
|
||||
return BP_BASE_PATH . '/resources/' . $path;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('base_path')) {
|
||||
function base_path(string $path = ''): string
|
||||
{
|
||||
return BP_BASE_PATH . '/' . $path;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('config')) {
|
||||
function config(string $key, $default = null)
|
||||
{
|
||||
return Application::getInstance()->get(Settings::class)->get($key, $default);
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('dd')) {
|
||||
function dd(): void
|
||||
{
|
||||
Utils::dd(func_get_args());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework\Translator;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
class Translator implements TranslatorInterface
|
||||
{
|
||||
private $language;
|
||||
private $translations;
|
||||
|
||||
public function __construct(string $language, array $translations = [])
|
||||
{
|
||||
$this->language = $language;
|
||||
$this->translations = $translations;
|
||||
}
|
||||
|
||||
public function loadTranslationsFromFolder(string $directory): void
|
||||
{
|
||||
if (!is_dir($directory)) {
|
||||
throw new RuntimeException('Translations folder not found.');
|
||||
}
|
||||
|
||||
$filename = $directory . "/{$this->language}.php";
|
||||
if (!is_file($filename)) {
|
||||
throw new RuntimeException("Translation file for language '{$this->language}' not found.");
|
||||
}
|
||||
|
||||
$translations = include $filename;
|
||||
$this->translations = array_merge($this->translations, $translations);
|
||||
}
|
||||
|
||||
public function translate(string $key, array $params = []): string
|
||||
{
|
||||
if (isset($this->translations[$key])) {
|
||||
return $this->substitute($this->translations[$key], $params);
|
||||
}
|
||||
|
||||
return $key;
|
||||
}
|
||||
|
||||
public function getTranslations(): array
|
||||
{
|
||||
return $this->translations;
|
||||
}
|
||||
|
||||
public function getLanguage(): string
|
||||
{
|
||||
return $this->language;
|
||||
}
|
||||
|
||||
private function substitute($text, array $parameters): string
|
||||
{
|
||||
if (!$parameters) {
|
||||
return $text;
|
||||
}
|
||||
|
||||
$search = array_map(static function ($param) {
|
||||
return '{' . $param . '}';
|
||||
}, array_keys($parameters));
|
||||
|
||||
return str_replace($search, array_values($parameters), $text);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework\Translator;
|
||||
|
||||
interface TranslatorInterface
|
||||
{
|
||||
public function loadTranslationsFromFolder(string $directory): void;
|
||||
|
||||
public function translate(string $key, array $params = []): string;
|
||||
|
||||
public function getTranslations(): array;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework\Translator;
|
||||
|
||||
use Openguru\OpenCartFramework\Container\Container;
|
||||
use Openguru\OpenCartFramework\Container\ServiceProvider;
|
||||
|
||||
class TranslatorServiceProvider extends ServiceProvider
|
||||
{
|
||||
public function register(): void
|
||||
{
|
||||
$this->container->singleton(TranslatorInterface::class, function (Container $container) {
|
||||
$language = $container->getConfigValue('lang');
|
||||
$translator = new Translator($language);
|
||||
$translator->loadTranslationsFromFolder(resources_path('/translations'));
|
||||
return $translator;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Openguru\OpenCartFramework\Validator;
|
||||
|
||||
class Validator
|
||||
{
|
||||
private $input;
|
||||
private $rules;
|
||||
|
||||
public function __construct(array $input, array $rules)
|
||||
{
|
||||
$this->input = $input;
|
||||
$this->rules = $rules;
|
||||
}
|
||||
|
||||
public function validate(): bool
|
||||
{
|
||||
foreach ($this->rules as $name => $rule) {
|
||||
$components = explode('|', $rule);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
26
module/oc_telegram_shop/upload/oc_telegram_shop/src/ApplicationFactory.php
Executable file
26
module/oc_telegram_shop/upload/oc_telegram_shop/src/ApplicationFactory.php
Executable file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
use App\ServiceProviders\AppServiceProvider;
|
||||
use Openguru\OpenCartFramework\Application;
|
||||
use Openguru\OpenCartFramework\Cache\CacheServiceProvider;
|
||||
use Openguru\OpenCartFramework\QueryBuilder\QueryBuilderServiceProvider;
|
||||
use Openguru\OpenCartFramework\Router\RouteServiceProvider;
|
||||
use Openguru\OpenCartFramework\Support\Arr;
|
||||
|
||||
class ApplicationFactory
|
||||
{
|
||||
public static function create(array $config): Application
|
||||
{
|
||||
$defaultConfig = require __DIR__ . '/config.php';
|
||||
|
||||
return (new Application(Arr::mergeArraysRecursively($defaultConfig, $config)))
|
||||
->withServiceProviders([
|
||||
QueryBuilderServiceProvider::class,
|
||||
CacheServiceProvider::class,
|
||||
RouteServiceProvider::class,
|
||||
AppServiceProvider::class
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace App\Handlers;
|
||||
|
||||
use Openguru\OpenCartFramework\Http\JsonResponse;
|
||||
use Openguru\OpenCartFramework\QueryBuilder\Builder;
|
||||
use Openguru\OpenCartFramework\QueryBuilder\JoinClause;
|
||||
|
||||
class HelloWorldHandler
|
||||
{
|
||||
private Builder $queryBuilder;
|
||||
|
||||
public function __construct(Builder $queryBuilder)
|
||||
{
|
||||
$this->queryBuilder = $queryBuilder;
|
||||
}
|
||||
|
||||
public function handle(): JsonResponse
|
||||
{
|
||||
$languageId = 1;
|
||||
|
||||
$products = $this->queryBuilder->newQuery()
|
||||
->select([
|
||||
'products.product_id' => 'product_id',
|
||||
'products.quantity' => 'product_quantity',
|
||||
'product_description.name' => 'product_name',
|
||||
'products.price' => 'product_price',
|
||||
])
|
||||
->from(db_table('product'), 'products')
|
||||
->join(
|
||||
db_table('product_description') . ' AS product_description',
|
||||
function (JoinClause $join) use ($languageId) {
|
||||
$join->on('products.product_id', '=', 'product_description.product_id')
|
||||
->where('product_description.language_id', '=', $languageId);
|
||||
}
|
||||
)
|
||||
->get();
|
||||
|
||||
return new JsonResponse([
|
||||
'data' => array_map(function ($product) {
|
||||
return [
|
||||
'product_id' => (int) $product['product_id'],
|
||||
'product_quantity' => (int) $product['product_quantity'],
|
||||
'product_name' => $product['product_name'],
|
||||
'product_price' => (float) $product['product_price'],
|
||||
];
|
||||
}, $products),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace App\Handlers;
|
||||
|
||||
use Openguru\OpenCartFramework\Http\JsonResponse;
|
||||
use Openguru\OpenCartFramework\Http\Request;
|
||||
use Openguru\OpenCartFramework\QueryBuilder\Connections\ConnectionInterface;
|
||||
|
||||
class OrderCreateHandler
|
||||
{
|
||||
private ConnectionInterface $database;
|
||||
|
||||
public function __construct(ConnectionInterface $database)
|
||||
{
|
||||
$this->database = $database;
|
||||
}
|
||||
|
||||
public function handle(Request $request): JsonResponse
|
||||
{
|
||||
$now = date('Y-m-d H:i:s');
|
||||
$storeId = 0;
|
||||
$storeName = 'Ваш магазин';
|
||||
|
||||
$sql = <<<SQL
|
||||
INSERT INTO oc_order
|
||||
(
|
||||
store_id,
|
||||
store_name,
|
||||
firstname,
|
||||
lastname,
|
||||
shipping_code,
|
||||
total,
|
||||
order_status_id,
|
||||
currency_code,
|
||||
currency_value,
|
||||
date_added,
|
||||
date_modified
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
$storeId,
|
||||
'$storeName',
|
||||
'John',
|
||||
'Doe',
|
||||
'flat.flat',
|
||||
99.9999,
|
||||
1,
|
||||
'RUB',
|
||||
1,
|
||||
'$now',
|
||||
'$now'
|
||||
)
|
||||
SQL;
|
||||
|
||||
$result = $this->database->statement($sql);
|
||||
|
||||
|
||||
return new JsonResponse([]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
namespace App\Handlers;
|
||||
|
||||
use Cart\Currency;
|
||||
use Cart\Tax;
|
||||
use Closure;
|
||||
use Openguru\OpenCartFramework\Application;
|
||||
use Openguru\OpenCartFramework\Config\Settings;
|
||||
use Openguru\OpenCartFramework\Http\JsonResponse;
|
||||
use Openguru\OpenCartFramework\Http\Request;
|
||||
use Openguru\OpenCartFramework\QueryBuilder\Builder;
|
||||
use Openguru\OpenCartFramework\QueryBuilder\JoinClause;
|
||||
|
||||
class ProductsHandler
|
||||
{
|
||||
private Builder $queryBuilder;
|
||||
private Currency $currency;
|
||||
private Tax $tax;
|
||||
private Settings $settings;
|
||||
|
||||
public function __construct(Builder $queryBuilder, Currency $currency, Tax $tax, Settings $settings)
|
||||
{
|
||||
$this->queryBuilder = $queryBuilder;
|
||||
$this->currency = $currency;
|
||||
$this->tax = $tax;
|
||||
$this->settings = $settings;
|
||||
}
|
||||
|
||||
public function handle(Request $request): JsonResponse
|
||||
{
|
||||
$languageId = 1;
|
||||
$page = $request->get('page', 1);
|
||||
$perPage = $request->get('perPage', 20);
|
||||
|
||||
$products = $this->queryBuilder->newQuery()
|
||||
->select([
|
||||
'products.product_id' => 'product_id',
|
||||
'products.quantity' => 'product_quantity',
|
||||
'product_description.name' => 'product_name',
|
||||
'products.price' => 'price',
|
||||
'products.image' => 'product_image',
|
||||
'products.tax_class_id' => 'tax_class_id',
|
||||
])
|
||||
->from(db_table('product'), 'products')
|
||||
->join(
|
||||
db_table('product_description') . ' AS product_description',
|
||||
function (JoinClause $join) use ($languageId) {
|
||||
$join->on('products.product_id', '=', 'product_description.product_id')
|
||||
->where('product_description.language_id', '=', $languageId);
|
||||
}
|
||||
)
|
||||
->forPage($page, $perPage)
|
||||
->get();
|
||||
|
||||
/** @var Closure $resize */
|
||||
$resize = Application::getInstance()->get('image_resize');
|
||||
|
||||
return new JsonResponse([
|
||||
'data' => array_map(function ($product) use ($resize) {
|
||||
if ($product['product_image']) {
|
||||
$image = $resize($product['product_image'], 500, 500);
|
||||
} else {
|
||||
$image = $resize('placeholder.png', 500, 500);
|
||||
}
|
||||
|
||||
$price = $this->currency->format(
|
||||
$this->tax->calculate(
|
||||
$product['price'],
|
||||
$product['tax_class_id'],
|
||||
$this->settings->get('oc_config_tax'),
|
||||
),
|
||||
$this->settings->get('oc_currency'),
|
||||
);
|
||||
|
||||
return [
|
||||
'id' => (int)$product['product_id'],
|
||||
'product_quantity' => (int)$product['product_quantity'],
|
||||
'name' => $product['product_name'],
|
||||
'price' => $price,
|
||||
'image' => $image,
|
||||
];
|
||||
}, $products),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace App\ServiceProviders;
|
||||
|
||||
use Openguru\OpenCartFramework\Container\ServiceProvider;
|
||||
use Openguru\OpenCartFramework\Router\Router;
|
||||
|
||||
class AppServiceProvider extends ServiceProvider
|
||||
{
|
||||
public function register(): void
|
||||
{
|
||||
$this->container->get(Router::class)->loadRoutesFromFile(__DIR__ . '/../routes.php');
|
||||
}
|
||||
}
|
||||
42
module/oc_telegram_shop/upload/oc_telegram_shop/src/config.php
Executable file
42
module/oc_telegram_shop/upload/oc_telegram_shop/src/config.php
Executable file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
'config_timezone' => 'UTC',
|
||||
|
||||
'lang' => 'en-gb',
|
||||
'language_id' => 1,
|
||||
'auth_user_id' => 0,
|
||||
|
||||
'base_url' => 'http://localhost',
|
||||
|
||||
'search_cache_seconds' => 60,
|
||||
|
||||
'chunk_size' => 100,
|
||||
|
||||
'retry_count' => 3,
|
||||
|
||||
'activity_log_retention_limit' => 5000,
|
||||
|
||||
'tables' => [
|
||||
'selected_products' => 'bp_selected_products',
|
||||
'simulation_results' => 'bp_simulation_results',
|
||||
'activity_logs' => 'bp_activity_logs',
|
||||
'cache' => 'bp_cache',
|
||||
'task_progress' => 'bp_task_progress',
|
||||
'task_steps' => 'bp_task_steps',
|
||||
'search_results' => 'bp_search_results',
|
||||
'settings' => 'bp_settings',
|
||||
],
|
||||
|
||||
'db' => [
|
||||
'host' => 'localhost',
|
||||
'database' => 'not_set',
|
||||
'username' => 'not_set',
|
||||
'password' => 'not_set',
|
||||
],
|
||||
|
||||
'logs' => [
|
||||
'path' => 'not_set',
|
||||
],
|
||||
];
|
||||
10
module/oc_telegram_shop/upload/oc_telegram_shop/src/routes.php
Executable file
10
module/oc_telegram_shop/upload/oc_telegram_shop/src/routes.php
Executable file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
use App\Handlers\HelloWorldHandler;
|
||||
use App\Handlers\OrderCreateHandler;
|
||||
use App\Handlers\ProductsHandler;
|
||||
|
||||
return [
|
||||
'products' => [ProductsHandler::class, 'handle'],
|
||||
'order_create' => [OrderCreateHandler::class, 'handle'],
|
||||
];
|
||||
Reference in New Issue
Block a user