first commit

This commit is contained in:
sujan
2024-08-06 18:06:00 +05:45
commit a2fa49071a
2745 changed files with 391199 additions and 0 deletions

87
system/engine/action.php Normal file
View File

@ -0,0 +1,87 @@
<?php
/**
* @package OpenCart
* @author Daniel Kerr
* @copyright Copyright (c) 2005 - 2017, OpenCart, Ltd. (https://www.opencart.com/)
* @license https://opensource.org/licenses/GPL-3.0
* @link https://www.opencart.com
*/
namespace Opencart\System\Engine;
/**
* Class Action
*/
class Action {
/**
* @var string|array|string[]|null
*/
private string $route;
/**
* @var string
*/
private string $class;
/**
* @var string
*/
private string $method;
/**
* Constructor
*
* @param string $route
*/
public function __construct(string $route) {
$this->route = preg_replace('/[^a-zA-Z0-9_|\/\.]/', '', $route);
$pos = strrpos($this->route, '.');
if ($pos === false) {
$this->class = 'Controller\\' . str_replace(['_', '/'], ['', '\\'], ucwords($this->route, '_/'));
$this->method = 'index';
} else {
$this->class = 'Controller\\' . str_replace(['_', '/'], ['', '\\'], ucwords(substr($this->route, 0, $pos), '_/'));
$this->method = substr($this->route, $pos + 1);
}
}
/**
* getId
*
* @return string
*
*/
public function getId(): string {
return $this->route;
}
/**
*
* Execute
*
* @param object $registry
* @param array $args
*
* @return mixed
*/
public function execute(\Opencart\System\Engine\Registry $registry, array &$args = []): mixed {
// Stop any magical methods being called
if (substr($this->method, 0, 2) == '__') {
return new \Exception('Error: Calls to magic methods are not allowed!');
}
// Get the current namespace being used by the config
$class = 'Opencart\\' . $registry->get('config')->get('application') . '\\' . $this->class;
// Initialize the class
if (class_exists($class)) {
$controller = new $class($registry);
} else {
return new \Exception('Error: Could not call route ' . $this->route . '!');
}
if (is_callable([$controller, $this->method])) {
return call_user_func_array([$controller, $this->method], $args);
} else {
return new \Exception('Error: Could not call route ' . $this->route . '!');
}
}
}

View File

@ -0,0 +1,81 @@
<?php
/**
* @package OpenCart
* @author Daniel Kerr
* @copyright Copyright (c) 2005 - 2017, OpenCart, Ltd. (https://www.opencart.com/)
* @license https://opensource.org/licenses/GPL-3.0
* @link https://www.opencart.com
*/
namespace Opencart\System\Engine;
/**
* Class Autoloader
*/
class Autoloader {
/**
* @var array
*/
private array $path = [];
/**
* Constructor
*/
public function __construct() {
spl_autoload_register([$this, 'load']);
spl_autoload_extensions('.php');
}
/**
* Register
*
* @param string $namespace
* @param string $directory
* @param bool $psr4
*
* @return void
*
* @psr-4 filename standard is stupid composer has lower case file structure than its packages have camelcase file names!
*/
public function register(string $namespace, string $directory, $psr4 = false): void {
$this->path[$namespace] = [
'directory' => $directory,
'psr4' => $psr4
];
}
/**
* Load
*
* @param string $class
*
* @return bool
*/
public function load(string $class): bool {
$namespace = '';
$parts = explode('\\', $class);
foreach ($parts as $part) {
if (!$namespace) {
$namespace .= $part;
} else {
$namespace .= '\\' . $part;
}
if (isset($this->path[$namespace])) {
if (!$this->path[$namespace]['psr4']) {
$file = $this->path[$namespace]['directory'] . trim(str_replace('\\', '/', strtolower(preg_replace('~([a-z])([A-Z]|[0-9])~', '\\1_\\2', substr($class, strlen($namespace))))), '/') . '.php';
} else {
$file = $this->path[$namespace]['directory'] . trim(str_replace('\\', '/', substr($class, strlen($namespace))), '/') . '.php';
}
}
}
if (isset($file) && is_file($file)) {
include_once($file);
return true;
} else {
return false;
}
}
}

