Merge branch 'master' of https://git.mcnd.ca/mcndave/ulmus
This commit is contained in:
commit
ab1d7e4f5b
|
@ -159,6 +159,14 @@ class SQLite implements AdapterInterface, MigrateInterface, SqlAdapterInterface
|
|||
$pdo->sqliteCreateFunction('length', fn($string) => strlen($string), 1);
|
||||
$pdo->sqliteCreateFunction('lcase', fn($string) => strtolower($string), 1);
|
||||
$pdo->sqliteCreateFunction('ucase', fn($string) => strtoupper($string), 1);
|
||||
$pdo->sqliteCreateFunction('md5', fn($string) => md5($string), 1);
|
||||
$pdo->sqliteCreateFunction('sha1', fn($string) => sha1($string), 1);
|
||||
$pdo->sqliteCreateFunction('sha256', fn($string) => hash('sha256', $string), 1);
|
||||
$pdo->sqliteCreateFunction('sha512', fn($string) => hash('sha512', $string), 1);
|
||||
$pdo->sqliteCreateFunction('whirlpool', fn($string) => hash('whirlpool', $string), 1);
|
||||
$pdo->sqliteCreateFunction('murmur3a', fn($string) => hash('murmur3a', $string), 1);
|
||||
$pdo->sqliteCreateFunction('murmur3c', fn($string) => hash('murmur3c', $string), 1);
|
||||
$pdo->sqliteCreateFunction('murmur3f', fn($string) => hash('murmur3f', $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);
|
||||
|
|
|
@ -134,7 +134,7 @@ trait SqlAdapterTrait
|
|||
case is_object($value):
|
||||
return Ulmus::convertObject($value);
|
||||
|
||||
case is_array($value):
|
||||
case is_array($value):
|
||||
return json_encode($value);
|
||||
|
||||
case is_bool($value):
|
||||
|
|
|
@ -13,7 +13,7 @@ use Ulmus\Attribute\ConstrainActionEnum;
|
|||
class ForeignKey extends PrimaryKey {
|
||||
public function __construct(
|
||||
public ? string $name = null,
|
||||
public ? string $type = 'bigint',
|
||||
public ? string $type = null,
|
||||
public null|int|string $length = null,
|
||||
public ? int $precision = null,
|
||||
public array $attributes = [
|
||||
|
|
|
@ -360,7 +360,7 @@ class EntityCollection extends \ArrayObject implements \JsonSerializable {
|
|||
|
||||
public function jsonSerialize(): mixed
|
||||
{
|
||||
return $this->toArray();
|
||||
return $this->toArray(true);
|
||||
}
|
||||
|
||||
public function append($value) : void
|
||||
|
|
|
@ -66,7 +66,7 @@ trait EntityTrait {
|
|||
$data = json_decode($value, true);
|
||||
|
||||
if (json_last_error() !== \JSON_ERROR_NONE) {
|
||||
throw new \Exception(sprintf("JSON error while decoding in EntityTrait : '%s' given %s with field %s", json_last_error_msg(), $value, json_encode($field)));
|
||||
throw new \Exception(sprintf("JSON error while decoding in EntityTrait : '%s' given %s", json_last_error_msg(), $value));
|
||||
}
|
||||
|
||||
$this->{$field['name']} = $data;
|
||||
|
@ -116,7 +116,7 @@ trait EntityTrait {
|
|||
$this->entityLoadedDataset = array_change_key_case($dataset, \CASE_LOWER);
|
||||
}
|
||||
elseif ($overwriteDataset) {
|
||||
$this->entityLoadedDataset = array_change_key_case($dataset, \CASE_LOWER) + $this->entityLoadedDataset;
|
||||
$this->entityLoadedDataset = iterator_to_array(array_change_key_case($dataset, \CASE_LOWER)) + $this->entityLoadedDataset;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -127,11 +127,9 @@ trait EntityTrait {
|
|||
public function resetVirtualProperties() : self
|
||||
{
|
||||
foreach($this->resolveEntity()->properties as $prop => $property) {
|
||||
if ( empty($property['builtin']) ) {
|
||||
foreach($property['tags'] as $tag) {
|
||||
if ( in_array(strtolower($tag['tag']), [ 'relation', 'join', 'virtual' ] ) ) {
|
||||
unset($this->$prop);
|
||||
}
|
||||
foreach($property['tags'] as $tag) {
|
||||
if ( in_array(strtolower($tag['tag']), [ 'relation', 'join', 'virtual' ] ) ) {
|
||||
unset($this->$prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -145,7 +143,7 @@ trait EntityTrait {
|
|||
return $this->entityFillFromDataset($dataset);
|
||||
}
|
||||
|
||||
public function entityGetDataset(bool $includeRelations = false, bool $returnSource = false) : array
|
||||
public function entityGetDataset(bool $includeRelations = false, bool $returnSource = false, bool $rewriteValue = true) : array
|
||||
{
|
||||
if ( $returnSource ) {
|
||||
return $this->entityLoadedDataset;
|
||||
|
@ -159,7 +157,10 @@ trait EntityTrait {
|
|||
$annotation = $entityResolver->searchFieldAnnotation($key, [ Attribute\Property\Field::class, Field::class ]);
|
||||
|
||||
if ( isset($this->$key) ) {
|
||||
$dataset[$annotation->name ?? $key] = static::repository()->adapter->adapter()->writableValue($this->$key);
|
||||
$dataset[$annotation->name ?? $key] = $rewriteValue?
|
||||
static::repository()->adapter->adapter()->writableValue($this->$key)
|
||||
:
|
||||
$this->$key;
|
||||
}
|
||||
elseif ( $field['nullable'] ) {
|
||||
$dataset[$annotation->name ?? $key] = null;
|
||||
|
@ -169,7 +170,7 @@ trait EntityTrait {
|
|||
# @TODO Must fix recursive bug !
|
||||
if ($includeRelations) {
|
||||
foreach($entityResolver->properties as $name => $field){
|
||||
$relation = $entityResolver->searchFieldAnnotation($key, [ Attribute\Property\Relation::class. Relation::class ] );
|
||||
$relation = $entityResolver->searchFieldAnnotation($name, [ Attribute\Property\Relation::class, Relation::class ] );
|
||||
|
||||
if ( $relation && isset($this->$name) && ($relation->entity ?? $relation->bridge) !== static::class ) {
|
||||
if ( null !== $value = $this->$name ?? null ) {
|
||||
|
@ -196,7 +197,7 @@ trait EntityTrait {
|
|||
#[Ignore]
|
||||
public function toArray($includeRelations = false, array $filterFields = null) : array
|
||||
{
|
||||
$dataset = $this->entityGetDataset($includeRelations);
|
||||
$dataset = $this->entityGetDataset($includeRelations, false, false);
|
||||
|
||||
return $filterFields ? array_intersect_key($dataset, array_flip($filterFields)) : $dataset;
|
||||
}
|
||||
|
@ -265,10 +266,6 @@ trait EntityTrait {
|
|||
#[Ignore]
|
||||
public function __clone()
|
||||
{
|
||||
foreach($this as $prop) {
|
||||
|
||||
}
|
||||
|
||||
if ( null !== $pkField = $this->resolveEntity()->getPrimaryKeyField($this) ) {
|
||||
$key = key($pkField);
|
||||
|
||||
|
@ -279,7 +276,7 @@ trait EntityTrait {
|
|||
#[Ignore]
|
||||
public function jsonSerialize() : mixed
|
||||
{
|
||||
return $this->entityGetDataset();
|
||||
return $this->entityGetDataset(true, false, false);
|
||||
}
|
||||
|
||||
#[Ignore]
|
||||
|
@ -310,9 +307,12 @@ trait EntityTrait {
|
|||
}
|
||||
|
||||
#[Ignore]
|
||||
public static function field($name, null|string|bool $alias = Repository::DEFAULT_ALIAS) : EntityField
|
||||
public static function field($name, null|string|false $alias = Repository::DEFAULT_ALIAS) : EntityField
|
||||
{
|
||||
return new EntityField(static::class, $name, $alias ? Ulmus::repository(static::class)->adapter->adapter()->escapeIdentifier($alias, Adapter\AdapterInterface::IDENTIFIER_FIELD) : ( $alias === false ? '' : Repository::DEFAULT_ALIAS ), Ulmus::resolveEntity(static::class));
|
||||
|
||||
$default = ( $alias === false ? '' : Repository::DEFAULT_ALIAS ); # bw compatibility, to be deprecated
|
||||
|
||||
return new EntityField(static::class, $name, $alias ? Ulmus::repository(static::class)->adapter->adapter()->escapeIdentifier($alias, Adapter\AdapterInterface::IDENTIFIER_FIELD) : $default, Ulmus::resolveEntity(static::class));
|
||||
}
|
||||
|
||||
#[Ignore]
|
||||
|
|
|
@ -16,7 +16,7 @@ class Where extends Fragment {
|
|||
const COMPARISON_IS = "IS";
|
||||
const COMPARISON_NULL = "NULL";
|
||||
|
||||
const SQL_TOKEN = "WHERE";
|
||||
const SQL_TOKEN = "WHERE";
|
||||
|
||||
public int $order = 50;
|
||||
|
||||
|
@ -35,7 +35,7 @@ class Where extends Fragment {
|
|||
$this->parent = $queryBuilder->where ?? null;
|
||||
}
|
||||
|
||||
public function add($field, $value, string $operator, string $condition, bool $not = false) : self
|
||||
public function add($field, mixed $value, string $operator, string $condition, bool $not = false) : self
|
||||
{
|
||||
$this->validateFieldType($field);
|
||||
# $this->validateValueType($value);
|
||||
|
@ -73,7 +73,7 @@ class Where extends Fragment {
|
|||
]);
|
||||
}
|
||||
|
||||
protected function whereCondition($field, $value, string $operator = self::OPERATOR_EQUAL, string $condition = self::CONDITION_AND, bool $not = false) {
|
||||
protected function whereCondition($field, mixed $value, string $operator = self::OPERATOR_EQUAL, string $condition = self::CONDITION_AND, bool $not = false) {
|
||||
return new class($this->queryBuilder, $field, $value, $operator, $condition, $not) {
|
||||
|
||||
public mixed $value;
|
||||
|
@ -123,7 +123,7 @@ class Where extends Fragment {
|
|||
$stack = [];
|
||||
|
||||
if ($this->value) {
|
||||
foreach ($this->value as $item) {
|
||||
foreach($this->value as $item) {
|
||||
$stack[] = $this->filterValue($item);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -198,9 +198,9 @@ class QueryBuilder implements Query\QueryBuilderInterface
|
|||
public function where(string|\Stringable $field, mixed $value, string $operator = Query\Where::OPERATOR_EQUAL, string $condition = Query\Where::CONDITION_AND, bool $not = false) : self
|
||||
{
|
||||
# Empty IN case
|
||||
#if ( [] === $value ) {
|
||||
# return $this;
|
||||
#}
|
||||
# if ( [] === $value ) {
|
||||
# return $this;
|
||||
# }
|
||||
|
||||
if ( $this->where ?? false ) {
|
||||
$where = $this->where;
|
||||
|
@ -259,6 +259,11 @@ class QueryBuilder implements Query\QueryBuilderInterface
|
|||
if ( null === $offset = $this->getFragment(Query\Offset::class) ) {
|
||||
$offset = new Query\Offset();
|
||||
$this->push($offset);
|
||||
|
||||
# A limit is required to match an offset
|
||||
if ( null === $limit = $this->getFragment(Query\Limit::class) ) {
|
||||
$this->limit(\PHP_INT_MAX);
|
||||
}
|
||||
}
|
||||
|
||||
$offset->set($value);
|
||||
|
|
|
@ -114,7 +114,7 @@ class Repository
|
|||
throw new Exception\EntityPrimaryKeyUnknown("A primary key value has to be defined to delete an item.");
|
||||
}
|
||||
|
||||
return (bool) $this->wherePrimaryKey($value)->deleteOne()->rowCount;
|
||||
return (bool) $this->wherePrimaryKey($value, null)->deleteOne()->rowCount;
|
||||
}
|
||||
|
||||
public function destroy(object $entity) : bool
|
||||
|
@ -599,7 +599,7 @@ class Repository
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function wherePrimaryKey(mixed $value) : self
|
||||
public function wherePrimaryKey(mixed $value, null|string|bool $alias = self::DEFAULT_ALIAS) : self
|
||||
{
|
||||
if ( null === $primaryKeyField = Ulmus::resolveEntity($this->entityClass)->getPrimaryKeyField() ) {
|
||||
throw new Exception\EntityPrimaryKeyUnknown("Entity has no field containing attributes 'primary_key'");
|
||||
|
@ -607,7 +607,7 @@ class Repository
|
|||
|
||||
$pkField = key($primaryKeyField);
|
||||
|
||||
return $this->where($this->entityClass::field($primaryKeyField[$pkField]->name ?? $pkField), $value);
|
||||
return $this->where($this->entityClass::field($primaryKeyField[$pkField]->name ?? $pkField, false), $value);
|
||||
}
|
||||
|
||||
public function withJoin(string|array $fields, array $options = []) : self
|
||||
|
|
|
@ -47,7 +47,7 @@ class RelationBuilder
|
|||
}
|
||||
}
|
||||
|
||||
public function searchRelation(string $name) : object|bool
|
||||
public function searchRelation(string $name) : mixed
|
||||
{
|
||||
# Resolve relations here if one is called
|
||||
if ( $this->entity->isLoaded() ) {
|
||||
|
@ -55,7 +55,13 @@ class RelationBuilder
|
|||
return $dataset;
|
||||
}
|
||||
|
||||
return $this->resolveRelation($name) ?: $this->resolveVirtual($name) ?: false;
|
||||
if ( false !== $value = $this->resolveRelation($name) ) {
|
||||
return $value;
|
||||
}
|
||||
elseif ( false !== $value = $this->resolveVirtual($name) ) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
if ( $relation = $this->resolver->searchFieldAnnotation($name, [ Attribute\Property\Relation::class , Relation::class ] ) ) {
|
||||
|
@ -69,7 +75,7 @@ class RelationBuilder
|
|||
return false;
|
||||
}
|
||||
|
||||
protected function resolveVirtual(string $name) : bool|object
|
||||
protected function resolveVirtual(string $name) : mixed
|
||||
{
|
||||
if (null !== ($virtual = $this->resolver->searchFieldAnnotation($name, [ Attribute\Property\Virtual::class, Annotation\Property\Virtual::class ]))) {
|
||||
if ($virtual->closure ?? false) {
|
||||
|
@ -82,7 +88,7 @@ class RelationBuilder
|
|||
return false;
|
||||
}
|
||||
|
||||
protected function resolveRelation(string $name) : bool|object
|
||||
protected function resolveRelation(string $name) : mixed
|
||||
{
|
||||
if ( null !== ( $relation = $this->resolver->searchFieldAnnotation($name, [ Attribute\Property\Relation::class, Relation::class ] ) ) ) {
|
||||
$this->orders = $this->resolver->searchFieldAnnotationList($name, [ Attribute\Property\OrderBy::class, OrderBy::class ] );
|
||||
|
@ -109,14 +115,14 @@ class RelationBuilder
|
|||
|
||||
$this->entity->eventExecute(Event\EntityRelationLoadInterface::class, $name, $this->repository);
|
||||
|
||||
return call_user_func([ $this->repository, $relation->function() ]);
|
||||
return call_user_func([ $this->repository, $relation->function() ]);
|
||||
|
||||
case $relation->isManyToMany():
|
||||
$this->manyToMany($name, $relation, $relationRelation);
|
||||
|
||||
$this->entity->eventExecute(Event\EntityRelationLoadInterface::class, $name, $this->repository);
|
||||
|
||||
$results = call_user_func([ $this->repository, 'loadAll' ]);
|
||||
$results = call_user_func([ $this->repository, $relationRelation->function() ]);
|
||||
|
||||
if ($relation->bridgeField ?? false) {
|
||||
$collection = $relation->bridge::entityCollection();
|
||||
|
|
Loading…
Reference in New Issue