- First draft of current WIP
This commit is contained in:
commit
b73d046e0a
47 files changed
+2797
No files matched your search
@@ -0,0 +1,212 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Common;
|
||||
|
||||
trait ArrayObjectTrait {
|
||||
|
||||
protected $arrayobject_pointer = null;
|
||||
|
||||
protected $arrayobject_container = [];
|
||||
|
||||
protected $arrayobject_changed = [];
|
||||
|
||||
protected $arrayobject_selected = false;
|
||||
|
||||
public function count() : int
|
||||
{
|
||||
return count( $this->arrayobject_container() );
|
||||
}
|
||||
|
||||
public function contains($term, $strict = false) : bool
|
||||
{
|
||||
return (array_search($term, $this->arrayobject_container(), $strict) !== false) ;
|
||||
}
|
||||
|
||||
public function &arrayobject_current()
|
||||
{
|
||||
if ( !is_null($this->arrayobject_pointer) ) {
|
||||
$var = &$this->arrayobject_container()[$this->arrayobject_pointer] ?: [];
|
||||
$var || ( $var = [] );
|
||||
return $var;
|
||||
}
|
||||
|
||||
if ( $this->arrayobject_selected !== false ){
|
||||
$ret = &$this->arrayobject_selected ?: [];
|
||||
return $ret;
|
||||
}
|
||||
|
||||
# Restoring integrity of container since it could be nullified
|
||||
if ( ! is_array($this->arrayobject_container()) ) {
|
||||
$this->arrayobject_container([]);
|
||||
}
|
||||
|
||||
return $this->arrayobject_container();
|
||||
}
|
||||
|
||||
public function offsetSet($offset, $value, $changed = null)
|
||||
{
|
||||
if ( $changed && (!isset($this->arrayobject_current()[$offset]) || ($this->arrayobject_current()[$offset] !== $value) ) ) {
|
||||
$this->arrayobject_changed($offset, true);
|
||||
}
|
||||
|
||||
return is_null($offset) ? $this->arrayobject_current()[] = $value : $this->arrayobject_current()[$offset] = $value;
|
||||
}
|
||||
|
||||
public function arrayobject_set_pointer($pointer)
|
||||
{
|
||||
# $pointer could nullify obj pointer
|
||||
if ( $this->arrayobject_pointer = $pointer ) {
|
||||
# Creating dataset whenever we have a new one
|
||||
if ( ! isset($this->arrayobject_container()[$this->arrayobject_pointer]) ) {
|
||||
$this->arrayobject_container()[$this->arrayobject_pointer] = [];
|
||||
$this->arrayobject_changed[$this->arrayobject_pointer] = [];
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function arrayobject_select($selection, $purge = true)
|
||||
{
|
||||
if ( is_bool($selection) ) {
|
||||
return $this->arrayobject_selected = $selection;
|
||||
}
|
||||
|
||||
$purge && ( $this->arrayobject_selected = [] );
|
||||
|
||||
foreach($selection as $pointer) {
|
||||
$this->arrayobject_selected[$pointer] = &$this->arrayobject_container[$pointer];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function arrayobject_exist($pointer) : bool
|
||||
{
|
||||
return isset( $this->arrayobject_container()[$pointer] );
|
||||
}
|
||||
|
||||
public function arrayobject_flush_changed() {
|
||||
! is_null($this->arrayobject_pointer) ?
|
||||
$this->arrayobject_changed[$this->arrayobject_pointer] = []
|
||||
:
|
||||
$this->arrayobject_changed = []
|
||||
;
|
||||
}
|
||||
|
||||
public function arrayobject_changed($offset = null, $set = null) {
|
||||
if ($offset) {
|
||||
if ($set !== null) {
|
||||
! is_null($this->arrayobject_pointer) ?
|
||||
( $this->arrayobject_changed[$this->arrayobject_pointer][$offset] = $set )
|
||||
:
|
||||
( $this->arrayobject_changed[$offset] = $set );
|
||||
}
|
||||
|
||||
return !is_null($this->arrayobject_pointer) ? $this->arrayobject_changed[$this->arrayobject_pointer][$offset] : $this->arrayobject_changed[$offset];
|
||||
}
|
||||
|
||||
return array_keys( !is_null($this->arrayobject_pointer)
|
||||
? $this->arrayobject_changed[$this->arrayobject_pointer] ?? []
|
||||
: $this->arrayobject_changed) ?? [];
|
||||
}
|
||||
|
||||
public function arrayobject_remove($pointer) {
|
||||
if ( isset($this->arrayobject_container()[$pointer]) ) {
|
||||
unset( $this->arrayobject_container()[$pointer], $this->arrayobject_changed[$pointer]);
|
||||
}
|
||||
}
|
||||
|
||||
public function arrayobject_iterate($callback) {
|
||||
if ( $callback && is_callable($callback) ) {
|
||||
$pointer = $this->arrayobject_pointer;
|
||||
|
||||
foreach($this->arrayobject_container() as $key => $value) {
|
||||
$this->arrayobject_set_pointer($key);
|
||||
$callback($key, $this);
|
||||
}
|
||||
|
||||
$this->arrayobject_set_pointer($pointer);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function offsetGet($offset)
|
||||
{
|
||||
if ( !is_null($this->arrayobject_pointer) ) {
|
||||
return isset($this->arrayobject_container()[$this->arrayobject_pointer][$offset]) ? $this->arrayobject_container()[$this->arrayobject_pointer][$offset] : null;
|
||||
}
|
||||
else {
|
||||
return isset($this->arrayobject_container()[$offset]) ? $this->arrayobject_container()[$offset] : null;
|
||||
}
|
||||
}
|
||||
|
||||
public function offsetExists($offset) : bool
|
||||
{
|
||||
return array_key_exists($offset, $this->arrayobject_current() );
|
||||
}
|
||||
|
||||
public function offsetUnset($offset)
|
||||
{
|
||||
if ( !is_null($this->arrayobject_pointer)) {
|
||||
unset($this->arrayobject_container()[$this->arrayobject_pointer][$offset]);
|
||||
}
|
||||
else {
|
||||
unset($this->arrayobject_container()[$offset]) ;
|
||||
}
|
||||
}
|
||||
|
||||
public function arrayobject_sort($field, $order = 'ASC')
|
||||
{
|
||||
Arrayobj::order_by($this->arrayobject_container(), $field);
|
||||
$order === 'DESC' && array_reverse($this->arrayobject_current());
|
||||
}
|
||||
|
||||
public function rewind()
|
||||
{
|
||||
reset( $this->arrayobject_container() );
|
||||
|
||||
# Rewinding will also reset the pointer
|
||||
$this->arrayobject_set_pointer(key($this->arrayobject_container()));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function current()
|
||||
{
|
||||
return $this->arrayobject_set_pointer( $this->key() );
|
||||
}
|
||||
|
||||
public function key()
|
||||
{
|
||||
$var = key( $this->arrayobject_container() );
|
||||
return $var;
|
||||
}
|
||||
|
||||
public function next()
|
||||
{
|
||||
$var = next( $this->arrayobject_container() );
|
||||
return $var;
|
||||
}
|
||||
|
||||
public function valid() : bool
|
||||
{
|
||||
$key = $this->key();
|
||||
return ( $key !== NULL ) && ( $key !== FALSE );
|
||||
}
|
||||
|
||||
protected function &arrayobject_container($set = null)
|
||||
{
|
||||
if ( $set !== null ) {
|
||||
$this->arrayobject_container = $set;
|
||||
}
|
||||
|
||||
if ( $this->arrayobject_selected !== false ) {
|
||||
return $this->arrayobject_selected;
|
||||
}
|
||||
|
||||
return $this->arrayobject_container;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Common;
|
||||
|
||||
use Ulmus\Ulmus;
|
||||
|
||||
class EntityField
|
||||
{
|
||||
public string $name;
|
||||
|
||||
public string $entityClass;
|
||||
|
||||
public string $alias;
|
||||
|
||||
protected EntityResolver $entityResolver;
|
||||
|
||||
public function __construct(string $entityClass, string $name, string $alias)
|
||||
{
|
||||
$this->entityClass = $entityClass;
|
||||
$this->name = $name;
|
||||
$this->alias = $alias;
|
||||
$this->entityResolver = Ulmus::resolveEntity(static::class);
|
||||
}
|
||||
|
||||
public function name($useAlias = true) : string
|
||||
{
|
||||
# Must use REFLECTION before throwing this value.
|
||||
# Should first check if it's a relation field, and if it is,
|
||||
# it's real key must be returned (PK usually)
|
||||
return $useAlias ? "{$this->alias}.`{$this->name}`" : $this->name;
|
||||
}
|
||||
|
||||
public static function isScalarType($type) : bool
|
||||
{
|
||||
switch($type) {
|
||||
case 'int':
|
||||
case 'bool':
|
||||
case 'string':
|
||||
case 'float':
|
||||
case 'double':
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function isObjectType($type) : bool
|
||||
{
|
||||
return strpos($type, "\\") !== false;
|
||||
}
|
||||
|
||||
public function __toString() : string
|
||||
{
|
||||
return $this->name();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Common;
|
||||
|
||||
use Ulmus\Annotation\Annotation,
|
||||
Ulmus\Annotation\Classes\Table,
|
||||
Ulmus\Annotation\Property\Field;
|
||||
|
||||
class EntityResolver {
|
||||
|
||||
const KEY_ENTITY_NAME = 01;
|
||||
const KEY_COLUMN_NAME = 02;
|
||||
|
||||
public string $entityClass;
|
||||
|
||||
public array $uses;
|
||||
|
||||
public array $class;
|
||||
|
||||
public array $properties;
|
||||
|
||||
public array $methods;
|
||||
|
||||
public function __construct(string $entityClass)
|
||||
{
|
||||
$this->entityClass = $entityClass;
|
||||
|
||||
list($this->uses, $this->class, $this->methods, $this->properties) = array_values(
|
||||
ObjectReflection::fromClass($entityClass)->read()
|
||||
);
|
||||
|
||||
$this->resolveAnnotations();
|
||||
}
|
||||
|
||||
public function field($name, $fieldKey = self::KEY_ENTITY_NAME) : ? array
|
||||
{
|
||||
try{
|
||||
return $this->fieldList($fieldKey)[$name];
|
||||
}
|
||||
catch(\Throwable $e) {
|
||||
throw new \InvalidArgumentException("Can't find entity field's column named `$name` from entity {$this->entityClass}");
|
||||
}
|
||||
}
|
||||
|
||||
public function fieldList($fieldKey = self::KEY_ENTITY_NAME) : array
|
||||
{
|
||||
$fieldList = [];
|
||||
|
||||
foreach($this->properties as $item) {
|
||||
foreach($item['tags'] ?? [] as $tag) {
|
||||
if ( $tag['object'] instanceof Field ) {
|
||||
switch($fieldKey) {
|
||||
case static::KEY_ENTITY_NAME:
|
||||
$key = $item['name'];
|
||||
break;
|
||||
|
||||
case static::KEY_COLUMN_NAME:
|
||||
$key = $tag['object']->name ?? $item['name'];
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new \InvalidArgumentException("Given `fieldKey` is unknown to the EntityResolver");
|
||||
}
|
||||
|
||||
$fieldList[$key] = $item;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $fieldList;
|
||||
}
|
||||
|
||||
public function tableName() : string
|
||||
{
|
||||
if ( null === $table = $this->getAnnotationFromClassname( Table::class ) ) {
|
||||
throw new \LogicException("Your entity {$this->entityClass} seems to be missing a @Table() annotation");
|
||||
}
|
||||
|
||||
if ( $table->name === "" ) {
|
||||
throw new \ArgumentCountError("Your entity {$this->entityClass} seems to be missing a `name` argument for your @Table() annotation");
|
||||
}
|
||||
|
||||
return $table->name;
|
||||
}
|
||||
|
||||
public function primaryKeys() : array
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform an annotation into it's object's counterpart
|
||||
*/
|
||||
public function getAnnotationFromClassname(string $className) : ? object
|
||||
{
|
||||
if ( $name = $this->uses[$className] ?? false) {
|
||||
|
||||
foreach($this->class['tags'] as $item) {
|
||||
if ( $item['tag'] === $name ) {
|
||||
return $this->instanciateAnnotationObject($item);
|
||||
}
|
||||
|
||||
foreach($this->properties as $item) {
|
||||
foreach($item['tags'] as $item) {
|
||||
if ( $item['tag'] === $name ) {
|
||||
return $this->instanciateAnnotationObject($item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach($this->methods as $item) {
|
||||
foreach($item['tags'] as $item) {
|
||||
if ( $item['tag'] === $name ) {
|
||||
return $this->instanciateAnnotationObject($item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
throw new \TypeError("Annotation `$className` could not be found within your object `{$this->entityClass}`");
|
||||
}
|
||||
else {
|
||||
throw new \InvalidArgumentException("Class `$className` was not found within {$this->entityClass} uses statement (or it's children / traits)");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function instanciateAnnotationObject(array $tagDefinition) : Annotation
|
||||
{
|
||||
$arguments = $this->extractArguments($tagDefinition['arguments']);
|
||||
|
||||
if ( false === $class = array_search($tagDefinition['tag'], $this->uses) ) {
|
||||
throw new \InvalidArgumentException("Annotation class `{$tagDefinition['tag']}` was not found within {$this->entityClass} uses statement (or it's children / traits)");
|
||||
}
|
||||
|
||||
$obj = new $class(... $arguments['constructor']);
|
||||
|
||||
foreach($arguments['setter'] as $key => $value) {
|
||||
$obj->$key = $value;
|
||||
}
|
||||
|
||||
return $obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts arguments from an Annotation definition, easing object's declaration.
|
||||
*/
|
||||
protected function extractArguments(array $arguments) : array
|
||||
{
|
||||
$list = [
|
||||
'setter' => [],
|
||||
'constructor' => [],
|
||||
];
|
||||
|
||||
ksort($arguments);
|
||||
|
||||
foreach($arguments as $key => $value) {
|
||||
$list[ is_int($key) ? 'constructor' : 'setter' ][$key] = $value;
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
protected function resolveAnnotations()
|
||||
{
|
||||
foreach($this->class['tags'] as &$tag) {
|
||||
$tag['object'] = $this->instanciateAnnotationObject($tag);
|
||||
}
|
||||
|
||||
foreach($this->properties as &$property) {
|
||||
foreach($property['tags'] as &$tag){
|
||||
$tag['object'] = $this->instanciateAnnotationObject($tag);
|
||||
}
|
||||
}
|
||||
|
||||
foreach($this->methods as &$method) {
|
||||
foreach($method['tags'] as &$tag){
|
||||
$tag['object'] = $this->instanciateAnnotationObject($tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,273 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Common;
|
||||
|
||||
use Ulmus\Ulmus;
|
||||
|
||||
use Ulmus\Annotation\AnnotationReader;
|
||||
|
||||
use Reflector, ReflectionClass, ReflectionProperty, ReflectionMethod;
|
||||
|
||||
class ObjectReflection {
|
||||
|
||||
public AnnotationReader $annotationReader;
|
||||
|
||||
public function __construct($class, AnnotationReader $annotationReader = null) {
|
||||
$this->classReflection = $class instanceof ReflectionClass ? $class : new ReflectionClass($class);
|
||||
$this->annotationReader = $annotationReader ?: AnnotationReader::fromClass($class);
|
||||
}
|
||||
|
||||
public static function fromClass($class) : self
|
||||
{
|
||||
return new static($class);
|
||||
}
|
||||
|
||||
public function read() : array
|
||||
{
|
||||
return [
|
||||
'uses' => $this->gatherUses(true),
|
||||
'class' => $this->gatherClass(true),
|
||||
'method' => $this->gatherMethods(true),
|
||||
'property' => $this->gatherProperties(true),
|
||||
];
|
||||
}
|
||||
|
||||
public function gatherUses(bool $full = true) : array
|
||||
{
|
||||
$list = [];
|
||||
|
||||
if ( $full ) {
|
||||
if ( $parentClass = $this->classReflection->getParentClass() ) {
|
||||
$list = static::fromClass($parentClass)->gatherUses(true);
|
||||
}
|
||||
|
||||
foreach($this->classReflection->getTraits() as $trait) {
|
||||
$list = array_merge($list, static::fromClass($trait)->gatherUses(true));
|
||||
}
|
||||
}
|
||||
|
||||
return array_merge($this->getUsesStatements(), $list);
|
||||
}
|
||||
|
||||
public function gatherClass(bool $full = true) : array
|
||||
{
|
||||
$class = [];
|
||||
|
||||
if ( $full ) {
|
||||
if ( $parentClass = $this->classReflection->getParentClass() ) {
|
||||
$class = static::fromClass($parentClass)->gatherClass(true);
|
||||
}
|
||||
|
||||
$itemName = function($item) {
|
||||
return $item->getName();
|
||||
};
|
||||
}
|
||||
|
||||
return [
|
||||
'tags' => array_merge($class, $this->annotationReader->getClass($this->classReflection))
|
||||
] + ( ! $full ? [] : [
|
||||
'traits' => array_map($itemName, $this->classReflection->getTraits()),
|
||||
'interfaces' => array_map($itemName, $this->classReflection->getInterfaces()),
|
||||
]);
|
||||
}
|
||||
|
||||
public function gatherProperties(bool $full = true, int $filter =
|
||||
ReflectionProperty::IS_PUBLIC |
|
||||
ReflectionProperty::IS_PROTECTED |
|
||||
ReflectionProperty::IS_PRIVATE
|
||||
) : array
|
||||
{
|
||||
$properties = [];
|
||||
$defaultValues = $this->classReflection->getDefaultProperties();
|
||||
|
||||
if ( $full ) {
|
||||
if ( $parentClass = $this->classReflection->getParentClass() ) {
|
||||
$properties = static::fromClass($parentClass)->gatherProperties($full, $filter);
|
||||
}
|
||||
}
|
||||
|
||||
$properties = array_merge($properties, $this->classReflection->getProperties($filter));
|
||||
|
||||
$list = [];
|
||||
|
||||
foreach($properties as $property) {
|
||||
$current = [
|
||||
'name' => $property->getName()
|
||||
];
|
||||
|
||||
# Default value can be 'null', so isset() it not suitable here
|
||||
if ( array_key_exists($current['name'], $defaultValues) ) {
|
||||
$current['value'] = $defaultValues[ $current['name'] ];
|
||||
}
|
||||
|
||||
if ( $property->hasType() ) {
|
||||
$current['type'] = $property->getType()->getName();
|
||||
$current['nullable'] = $property->getType()->allowsNull();
|
||||
}
|
||||
|
||||
$current['tags'] = $this->annotationReader->getProperty($property);
|
||||
|
||||
if ( $this->ignoreElementAnnotation($current['tags']) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$list[ $current['name'] ] = $current;
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
public function gatherMethods(bool $full = true, int $filter =
|
||||
ReflectionMethod::IS_PUBLIC |
|
||||
ReflectionMethod::IS_PROTECTED |
|
||||
ReflectionMethod::IS_PRIVATE |
|
||||
ReflectionMethod::IS_STATIC
|
||||
) : array
|
||||
{
|
||||
$methods = [];
|
||||
|
||||
if ( $full ) {
|
||||
if ( $parentClass = $this->classReflection->getParentClass() ) {
|
||||
$methods = static::fromClass($parentClass)->gatherMethods($full, $filter);
|
||||
}
|
||||
}
|
||||
|
||||
$methods = array_merge($methods, $this->classReflection->getMethods($filter));
|
||||
|
||||
$list = [];
|
||||
|
||||
foreach($methods as $method) {
|
||||
$parameters = [];
|
||||
|
||||
foreach($method->getParameters() as $parameter) {
|
||||
$parameters[$parameter->getName()] = [
|
||||
'null' => $parameter->allowsNull(),
|
||||
'position' => $parameter->getPosition(),
|
||||
'type' => $parameter->hasType() ? $parameter->getType()->getName() : false,
|
||||
'array' => $parameter->isArray(),
|
||||
'callable' => $parameter->isCallable(),
|
||||
'optional' => $parameter->isOptional(),
|
||||
'byReference' => $parameter->isPassedByReference(),
|
||||
];
|
||||
}
|
||||
|
||||
$current = [
|
||||
'name' => $method->getName(),
|
||||
'type' => $method->hasReturnType() ? $method->getReturnType()->getName() : false,
|
||||
'constructor' => $method->isConstructor(),
|
||||
'destructor' => $method->isDestructor(),
|
||||
'parameters' => $parameters,
|
||||
];
|
||||
|
||||
$current['tags'] = $this->annotationReader->getMethod($method);
|
||||
|
||||
if ( $this->ignoreElementAnnotation($current['tags']) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$list[ $current['name'] ] = $current;
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
protected function ignoreElementAnnotation($tags) : bool
|
||||
{
|
||||
return in_array('IGNORE', array_map('strtoupper', array_column($tags, 'tag') ));
|
||||
}
|
||||
|
||||
|
||||
protected function readCode() : string
|
||||
{
|
||||
static $code = [];
|
||||
$fileName = $this->classReflection->getFilename();
|
||||
return $code[$fileName] ?? $code[$fileName] = file_get_contents($fileName);
|
||||
}
|
||||
|
||||
protected function getUsesStatements() : array
|
||||
{
|
||||
$uses = [];
|
||||
$tokens = token_get_all( $c = $this->readCode() );
|
||||
|
||||
while ( $token = array_shift($tokens) ) {
|
||||
|
||||
if ( is_array($token) ) {
|
||||
list($token, $value) = $token;
|
||||
}
|
||||
|
||||
switch ($token) {
|
||||
case T_CLASS:
|
||||
case T_TRAIT:
|
||||
case T_INTERFACE:
|
||||
break 2;
|
||||
|
||||
case T_USE:
|
||||
$isUse = true;
|
||||
break;
|
||||
|
||||
case T_NS_SEPARATOR:
|
||||
$isNamespace = $isUse;
|
||||
break;
|
||||
|
||||
case T_STRING:
|
||||
if ( $isNamespace && $latestString ) {
|
||||
$statement[] = $latestString;
|
||||
}
|
||||
|
||||
$latestString = $value;
|
||||
break;
|
||||
|
||||
case T_AS:
|
||||
# My\Name\Space\aClassHere `as` ClassAlias;
|
||||
$replacedClass = implode("\\", array_merge($statement, [ $latestString ]));
|
||||
$latestString = null;
|
||||
break;
|
||||
|
||||
case T_WHITESPACE:
|
||||
case T_COMMENT:
|
||||
case T_DOC_COMMENT:
|
||||
break;
|
||||
|
||||
case '{':
|
||||
# opening a sub-namespace -> \My\Name\Space\`{`OneItem, AnotherItem}
|
||||
if ( $isNamespace ) {
|
||||
$inNamespace = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case ';';
|
||||
case ',':
|
||||
case '}':
|
||||
if ( $isUse ) {
|
||||
if ( $replacedClass ) {
|
||||
$uses[$replacedClass] = $latestString;
|
||||
$replacedClass = "";
|
||||
}
|
||||
elseif ( $latestString ) {
|
||||
$uses[implode("\\", array_merge($statement, [ $latestString ]))] = $latestString;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $inNamespace ) {
|
||||
$latestString = "";
|
||||
|
||||
# \My\Name\Space\{OneItem, AnotherItem`}` <- closing a sub-namespace
|
||||
if ( $token !== "}" ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
case T_OPEN_TAG:
|
||||
default:
|
||||
$statement = [];
|
||||
$latestString = "";
|
||||
$replacedClass = null;
|
||||
$isNamespace = $inNamespace = false;
|
||||
$isUse = ( $isUse ?? false ) && ( $token === ',' );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $uses;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Common;
|
||||
|
||||
use PDO, PDOStatement;
|
||||
|
||||
class PdoObject extends PDO {
|
||||
|
||||
public function select(string $sql, array $parameters = []) : PDOStatement
|
||||
{
|
||||
try {
|
||||
if ( $statement = $this->prepare($sql) ) {
|
||||
$statement = $this->execute($statement, $parameters, true);
|
||||
$statement->setFetchMode(\PDO::FETCH_ASSOC);
|
||||
return $statement;
|
||||
}
|
||||
} catch (\PDOException $e) { throw $e; }
|
||||
}
|
||||
|
||||
public function execute(PDOStatement $statement, array $parameters = [], bool $commit = true) : ? PDOStatement
|
||||
{
|
||||
try {
|
||||
if (! $this->inTransaction() ) {
|
||||
$this->beginTransaction();
|
||||
}
|
||||
|
||||
if ( empty($parameters) ? $statement->execute() : $statement->execute($parameters) ) {
|
||||
# if ( $commit ) {
|
||||
$this->commit();
|
||||
# }
|
||||
|
||||
return $statement;
|
||||
}
|
||||
else {
|
||||
throw new PDOException('Could not begin transaction or given statement is invalid.');
|
||||
}
|
||||
} catch (\PDOException $e) {
|
||||
$this->rollback();
|
||||
throw $e;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Common;
|
||||
|
||||
abstract class Sql {
|
||||
|
||||
public static function function($name, ...$arguments)
|
||||
{
|
||||
return new class($name, ...$arguments) {
|
||||
|
||||
protected string $as = "";
|
||||
|
||||
protected string $name;
|
||||
|
||||
protected array $arguments;
|
||||
|
||||
public function __construct(string $name, ...$arguments) {
|
||||
$this->name = $name;
|
||||
$this->arguments = $arguments;
|
||||
$this->parseArguments();
|
||||
}
|
||||
|
||||
public function __toString() {
|
||||
return implode(' ', array_filter([
|
||||
"{$this->name}(" . implode(", ", $this->arguments) . ")",
|
||||
$this->as ? "AS {$this->as}" : false,
|
||||
]));
|
||||
}
|
||||
|
||||
public function as($fieldName) {
|
||||
$this->as = $fieldName;
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function parseArguments() {
|
||||
foreach($this->arguments as &$item) {
|
||||
$item = Sql::escape($item);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static function escape($value)
|
||||
{
|
||||
switch(true) {
|
||||
case is_object($value):
|
||||
# @TODO Make sure the object is a Field
|
||||
return (string) $value;
|
||||
break;
|
||||
|
||||
case is_string($value):
|
||||
$value = "\"$value\"";
|
||||
break;
|
||||
|
||||
case is_null($value):
|
||||
$value = "NULL";
|
||||
break;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
public static function parameter($value) : string
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user