109
system/engine/config.php Normal file
View File

@ -0,0 +1,109 @@
<?php
/**
* @package OpenCart
* @author Daniel Kerr
* @copyright Copyright (c) 2005 - 2017, OpenCart, Ltd. (https://www.opencart.com/)
* @license https://opensource.org/licenses/GPL-3.0
* @link https://www.opencart.com
*/
namespace Opencart\System\Engine;
/**
* Class Config
*/
class Config {
/**
* @var string
*/
protected string $directory;
/**
* @var array
*/
private array $path = [];
/**
* @var array
*/
private array $data = [];
/**
* addPath
*
* @param string $namespace
* @param string $directory
*/
public function addPath(string $namespace, string $directory = ''): void {
if (!$directory) {
$this->directory = $namespace;
} else {
$this->path[$namespace] = $directory;
}
}
/**
* Get
*
* @param string $key
*
* @return mixed
*/
public function get(string $key): mixed {
return isset($this->data[$key]) ? $this->data[$key] : '';
}
/**
* Set
*
* @param string $key
* @param string $value
*/
public function set(string $key, mixed $value): void {
$this->data[$key] = $value;
}
/**
* Has
*
* @param string $key
*
* @return mixed
*/
public function has(string $key): bool {
return isset($this->data[$key]);
}
/**
* Load
*
* @param string $filename
*/
public function load(string $filename): array {
$file = $this->directory . $filename . '.php';
$namespace = '';
$parts = explode('/', $filename);
foreach ($parts as $part) {
if (!$namespace) {
$namespace .= $part;
} else {
$namespace .= '/' . $part;
}
if (isset($this->path[$namespace])) {
$file = $this->path[$namespace] . substr($filename, strlen($namespace)) . '.php';
}
}
if (is_file($file)) {
$_ = [];
require($file);
$this->data = array_merge($this->data, $_);
return $this->data;
} else {
return [];
}
}
}

View File

@ -0,0 +1,54 @@
<?php
/**
* @package OpenCart
* @author Daniel Kerr
* @copyright Copyright (c) 2005 - 2022, OpenCart, Ltd. (https://www.opencart.com/)
* @license https://opensource.org/licenses/GPL-3.0
* @link https://www.opencart.com
*/
namespace Opencart\System\Engine;
/**
* Class Controller
*/
class Controller {
/**
* @var object|\Opencart\System\Engine\Registry
*/
protected $registry;
/**
* Constructor
*
* @param object $registry
*/
public function __construct(\Opencart\System\Engine\Registry $registry) {
$this->registry = $registry;
}
/**
* __get
*
* @param string $key
*
* @return object
*/
public function __get(string $key): object {
if ($this->registry->has($key)) {
return $this->registry->get($key);
} else {
throw new \Exception('Error: Could not call registry key ' . $key . '!');
}
}
/**
* __set
*
* @param string $key
* @param object $value
*
* @return void
*/
public function __set(string $key, object $value): void {
$this->registry->set($key, $value);
}
}

103
system/engine/event.php Normal file
View File

@ -0,0 +1,103 @@
<?php
/**
* @package OpenCart
* @author Daniel Kerr
* @copyright Copyright (c) 2005 - 2022, OpenCart, Ltd. (https://www.opencart.com/)
* @license https://opensource.org/licenses/GPL-3.0
* @link https://www.opencart.com
*/
namespace Opencart\System\Engine;
/**
* Class Event
*
* https://github.com/opencart/opencart/wiki/Events-(script-notifications)-2.2.x.x
*/
class Event {
/**
* @var \Opencart\System\Engine\Registry
*/
protected $registry;
/**
* @var array
*/
protected array $data = [];
/**
* Constructor
*
* @param object $route
*/
public function __construct(\Opencart\System\Engine\Registry $registry) {
$this->registry = $registry;
}
/**
*
*
* @param string $trigger
* @param object $action
* @param int $priority
*/
public function register(string $trigger, \Opencart\System\Engine\Action $action, int $priority = 0): void {
$this->data[] = [
'trigger' => $trigger,
'action' => $action,
'priority' => $priority
];
$sort_order = [];
foreach ($this->data as $key => $value) {
$sort_order[$key] = $value['priority'];
}
array_multisort($sort_order, SORT_ASC, $this->data);
}
/**
*
*
* @param string $event
* @param array $args
*/
public function trigger(string $event, array $args = []): mixed {
foreach ($this->data as $value) {
if (preg_match('/^' . str_replace(['\*', '\?'], ['.*', '.'], preg_quote($value['trigger'], '/')) . '/', $event)) {
$result = $value['action']->execute($this->registry, $args);
if (!is_null($result) && !($result instanceof \Exception)) {
return $result;
}
}
}
return '';
}
/**
*
*
* @param string $trigger
* @param string $route
*/
public function unregister(string $trigger, string $route): void {
foreach ($this->data as $key => $value) {
if ($trigger == $value['trigger'] && $value['action']->getId() == $route) {
unset($this->data[$key]);
}
}
}
/**
*
*
* @param string $trigger
*/
public function clear(string $trigger): void {
foreach ($this->data as $key => $value) {
if ($trigger == $value['trigger']) {
unset($this->data[$key]);
}
}
}
}

