- Completed merge

This commit is contained in:
Dave M. 2022-07-15 19:59:38 +00:00
parent 430cd03bc4
commit 00ebf3381f
10 changed files with 93 additions and 34 deletions

View File

@ -7,7 +7,7 @@ use Ulmus\Common\PdoObject;
use Ulmus\Entity\Sqlite\Table; use Ulmus\Entity\Sqlite\Table;
use Ulmus\Exception\AdapterConfigurationException; use Ulmus\Exception\AdapterConfigurationException;
use Ulmus\Migration\FieldDefinition; use Ulmus\Migration\FieldDefinition;
use Ulmus\{ Repository, QueryBuilder }; use Ulmus\{Repository, QueryBuilder, Ulmus};
class SQLite implements AdapterInterface { class SQLite implements AdapterInterface {
use DefaultAdapterTrait; use DefaultAdapterTrait;
@ -38,6 +38,8 @@ class SQLite implements AdapterInterface {
$pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); $pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(\PDO::ATTR_EMULATE_PREPARES, false); $pdo->setAttribute(\PDO::ATTR_EMULATE_PREPARES, false);
$pdo->setAttribute(\PDO::ATTR_DEFAULT_FETCH_MODE, \PDO::FETCH_ASSOC); $pdo->setAttribute(\PDO::ATTR_DEFAULT_FETCH_MODE, \PDO::FETCH_ASSOC);
$this->exportFunctions($pdo);
} }
catch(PDOException $ex){ catch(PDOException $ex){
throw $ex; throw $ex;
@ -126,7 +128,23 @@ class SQLite implements AdapterInterface {
} }
} }
return $typeOnly ? $type : $type . ( $length ? "($length" . ( $precision ? ",$precision" : "" ) . ")" : "" ); return $typeOnly ? $type : $type . ( $length ? "($length" . ( isset($precision) ? ",$precision" : "" ) . ")" : "" );
}
public function writableValue(/* mixed */ $value) /*: mixed*/
{
switch (true) {
case is_object($value):
return Ulmus::convertObject($value);
case is_array($value):
return json_encode($value);
case is_bool($value):
return (int) $value;
}
return $value;
} }
public function tableSyntax() : array public function tableSyntax() : array
@ -147,4 +165,28 @@ class SQLite implements AdapterInterface {
{ {
return QueryBuilder\SqliteQueryBuilder::class; return QueryBuilder\SqliteQueryBuilder::class;
} }
public function exportFunctions(PdoObject $pdo) : void
{
$pdo->sqliteCreateFunction('lcase', fn($string) => strtolower($string), 1);
$pdo->sqliteCreateFunction('ucase', fn($string) => strtoupper($string), 1);
$pdo->sqliteCreateFunction('left', fn($string, $length) => substr($string, 0, $length), 2);
$pdo->sqliteCreateFunction('right', fn($string, $length) => substr($string, -$length), 2);
$pdo->sqliteCreateFunction('strcmp', fn($s1, $s2) => strcmp($s1, $s2), 2);
$pdo->sqliteCreateFunction('lpad', fn($string, $length, $pad) => str_pad($string, $length, $pad, STR_PAD_LEFT), 3);
$pdo->sqliteCreateFunction('rpad', fn($string, $length, $pad) => str_pad($string, $length, $pad, STR_PAD_RIGHT), 3);
$pdo->sqliteCreateFunction('concat', fn(...$args) => implode('', $args), -1);
$pdo->sqliteCreateFunction('concat_ws', fn($separator, ...$args) => implode($separator, $args), -1);
$pdo->sqliteCreateFunction('find_in_set', function($string, $string_list) {
if ( $string === null || $string_list === null ) {
return null;
}
if ($string_list === "") {
return 0;
}
return (int) in_array($string, explode(',', $string_list));
}, 2);
}
} }

View File

