A super easy PHP Framework for web development! https://github.com/exacti/phacil-framework
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

333 lines
9.1 KiB

6 years ago
<?php
/*
* Copyright © 2021 ExacTI Technology Solutions. All rights reserved.
* GPLv3 General License.
* https://exacti.com.br
* Phacil PHP Framework - https://github.com/exacti/phacil-framework
*/
namespace Phacil\Framework;
/**
* The registration off all objects on this Framework.
*
* @since 0.0.1
*
* @package Phacil\Framework
*/
6 years ago
final class Registry {
/**
* data Objects
* @var array
*/
6 years ago
private $data = array();
/**
* Instances objects
*
* @var array
*/
private $instances = [];
/**
* Original route for childs
* @var string
*/
public $routeOrig;
/**
*
* @var string
*/
public $route;
/**
* AutoInstances Loaded
*
* @var array
*/
static private $autoInstances = [];
/**
* AutoInstances Loaded
*
* @var array
*/
static private $preferences = [];
/**
* Magic method to return engine instances
*
* @param string $key
* @return mixed
*/
public function __get($key) {
return $this->get($key);
}
/**
* @param string $key
* @return mixed
*/
6 years ago
public function get($key) {
return (isset($this->instances[$key]) ? $this->instances[$key] : $this->engine->checkRegistry($key));
6 years ago
}
/**
* @param string $key
* @param mixed $value
* @return void
*/
6 years ago
public function set($key, $value) {
$this->instances[$key] = $value;
6 years ago
}
/**
* @param string $key
* @return bool
*/
6 years ago
public function has($key) {
return isset($this->instances[$key]);
6 years ago
}
/**
* UnSet
*
* Unsets registry value by key.
*
* @param string $key
* @return void
*/
public function delete(string $key) {
if (isset($this->instances[$key])) {
unset($this->instances[$key]);
}
}
/**
* Try to obtain an iniciated engine instance
*
* @param string|object|null $class (optional)
* @param array $args (optional)
*
* @return \Phacil\Framework\Registry
* @since 2.0.0
*/
static public function getInstance($class = null, $args = [], $onlyCheckInstances = false) {
if(!$class) return \Phacil\Framework\startEngineExacTI::getRegistry();
$registry = \Phacil\Framework\startEngineExacTI::getRegistry();
$return = false;
$classObj = (is_object($class)) ? get_class($class) : $class;
if (isset(self::$autoInstances[($classObj)])) return self::$autoInstances[($classObj)];
foreach ($registry->instances as $key => $value) {
if(!is_object($value)) continue;
if(get_class($value) == $classObj) {$return = $value; break; }
}
if($return) return $return;
if($onlyCheckInstances) return $return;
if(is_string($class)) {
$classCreate = self::checkPreference($class);
$reflector = new ReflectionClass($classCreate);
return self::setAutoInstance($reflector->newInstanceArgs($args), $class);
}
if (is_object($class)) {
return self::getInstance($class);
}
return null;
}
/**
* @param string $class
* @param array $args
* @return mixed
* @throws \ReflectionException
* @throws \Exception
* @throws \Phacil\Framework\Exception
*/
public function create($class, $args = array()) {
if(is_string($class)) {
return $this->injectionClass($class, $args, true);
/* $classCreate = self::checkPreference($class);
$reflector = new ReflectionClass($classCreate);
return self::setAutoInstance($reflector->newInstanceArgs($args), $class); */
}
return null;
}
/**
* Adds DI preferences from a JSON file.
*
* This method reads a JSON file containing preferences and merges them into the existing preferences array.
*
* @param string $jsonFilePath The path to the JSON file containing preferences.
* @return void
* @throws \Phacil\Framework\Exception If there is an error reading the JSON file or if the JSON data is invalid.
*/
static public function addPreference($jsonFilePath) {
if (file_exists($jsonFilePath)) {
$jsonData = file_get_contents($jsonFilePath);
$dataArray = json_decode($jsonData, true);
// Verifica se a conversão foi bem-sucedida
if ($dataArray === null && json_last_error() !== JSON_ERROR_NONE) {
// Se houver um erro na conversão, trata o erro
$error = new \Phacil\Framework\Exception(json_last_error_msg());
return;
}
}
if (isset($dataArray['preferences']))
self::$preferences = array_merge(self::$preferences, $dataArray['preferences']);
}
/**
* Checks if a preference has been set for the specified class and returns it if found.
*
* This method checks if a preference has been set for the specified class. If a preference
* is found, it returns the class name defined as the preference; otherwise, it returns the
* original class name.
*
* @param string $class The class name to check for a preference.
* @return string The class name defined as the preference, if found; otherwise, the original class name.
*/
static public function checkPreference($class) {
if(isset(self::$preferences[$class])) {
return self::$preferences[$class];
}
return $class;
}
/**
* Sets an auto-instantiated object to be used as a dependency.
*
* This method allows you to set an object to be automatically instantiated and used as a dependency
* when resolving other dependencies that require an instance of the specified class.
*
* @param object $class The object instance to be set as an auto-instantiated dependency.
* @param string|null (Optional) $original The original class name of the object being set.
* @return object The object instance that was set as an auto-instantiated dependency.
* @throws \Phacil\Framework\Exception If the provided parameter is not an object.
* @since 2.0.0
*/
static public function setAutoInstance($class, $original = null) {
if(!is_object($class)) throw new Exception('Object type is required!');
self::$autoInstances[$original ?: get_class($class)] = $class;
return $class;
}
/**
*
* @param object $class
* @return object
* @since 2.0.0
* @throws \Phacil\Framework\Exception
*/
static public function getAutoInstance($class) {
if (!is_object($class)) throw new Exception('Object type is required!');
return isset(self::$autoInstances[get_class($class)]) ? self::$autoInstances[get_class($class)] : self::setAutoInstance($class);
}
/**
* Resolves and instantiates a class with optional constructor arguments and creation control.
*
* This method resolves a class by its name, instantiates it with optional constructor arguments,
* and provides control over the creation process.
*
* @param string $class The fully qualified name of the class to instantiate.
* @param array $args (Optional) Arguments for the class constructor. Default is an empty array.
* If empty, constructor arguments will be automatically detected and injected.
* @param bool $forceCreate (Optional) Whether to force creation. Default is false.
* @return mixed
* @throws \ReflectionException
* @throws \Exception
* @throws \Phacil\Framework\Exception
*/
public function injectionClass($class, $args = array(), $forceCreate = false)
{
$argsToInject = !empty($args) ? $args : false;
$originalClass = $class;
$class = self::checkPreference($class);
$originalClass = $originalClass == $class ? null : $originalClass;
$refClass = new ReflectionClass($class);
try {
if (!$forceCreate && $autoInstance = $this->getInstance($originalClass ?: $class, [], true))
return $autoInstance;
if (!$refClass->getConstructor() && !$argsToInject) {
if ($refClass->hasMethod('getInstance') && $refClass->getMethod('getInstance')->isStatic()) {
return $refClass->getMethod('getInstance')->invoke(null);
}
return $refClass->newInstanceWithoutConstructor();
}
} catch (\Throwable $th) {
//throw $th;
}
$rMethod = new ReflectionMethod($class, "__construct");
if(!$argsToInject){
$params = $rMethod->getParameters();
$argsToInject = [];
foreach ($params as $param) {
//$param is an instance of ReflectionParameter
try {
if (version_compare(phpversion(), "7.2.0", "<")) {
if ($param->getClass()) {
$injectionClass = $param->getClass()->name;
if (class_exists($injectionClass)) {
$argsToInject[$param->getPosition()] = $this->injectionClass($injectionClass);
continue;
}
if (!$param->isOptional()) {
throw new \Phacil\Framework\Exception\ReflectionException("Error Processing Request: " . $injectionClass . "not exist");
}
}
} else {
if ($param->getType()) {
$injectionClass = $param->getType()->getName();
if (class_exists($injectionClass)) {
$argsToInject[$param->getPosition()] = $this->injectionClass($injectionClass);
continue;
}
if (!$param->isOptional()) {
throw new \Phacil\Framework\Exception\ReflectionException("Error Processing Request: " . $injectionClass . "not exist");
}
}
}
} catch (\Exception $th) {
throw $th;
}
if ($param->isOptional() && $param->isDefaultValueAvailable()) {
$argsToInject[] = $param->getDefaultValue();
continue;
}
if ($param->isOptional()) {
$argsToInject[] = null;
}
}
}
return self::setAutoInstance($refClass->newInstanceArgs($argsToInject), $originalClass);
}
6 years ago
}