317
system/engine/loader.php Normal file
View File

@ -0,0 +1,317 @@
<?php
/**
* @package OpenCart
* @author Daniel Kerr
* @copyright Copyright (c) 2005 - 2022, OpenCart, Ltd. (https://www.opencart.com/)
* @license https://opensource.org/licenses/GPL-3.0
* @link https://www.opencart.com
*/
namespace Opencart\System\Engine;
/**
* Class Loader
*/
class Loader {
/**
* @var object|\Opencart\System\Engine\Registry
*/
protected $registry;
/**
* Constructor
*
* @param object $registry
*/
public function __construct(\Opencart\System\Engine\Registry $registry) {
$this->registry = $registry;
}
/**
* __get
*
* https://www.php.net/manual/en/language.oop5.overloading.php#object.get
*
* @param string $key
*
* @return object
*/
public function __get(string $key): object {
return $this->registry->get($key);
}
/**
* __set
*
* https://www.php.net/manual/en/language.oop5.overloading.php#object.set
*
* @param string $key
* @param object $value
*
* @return void
*/
public function __set(string $key, object $value): void {
$this->registry->set($key, $value);
}
/**
* Controller
*
* https://wiki.php.net/rfc/variadics
*
* @param string $route
* @param array $data
*
* @return mixed
*/
public function controller(string $route, mixed ...$args): mixed {
// Sanitize the call
$route = preg_replace('/[^a-zA-Z0-9_|\/\.]/', '', str_replace('|', '.', $route));
$output = '';
// Keep the original trigger
$action = new \Opencart\System\Engine\Action($route);
while ($action) {
$route = $action->getId();
// Trigger the pre events
$result = $this->event->trigger('controller/' . $route . '/before', [&$route, &$args]);
if ($result instanceof \Opencart\System\Engine\Action) {
$action = $result;
}
// Execute action
$result = $action->execute($this->registry, $args);
// Make action a non-object so it's not infinitely looping
$action = '';
// Action object returned then we keep the loop going
if ($result instanceof \Opencart\System\Engine\Action) {
$action = $result;
}
// If not an object then it's the output
if (!$action) {
$output = $result;
}
// Trigger the post events
$result = $this->event->trigger('controller/' . $route . '/after', [&$route, &$args, &$output]);
if ($result instanceof \Opencart\System\Engine\Action) {
$action = $result;
}
}
return $output;
}
/**
* Model
*
* @param string $route
*
* @return void
*/
public function model(string $route): void {
// Sanitize the call
$route = preg_replace('/[^a-zA-Z0-9_\/]/', '', $route);
// Converting a route path to a class name
$class = 'Opencart\\' . $this->config->get('application') . '\Model\\' . str_replace(['_', '/'], ['', '\\'], ucwords($route, '_/'));
// Create a key to store the model object
$key = 'model_' . str_replace('/', '_', $route);
// Check if the requested model is already stored in the registry.
if (!$this->registry->has($key)) {
if (class_exists($class)) {
$model = new $class($this->registry);
$proxy = new \Opencart\System\Engine\Proxy();
foreach (get_class_methods($model) as $method) {
if ((substr($method, 0, 2) != '__') && is_callable($class, $method)) {
// Grab args using function because we don't know the number of args being passed.
// https://www.php.net/manual/en/functions.arguments.php#functions.variable-arg-list
// https://wiki.php.net/rfc/variadics
$proxy->{$method} = function (mixed &...$args) use ($route, $model, $method): mixed {
$route = $route . '/' . $method;
$output = '';
// Trigger the pre events
$result = $this->event->trigger('model/' . $route . '/before', [&$route, &$args]);
if ($result) {
$output = $result;
}
if (!$output) {
// Get the method to be used
$callable = [$model, $method];
if (is_callable($callable)) {
$output = call_user_func_array($callable, $args);
} else {
throw new \Exception('Error: Could not call model/' . $route . '!');
}
}
// Trigger the post events
$result = $this->event->trigger('model/' . $route . '/after', [&$route, &$args, &$output]);
if ($result) {
$output = $result;
}
return $output;
};
}
}
$this->registry->set($key, $proxy);
} else {
throw new \Exception('Error: Could not load model ' . $class . '!');
}
}
}
/**
* View
*
* Loads the template file and generates the html code.
*
* @param string $route
* @param array $data
* @param string $code
*
* @return string
*/
public function view(string $route, array $data = [], string $code = ''): string {
// Sanitize the call
$route = preg_replace('/[^a-zA-Z0-9_\/]/', '', $route);
$output = '';
// Trigger the pre events
$result = $this->event->trigger('view/' . $route . '/before', [&$route, &$data, &$code]);
if ($result) {
$output = $result;
}
if (!$output) {
// Make sure it's only the last event that returns an output if required.
$output = $this->template->render($route, $data, $code);
}
// Trigger the post events
$result = $this->event->trigger('view/' . $route . '/after', [&$route, &$data, &$output]);
if ($result) {
$output = $result;
}
return $output;
}
/**
* Language
*
* @param string $route
* @param string $prefix
* @param string $code
*
* @return array
*/
public function language(string $route, string $prefix = '', string $code = ''): array {
// Sanitize the call
$route = preg_replace('/[^a-zA-Z0-9_\-\/]/', '', $route);
$output = [];
// Trigger the pre events
$result = $this->event->trigger('language/' . $route . '/before', [&$route, &$prefix, &$code]);
if ($result) {
$output = $result;
}
if (!$output) {
$output = $this->language->load($route, $prefix, $code);
}
// Trigger the post events
$result = $this->event->trigger('language/' . $route . '/after', [&$route, &$prefix, &$code, &$output]);
if ($result) {
$output = $result;
}
return $output;
}
/**
* Config
*
* @param string $route
*
* @return array
*/
public function config(string $route): array {
// Sanitize the call
$route = preg_replace('/[^a-zA-Z0-9_\-\/]/', '', $route);
$output = [];
// Trigger the pre events
$result = $this->event->trigger('config/' . $route . '/before', [&$route]);
if ($result) {
$output = $result;
}
if (!$output) {
$output = $this->config->load($route);
}
// Trigger the post events
$result = $this->event->trigger('config/' . $route . '/after', [&$route, &$output]);
if ($result) {
$output = $result;
}
return $output;
}
/**
* Helper
*
* @param string $route
*
* @return void
*/
public function helper(string $route): void {
$route = preg_replace('/[^a-zA-Z0-9_\/]/', '', $route);
if (!str_starts_with($route, 'extension/')) {
$file = DIR_SYSTEM . 'helper/' . $route . '.php';
} else {
$parts = explode('/', substr($route, 10));
$code = array_shift($parts);
$file = DIR_EXTENSION . $code . '/system/helper/' . implode('/', $parts) . '.php';
}
if (is_file($file)) {
include_once($file);
} else {
throw new \Exception('Error: Could not load helper ' . $route . '!');
}
}
}