@ -16,6 +16,8 @@ class Field implements \Ulmus\Annotation\Annotation {
public bool $nullable; public bool $nullable;
public /* mixed */ $default;
public bool $readonly = false; public bool $readonly = false;
public function __construct(? string $type = null, ? int $length = null) public function __construct(? string $type = null, ? int $length = null)

View File

@ -69,6 +69,18 @@ class Relation implements \Ulmus\Annotation\Annotation {
return $this->normalizeType() === 'manytomany'; return $this->normalizeType() === 'manytomany';
} }
public function function() : string
{
if ($this->function) {
return $this->function;
}
elseif ($this->isOneToOne()) {
return 'load';
}
return 'loadAll';
}
public function hasBridge() : bool public function hasBridge() : bool
{ {
return isset($this->bridge); return isset($this->bridge);

View File

@ -15,11 +15,11 @@ class EntityField implements WhereRawParameter
public string $entityClass; public string $entityClass;
public string $alias; public ? string $alias;
protected EntityResolver $entityResolver; protected EntityResolver $entityResolver;
public function __construct(string $entityClass, string $name, string $alias, EntityResolver $resolver) public function __construct(string $entityClass, string $name, ? string $alias, EntityResolver $resolver)
{ {
$this->entityClass = $entityClass; $this->entityClass = $entityClass;
$this->name = $name; $this->name = $name;

View File

@ -6,7 +6,7 @@ use Ulmus\Ulmus;
use Ulmus\Annotation\AnnotationReader; use Ulmus\Annotation\AnnotationReader;
use Reflector, ReflectionClass, ReflectionProperty, ReflectionMethod; use Reflector, ReflectionClass, ReflectionProperty, ReflectionMethod, ReflectionUnionType, ReflectionNamedType, ReflectionParameter;
class ObjectReflection { class ObjectReflection {
@ -139,8 +139,8 @@ class ObjectReflection {
'null' => $parameter->allowsNull(), 'null' => $parameter->allowsNull(),
'position' => $parameter->getPosition(), 'position' => $parameter->getPosition(),
'type' => $parameter->hasType() ? $parameter->getType()->getName() : false, 'type' => $parameter->hasType() ? $parameter->getType()->getName() : false,
'array' => $parameter->isArray(), 'array' => \Notes\ObjectReflection::isType('array', $parameter),
'callable' => $parameter->isCallable(), 'callable' => \Notes\ObjectReflection::isType('callable', $parameter),
'optional' => $parameter->isOptional(), 'optional' => $parameter->isOptional(),
'byReference' => $parameter->isPassedByReference(), 'byReference' => $parameter->isPassedByReference(),
]; ];
@ -205,6 +205,7 @@ class ObjectReflection {
break; break;
case T_STRING: case T_STRING:
case T_NAME_QUALIFIED:
if ( $isNamespace && $latestString ) { if ( $isNamespace && $latestString ) {
$statement[] = $latestString; $statement[] = $latestString;
} }

View File

@ -70,7 +70,6 @@ class EntityCollection extends \ArrayObject {
public function removeOne($value, string $field, bool $strict = true) : ? object public function removeOne($value, string $field, bool $strict = true) : ? object
{ {
foreach($this->search($value, $field, $strict) as $key => $item) { foreach($this->search($value, $field, $strict) as $key => $item) {
$this->offsetUnset($key); $this->offsetUnset($key);
return $item; return $item;
@ -79,7 +78,7 @@ class EntityCollection extends \ArrayObject {
return null; return null;
} }
public function remove(/* mixed */ $values, string $field, bool $strict = true) : array public function remove(/* mixed */ $value, string $field, bool $strict = true) : array
{ {
$removed = []; $removed = [];
@ -161,7 +160,7 @@ class EntityCollection extends \ArrayObject {
$list = []; $list = [];
foreach($this as $item) { foreach($this as $item) {
if ( is_callable($field) ) { if ( ! is_string($field) && is_callable($field) ) {
$value = call_user_func_array($field, [ $item ]); $value = call_user_func_array($field, [ $item ]);
} }
else { else {
@ -173,7 +172,7 @@ class EntityCollection extends \ArrayObject {
} }
if ( $keyField !== null ) { if ( $keyField !== null ) {
if ( is_callable($keyField) ) { if ( ! is_string($field) && is_callable($keyField) ) {
$key = call_user_func_array($keyField, [ $item ]); $key = call_user_func_array($keyField, [ $item ]);
} }
else { else {

View File

@ -9,7 +9,7 @@ use Ulmus\Repository,
use Ulmus\Annotation\Classes\{ Method, Table, Collation, }; use Ulmus\Annotation\Classes\{ Method, Table, Collation, };
use Ulmus\Annotation\Property\{ Field, Filter, FilterJoin, Relation, OrderBy, Where, OrWhere, Join, Virtual, On, WithJoin, }; use Ulmus\Annotation\Property\{ Field, Filter, FilterJoin, Relation, OrderBy, Where, OrWhere, Join, Virtual, On, WithJoin, };
use Ulmus\Annotation\Property\Field\{ Id, ForeignKey, CreatedAt, UpdatedAt, Datetime as DateTime, Date, Time, Bigint, Tinyint, Text, Mediumtext, Longtext, }; use Ulmus\Annotation\Property\Field\{ Id, ForeignKey, CreatedAt, UpdatedAt, Datetime as DateTime, Date, Time, Bigint, Tinyint, Text, Mediumtext, Longtext, Blob, Mediumblob, Longblob };
use Ulmus\Annotation\Property\Relation\{ Ignore as RelationIgnore }; use Ulmus\Annotation\Property\Relation\{ Ignore as RelationIgnore };
trait EntityTrait { trait EntityTrait {
@ -317,7 +317,7 @@ trait EntityTrait {
/** /**
* @Ignore * @Ignore
*/ */
public static function field($name, ? string $alias = null) : EntityField public static function field($name, ? string $alias = Repository::DEFAULT_ALIAS) : EntityField
{ {
return new EntityField(static::class, $name, $alias ? Ulmus::repository(static::class)->adapter->adapter()->escapeIdentifier($alias, Adapter\AdapterInterface::IDENTIFIER_FIELD) : Repository::DEFAULT_ALIAS, Ulmus::resolveEntity(static::class)); return new EntityField(static::class, $name, $alias ? Ulmus::repository(static::class)->adapter->adapter()->escapeIdentifier($alias, Adapter\AdapterInterface::IDENTIFIER_FIELD) : Repository::DEFAULT_ALIAS, Ulmus::resolveEntity(static::class));
} }
@ -325,7 +325,7 @@ trait EntityTrait {
/** /**
* @Ignore * @Ignore
*/ */
public static function fields(array $fields, ? string $alias = null) : string public static function fields(array $fields, ? string $alias = Repository::DEFAULT_ALIAS) : string
{ {
return implode(', ', array_map(function($item) use ($alias){ return implode(', ', array_map(function($item) use ($alias){
return static::field($item, $alias); return static::field($item, $alias);

View File

@ -463,7 +463,7 @@ class QueryBuilder implements Query\QueryBuilderInterface
public function getFragments(/*? Query\Fragment|array*/ $fragment = null) : array public function getFragments(/*? Query\Fragment|array*/ $fragment = null) : array
{ {
return $fragment === null ? array_filter($this->queryStack, fn($e) => get_class($e) === $fragment) : $this->queryStack; return $fragment !== null ? array_filter($this->queryStack, fn($e) => is_a($e, $fragment, true) ) : $this->queryStack;
} }
public function __toString() : string public function __toString() : string

View File

@ -692,8 +692,6 @@ class Repository
{ {
foreach ((array)$fields as $name) { foreach ((array)$fields as $name) {
if (null !== ($relation = $this->entityResolver->searchFieldAnnotation($name, new Annotation\Property\Relation()))) { if (null !== ($relation = $this->entityResolver->searchFieldAnnotation($name, new Annotation\Property\Relation()))) {
$relationType = strtolower(str_replace(['-', '_', ' '], '', $relation->type));
$order = $this->entityResolver->searchFieldAnnotationList($name, new Annotation\Property\OrderBy()); $order = $this->entityResolver->searchFieldAnnotationList($name, new Annotation\Property\OrderBy());
$where = $this->entityResolver->searchFieldAnnotationList($name, new Annotation\Property\Where()); $where = $this->entityResolver->searchFieldAnnotationList($name, new Annotation\Property\Where());
@ -705,6 +703,12 @@ class Repository
$repository = $baseEntity::repository(); $repository = $baseEntity::repository();
foreach ($baseEntityResolver->fieldList(Common\EntityResolver::KEY_COLUMN_NAME, true) as $key => $field) {
if (null === $baseEntityResolver->searchFieldAnnotation($field['name'], new RelationIgnore)) {
$repository->select($baseEntityResolver->entityClass::field($key));
}
}
foreach ($where as $condition) { foreach ($where as $condition) {
$repository->where($condition->field, is_callable($condition->value) ? call_user_func_array($condition->value, [$this]) : $condition->value, $condition->operator, $condition->condition); $repository->where($condition->field, is_callable($condition->value) ? call_user_func_array($condition->value, [$this]) : $condition->value, $condition->operator, $condition->condition);
} }
@ -725,22 +729,16 @@ class Repository
$repository->where($key, $values); $repository->where($key, $values);
switch ($relationType) { $results = call_user_func([ $repository, $relation->function() ]);
case 'onetoone':
$results = call_user_func([$repository, "loadOne"]);
$item->$name = $results ?: new $baseEntity();
break; if ($relation->isOneToOne()) {
$item->$name = $results ?: new $baseEntity();
case 'onetomany': }
$results = call_user_func([$repository, $relation->function]); elseif ($relation->isOneToMany()) {
foreach ($collection as $item) {
foreach ($collection as $item) { $item->$name = $baseEntity::entityCollection();
$item->$name = $baseEntity::entityCollection(); $item->$name->mergeWith($results->filtersCollection(fn($e) => $e->$property === $item->$entityProperty));
$item->$name->mergeWith($results->filtersCollection(fn($e) => $e->$property === $item->$entityProperty)); }
}
break;
} }
} }
} }

View File

@ -47,8 +47,13 @@ class RelationBuilder
return $this->resolveRelation($name) ?: $this->resolveVirtual($name); return $this->resolveRelation($name) ?: $this->resolveVirtual($name);
} }
elseif ( $relation = $this->resolver->searchFieldAnnotation($name, new Relation() ) ) { else {
return $this->instanciateEmptyObject($name, $relation); if ( $relation = $this->resolver->searchFieldAnnotation($name, new Relation() ) ) {
return $this->instanciateEmptyObject($name, $relation);
}
elseif ($virtual = $this->resolveVirtual($name)) {
return $virtual;
}
} }
return false; return false;