58
system/engine/model.php Normal file
View File

@ -0,0 +1,58 @@
<?php
/**
* @package OpenCart
* @author Daniel Kerr
* @copyright Copyright (c) 2005 - 2022, OpenCart, Ltd. (https://www.opencart.com/)
* @license https://opensource.org/licenses/GPL-3.0
* @link https://www.opencart.com
*/
/**
* Model class
*/
namespace Opencart\System\Engine;
/**
* Class Model
*/
class Model {
/**
* @var object|\Opencart\System\Engine\Registry
*/
protected $registry;
/**
* Constructor
*
* @param object $registry
*/
public function __construct(\Opencart\System\Engine\Registry $registry) {
$this->registry = $registry;
}
/**
* __get
*
* @param string $key
*
* @return object
*/
public function __get(string $key): object {
if ($this->registry->has($key)) {
return $this->registry->get($key);
} else {
throw new \Exception('Error: Could not call registry key ' . $key . '!');
}
}
/**
* __set
*
* @param string $key
* @param string $value
*
* @return void
*/
public function __set(string $key, object $value): void {
$this->registry->set($key, $value);
}
}

88
system/engine/proxy.php Normal file
View File

@ -0,0 +1,88 @@
<?php
/**
* @package OpenCart
* @author Daniel Kerr
* @copyright Copyright (c) 2005 - 2022, OpenCart, Ltd. (https://www.opencart.com/)
* @license https://opensource.org/licenses/GPL-3.0
* @link https://www.opencart.com
*/
namespace Opencart\System\Engine;
/**
* Class Proxy
*/
class Proxy {
/**
* @var array
*/
protected $data = [];
/**
* __get
*
* @param string $key
*
* @return object|null
*/
public function &__get(string $key): object|null {
if (isset($this->data[$key])) {
return $this->data[$key];
} else {
throw new \Exception('Error: Could not call proxy key ' . $key . '!');
}
}
/**
* __set
*
* @param string $key
* @param string $value
*
* @return void
*/
public function __set(string $key, object $value): void {
$this->data[$key] = $value;
}
/**
* __isset
*
* @param string $key
*
* @return void
*/
public function __isset(string $key) {
return isset($this->data[$key]);
}
/**
* __unset
*
* @param string $key
*
* @return void
*/
public function __unset(string $key) {
unset($this->data[$key]);
}
/**
* __call
*
* @param string $method
* @param array $args
*
* @return mixed
*/
public function __call(string $method, array $args): mixed {
// Hack for pass-by-reference
foreach ($args as $key => &$value) ;
if (isset($this->data[$method])) {
return call_user_func_array($this->data[$method], $args);
} else {
$trace = debug_backtrace();
throw new \Exception('<b>Notice</b>: Undefined property: Proxy::' . $method . ' in <b>' . $trace[0]['file'] . '</b> on line <b>' . $trace[0]['line'] . '</b>');
}
}
}

View File

@ -0,0 +1,94 @@
<?php
/**
* @package OpenCart
* @author Daniel Kerr
* @copyright Copyright (c) 2005 - 2022, OpenCart, Ltd. (https://www.opencart.com/)
* @license https://opensource.org/licenses/GPL-3.0
* @link https://www.opencart.com
*/
namespace Opencart\System\Engine;
/**
* Class Registry
*/
class Registry {
/**
* @var array
*/
private array $data = [];
/**
* __get
*
* https://www.php.net/manual/en/language.oop5.overloading.php#object.get
*
* @param string $key
*
* @return object
*/
public function __get(string $key): object|null {
return $this->get($key);
}
/**
* __set
*
* https://www.php.net/manual/en/language.oop5.overloading.php#object.set
*
* @param string $key
* @param object $value
*
* @return null
*/
public function __set(string $key, object $value): void {
$this->set($key, $value);
}
/**
* Get
*
* @param string $key
*
* @return object
*/
public function get(string $key): object|null {
return isset($this->data[$key]) ? $this->data[$key] : null;
}
/**
* Set
*
* @param string $key
* @param object $value
*
* @return void
*/
public function set(string $key, object $value): void {
$this->data[$key] = $value;
}
/**
* Has
*
* @param string $key
*
* @return bool
*/
public function has(string $key): bool {
return isset($this->data[$key]);
}
/**
* Unset
*
* Unsets registry value by key.
*
* @param string $key
*
* @return null
*/
public function unset(string $key): void {
if (isset($this->data[$key])) {
unset($this->data[$key]);
}
}
}