- Merged getValue override
This commit is contained in:
parent
b0b3aca6d9
commit
fd5d31fa17
10
src/Attribute/Obj/JsonSerialize.php
Normal file
10
src/Attribute/Obj/JsonSerialize.php
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Attribute\Obj;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_CLASS)]
|
||||
class JsonSerialize {
|
||||
public function __construct(
|
||||
public bool $includeRelations = true,
|
||||
) {}
|
||||
}
|
||||
10
src/Attribute/Property/JsonSerialize.php
Normal file
10
src/Attribute/Property/JsonSerialize.php
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Attribute\Property;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||
class JsonSerialize {
|
||||
public function __construct(
|
||||
public bool $ignoreField = false,
|
||||
) {}
|
||||
}
|
||||
@ -5,6 +5,6 @@ namespace Ulmus\Attribute\Property;
|
||||
#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::IS_REPEATABLE)]
|
||||
class WithJoin {
|
||||
public function __construct(
|
||||
public array $joins = []
|
||||
public string|array $joins = []
|
||||
) {}
|
||||
}
|
||||
|
||||
@ -43,6 +43,7 @@ class EntityField implements WhereRawParameter
|
||||
case 'string':
|
||||
case 'float':
|
||||
case 'double':
|
||||
case 'mixed':
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@ namespace Ulmus\Entity\Field;
|
||||
|
||||
use Ulmus\Entity\EntityObjectInterface;
|
||||
|
||||
class Datetime extends \DateTime implements EntityObjectInterface {
|
||||
class Datetime extends \DateTime implements EntityObjectInterface, \JsonSerializable {
|
||||
|
||||
public string $format = "Y-m-d H:i:s";
|
||||
|
||||
@ -52,7 +52,7 @@ class Datetime extends \DateTime implements EntityObjectInterface {
|
||||
|
||||
public function formatLocaleIntl(int $dateFormatter = \IntlDateFormatter::LONG, int $timeFormatter = \IntlDateFormatter::NONE) : string
|
||||
{
|
||||
$formatter = new \IntlDateFormatter(\Locale::getDefault(), $dateFormatter, $timeFormatter);
|
||||
$formatter = new \IntlDateFormatter(\Locale::getDefault(), $dateFormatter, $timeFormatter, \Locale::getRegion(""));
|
||||
|
||||
return $formatter->format($this->getTimestamp());
|
||||
}
|
||||
@ -62,4 +62,8 @@ class Datetime extends \DateTime implements EntityObjectInterface {
|
||||
return (int) ( (int) ($dateTime ?: new DateTime())->format('Ymd') - (int) $this->format('Ymd') ) / 10000;
|
||||
}
|
||||
|
||||
public function jsonSerialize(): mixed
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,7 +4,8 @@ namespace Ulmus;
|
||||
|
||||
use Notes\Attribute\Ignore;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Ulmus\{Attribute\Property\Join,
|
||||
use Ulmus\{Attribute\Obj\JsonSerialize,
|
||||
Attribute\Property\Join,
|
||||
Attribute\Property\Relation,
|
||||
Attribute\Property\ResettablePropertyInterface,
|
||||
Attribute\Property\Virtual,
|
||||
@ -19,6 +20,7 @@ use Ulmus\SearchRequest\{Attribute\SearchParameter,
|
||||
SearchRequestFromRequestTrait,
|
||||
SearchRequestPaginationTrait};
|
||||
|
||||
#[JsonSerialize(includeRelations: true)]
|
||||
trait EntityTrait {
|
||||
use EventTrait;
|
||||
|
||||
@ -86,21 +88,25 @@ trait EntityTrait {
|
||||
return $this->entityLoadedDataset;
|
||||
}
|
||||
|
||||
$dataset = [];
|
||||
return iterator_to_array($this->entityYieldDataset($includeRelations, $rewriteValue));
|
||||
}
|
||||
|
||||
|
||||
#[Ignore]
|
||||
protected function entityYieldDataset(bool $includeRelations = false, bool $rewriteValue = true) : \Generator
|
||||
{
|
||||
foreach($this->datasetHandler->pull($this) as $field => $value) {
|
||||
$dataset[$field] = $rewriteValue ? static::repository()->adapter->adapter()->writableValue($value) : $value;
|
||||
yield $field => $rewriteValue ? static::repository()->adapter->adapter()->writableValue($value) : $value;
|
||||
}
|
||||
|
||||
if ($includeRelations) {
|
||||
foreach($this->datasetHandler->pullRelation($this) as $field => $object) {
|
||||
$dataset[$field] = $object;
|
||||
yield $field => $object;
|
||||
}
|
||||
}
|
||||
|
||||
return $dataset;
|
||||
}
|
||||
|
||||
|
||||
#[Ignore]
|
||||
public function resetVirtualProperties() : self
|
||||
{
|
||||
@ -219,7 +225,40 @@ trait EntityTrait {
|
||||
#[Ignore]
|
||||
public function jsonSerialize() : mixed
|
||||
{
|
||||
return $this->entityGetDataset(true, false, false);
|
||||
# Allows overridding of this method
|
||||
return $this->_jsonSerialize();
|
||||
}
|
||||
|
||||
#[Ignore]
|
||||
public function _jsonSerialize() : mixed
|
||||
{
|
||||
$resolver = static::resolveEntity();
|
||||
$objectAttribute = $resolver->getAttributeImplementing(JsonSerialize::class);
|
||||
|
||||
$dataset = [];
|
||||
|
||||
foreach($this->entityYieldDataset($objectAttribute->includeRelations ?? true, false, false) as $key => $value) {
|
||||
$field = $resolver->searchField($key, EntityResolver::KEY_COLUMN_NAME);
|
||||
|
||||
if ($field) {
|
||||
$jsonSerialize = $field->getAttribute(\Ulmus\Attribute\Property\JsonSerialize::class);
|
||||
if ($jsonSerialize) {
|
||||
# Should we ignore the field ?
|
||||
if ($jsonSerialize->object->ignoreField) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (is_object($value) && ($value instanceof JsonSerializable) ) {
|
||||
$dataset[$key] = $value->jsonSerialize();
|
||||
}
|
||||
else {
|
||||
$dataset[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $dataset;
|
||||
}
|
||||
|
||||
#[Ignore]
|
||||
|
||||
@ -34,7 +34,7 @@ abstract class Fragment implements QueryFragmentInterface{
|
||||
return implode(", ", $list);
|
||||
}
|
||||
|
||||
protected function validateFieldType($field) : void
|
||||
protected function validateFieldType(mixed $field) : void
|
||||
{
|
||||
if ( is_numeric($field) ) {
|
||||
throw new \Ulmus\Exception\InvalidFieldType(sprintf("Validation of field `%s` failed from query `%s`", $field, get_class($this)));
|
||||
|
||||
@ -10,6 +10,8 @@ class OrderBy extends Fragment {
|
||||
const SQL_TOKEN = "ORDER BY";
|
||||
const SQL_COLLATE = "COLLATE";
|
||||
|
||||
# const 'NULLS LAST|FIRST' must be handlded
|
||||
|
||||
public function set(array $order) : self
|
||||
{
|
||||
$this->orderBy = $order;
|
||||
@ -17,9 +19,9 @@ class OrderBy extends Fragment {
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function add(string|\Stringable $field, ? string $direction = null) : self
|
||||
public function add(string|\Stringable $field, string|\Stringable|null $direction = null) : self
|
||||
{
|
||||
$this->validateFieldType($field);
|
||||
$this->validateDirectionType($direction);
|
||||
|
||||
$this->orderBy[] = [ $field, $direction ];
|
||||
|
||||
@ -39,4 +41,10 @@ class OrderBy extends Fragment {
|
||||
]);
|
||||
}
|
||||
|
||||
protected function validateDirectionType(mixed $direction) {
|
||||
# Could be coming from user-input, we must whitelist
|
||||
if (is_string($direction) && ! in_array(strtoupper($direction), [ 'ASC', 'DESC' ])) {
|
||||
throw new \Ulmus\Exception\InvalidFieldType(sprintf("Validation of string `%s` failed from query `%s`", $direction, get_class($this)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,7 +6,6 @@ use Ulmus\Attribute\Property\{
|
||||
Field, OrderBy, Where, Having, Relation, Filter, Join, FilterJoin, WithJoin
|
||||
};
|
||||
use Psr\SimpleCache\CacheInterface;
|
||||
use Ulmus\Adapter\AdapterInterface;
|
||||
use Ulmus\Common\EntityResolver;
|
||||
use Ulmus\Entity\EntityInterface;
|
||||
use Ulmus\Repository\RepositoryInterface;
|
||||
@ -26,7 +25,7 @@ class Repository implements RepositoryInterface
|
||||
|
||||
public ? ConnectionAdapter $adapters;
|
||||
|
||||
public QueryBuilder\QueryBuilderInterface $queryBuilder;
|
||||
public readonly QueryBuilder\QueryBuilderInterface $queryBuilder;
|
||||
|
||||
protected EntityResolver $entityResolver;
|
||||
|
||||
@ -37,11 +36,6 @@ class Repository implements RepositoryInterface
|
||||
$this->alias = $alias;
|
||||
$this->entityResolver = Ulmus::resolveEntity($entity);
|
||||
|
||||
$this->setAdapter($adapter);
|
||||
}
|
||||
|
||||
public function setAdapter(? ConnectionAdapter $adapter = null) : void {
|
||||
|
||||
if ($adapter) {
|
||||
$this->adapter = $adapter;
|
||||
|
||||
@ -132,6 +126,8 @@ class Repository implements RepositoryInterface
|
||||
|
||||
public function deleteAll()
|
||||
{
|
||||
$this->eventExecute(Event\Query\Delete::class, $this);
|
||||
|
||||
return $this->deleteSqlQuery()->runDeleteQuery();
|
||||
}
|
||||
|
||||
@ -144,6 +140,15 @@ class Repository implements RepositoryInterface
|
||||
return (bool) $this->wherePrimaryKey($value, false)->deleteOne()->rowCount;
|
||||
}
|
||||
|
||||
public function deleteFromCompoundKeys(array $values) : bool
|
||||
{
|
||||
foreach($values as $field => $value) {
|
||||
$this->where($field, $value);
|
||||
}
|
||||
|
||||
return (bool) $this->deleteOne()->rowCount;
|
||||
}
|
||||
|
||||
public function destroy(object $entity) : bool
|
||||
{
|
||||
if ( ! $this->matchEntity($entity) ) {
|
||||
@ -152,16 +157,25 @@ class Repository implements RepositoryInterface
|
||||
|
||||
$primaryKeyDefinition = Ulmus::resolveEntity($this->entityClass)->getPrimaryKeyField();
|
||||
|
||||
if ( $primaryKeyDefinition === null ) {
|
||||
throw new \Exception(sprintf("No primary key found for entity %s", $this->entityClass));
|
||||
}
|
||||
else {
|
||||
if ( $primaryKeyDefinition !== null ) {
|
||||
$pkField = key($primaryKeyDefinition);
|
||||
|
||||
$this->eventExecute(Event\Query\Delete::class, $this, $entity);
|
||||
|
||||
return $this->deleteFromPk($entity->$pkField);
|
||||
}
|
||||
else {
|
||||
$compoundKeyFields = Ulmus::resolveEntity($this->entityClass)->getCompoundKeyFields();
|
||||
|
||||
if ($compoundKeyFields) {
|
||||
$this->eventExecute(Event\Query\Delete::class, $this, $entity);
|
||||
|
||||
return $this->deleteFromCompoundKeys(array_combine($compoundKeyFields->column, array_map(fn($column) => $entity->$column, $compoundKeyFields->column)));
|
||||
}
|
||||
else {
|
||||
throw new \Exception(sprintf("No primary key found for entity %s", $this->entityClass));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function destroyAll(EntityCollection $collection) : void
|
||||
@ -224,20 +238,24 @@ class Repository implements RepositoryInterface
|
||||
}
|
||||
else {
|
||||
if ( $primaryKeyDefinition === null ) {
|
||||
if ( null !== $compoundKeyFields = Ulmus::resolveEntity($this->entityClass)->getCompoundKeyFields() ) {
|
||||
throw new \Exception("TO DO!");
|
||||
}
|
||||
else {
|
||||
throw new \Exception(sprintf("No primary key found for entity %s", $this->entityClass));
|
||||
if ( null === $compoundKeyFields = Ulmus::resolveEntity($this->entityClass)->getCompoundKeyFields() ) {
|
||||
throw new \Exception(sprintf("No primary key or compound key found for entity %s", $this->entityClass));
|
||||
}
|
||||
}
|
||||
|
||||
$diff = $fieldsAndValue ?? $this->generateWritableDataset($entity);
|
||||
|
||||
if ( [] !== $diff ) {
|
||||
$pkField = key($primaryKeyDefinition);
|
||||
$pkFieldName = $primaryKeyDefinition[$pkField]->name ?? $pkField;
|
||||
$this->where($pkFieldName, $dataset[$pkFieldName]);
|
||||
if ($primaryKeyDefinition) {
|
||||
$pkField = key($primaryKeyDefinition);
|
||||
$pkFieldName = $primaryKeyDefinition[$pkField]->name ?? $pkField;
|
||||
$this->where($pkFieldName, $dataset[$pkFieldName]);
|
||||
}
|
||||
else {
|
||||
foreach($compoundKeyFields->column as $field) {
|
||||
$this->where($field, $dataset[$field]);
|
||||
}
|
||||
}
|
||||
|
||||
$update = $this->updateSqlQuery($diff)->runUpdateQuery();
|
||||
|
||||
@ -336,6 +354,14 @@ class Repository implements RepositoryInterface
|
||||
return $e1 !== $e2;
|
||||
}
|
||||
|
||||
if ($e1 instanceof \BackedEnum) {
|
||||
$e1 = $e1->value;
|
||||
}
|
||||
|
||||
if ($e2 instanceof \BackedEnum) {
|
||||
$e2 = $e2->value;
|
||||
}
|
||||
|
||||
return (string) $e1 !== (string) $e2;
|
||||
});
|
||||
}
|
||||
@ -424,8 +450,7 @@ class Repository implements RepositoryInterface
|
||||
|
||||
public function withJoin(string|array $fields, array $options = []) : self
|
||||
{
|
||||
$selectObj = $this->queryBuilder->getFragment(Query\Select::class);
|
||||
$canSelect = empty($selectObj) || $selectObj->isInternalSelect === true;
|
||||
$canSelect = null === $this->queryBuilder->getFragment(Query\Select::class);
|
||||
|
||||
if ( $canSelect ) {
|
||||
$select = $this->entityResolver->fieldList(EntityResolver::KEY_COLUMN_NAME, true);
|
||||
@ -433,8 +458,13 @@ class Repository implements RepositoryInterface
|
||||
}
|
||||
|
||||
# @TODO Apply FILTER annotation to this too !
|
||||
foreach(array_filter((array) $fields, fn($e) => $e && ! isset($this->joined[$e]) ) as $item) {
|
||||
$this->joined[$item] = true;
|
||||
foreach(array_filter((array) $fields) as $item) {
|
||||
if ( isset($this->joined[$item]) ) {
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
$this->joined[$item] = true;
|
||||
}
|
||||
|
||||
$attribute = $this->entityResolver->searchFieldAnnotation($item, [ Join::class ]) ?:
|
||||
$this->entityResolver->searchFieldAnnotation($item, [ Relation::class ]);
|
||||
@ -446,19 +476,19 @@ class Repository implements RepositoryInterface
|
||||
}
|
||||
|
||||
if ( $attribute ) {
|
||||
$attribute->alias ??= $item;
|
||||
$alias = $attribute->alias ?? $item;
|
||||
|
||||
$attribute->entity ??= $this->entityResolver->getPropertyEntityType($item);
|
||||
$entity = $attribute->entity ?? $this->entityResolver->reflectedClass->getProperties(true)[$item]->getTypes()[0]->type;
|
||||
|
||||
foreach($attribute->entity::resolveEntity()->fieldList(Common\EntityResolver::KEY_COLUMN_NAME, true) as $key => $field) {
|
||||
if ( null === $attribute->entity::resolveEntity()->searchFieldAnnotation($field->name, [ Relation\Ignore::class ]) ) {
|
||||
$escAlias = $this->escapeIdentifier($attribute->alias);
|
||||
foreach($entity::resolveEntity()->fieldList(Common\EntityResolver::KEY_COLUMN_NAME, true) as $key => $field) {
|
||||
if ( null === $entity::resolveEntity()->searchFieldAnnotation($field->name, [ Relation\Ignore::class ]) ) {
|
||||
$escAlias = $this->escapeIdentifier($alias);
|
||||
$fieldName = $this->escapeIdentifier($key);
|
||||
|
||||
$name = $attribute->entity::resolveEntity()->searchFieldAnnotation($field->name, [ Field::class ])->name ?? $field->name;
|
||||
$name = $entity::resolveEntity()->searchFieldAnnotation($field->name, [ Field::class ])->name ?? $field->name;
|
||||
|
||||
if ($canSelect) {
|
||||
$this->select("$escAlias.$fieldName as {$attribute->alias}\${$name}");
|
||||
$this->select("$escAlias.$fieldName as $alias\${$name}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -467,15 +497,15 @@ class Repository implements RepositoryInterface
|
||||
|
||||
if ( ! in_array(WithOptionEnum::SkipWhere, $options)) {
|
||||
foreach($this->entityResolver->searchFieldAnnotationList($item, [ Where::class ] ) as $condition) {
|
||||
if ( is_object($condition->field) && ( $condition->field->entityClass !== $attribute->entity ) ) {
|
||||
$this->where(is_object($condition->field) ? $condition->field : $attribute->entity::field($condition->field), $condition->getValue(), $condition->operator);
|
||||
if ( is_object($condition->field) && ( $condition->field->entityClass !== $entity ) ) {
|
||||
$this->where(is_object($condition->field) ? $condition->field : $entity::field($condition->field), $condition->getValue(), $condition->operator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! in_array(WithOptionEnum::SkipHaving, $options)) {
|
||||
foreach ($this->entityResolver->searchFieldAnnotationList($item, [ Having::class ]) as $condition) {
|
||||
$this->having(is_object($condition->field) ? $condition->field : $attribute->entity::field($condition->field), $condition->getValue(), $condition->operator);
|
||||
$this->having(is_object($condition->field) ? $condition->field : $entity::field($condition->field), $condition->getValue(), $condition->operator);
|
||||
}
|
||||
}
|
||||
|
||||
@ -488,9 +518,10 @@ class Repository implements RepositoryInterface
|
||||
$this->close();
|
||||
|
||||
$key = is_string($attribute->key) ? $this->entityClass::field($attribute->key) : $attribute->key;
|
||||
$foreignKey = $this->evalClosure($attribute->foreignKey, $attribute->entity, $attribute->alias);
|
||||
|
||||
$this->join($isRelation ? "LEFT" : $attribute->type, $attribute->entity::resolveEntity()->tableName(), $key, $attribute->foreignKey($this), $attribute->alias, function($join) use ($item, $attribute, $options) {
|
||||
$foreignKey = is_string($attribute->foreignKey) ? $entity::field($attribute->foreignKey, $alias) : $attribute->foreignKey;
|
||||
|
||||
$this->join("LEFT", $entity::resolveEntity()->tableName(), $key, $foreignKey, $alias, function($join) use ($item, $entity, $alias, $options) {
|
||||
if ( ! in_array(WithOptionEnum::SkipJoinWhere, $options)) {
|
||||
foreach($this->entityResolver->searchFieldAnnotationList($item, [ Where::class ]) as $condition) {
|
||||
if ( ! is_object($condition->field) ) {
|
||||
@ -501,10 +532,10 @@ class Repository implements RepositoryInterface
|
||||
}
|
||||
|
||||
# Adding directly
|
||||
if ( $field->entityClass === $attribute->entity ) {
|
||||
$field->alias = $attribute->alias;
|
||||
if ( $field->entityClass === $entity ) {
|
||||
$field->alias = $alias;
|
||||
|
||||
$join->where(is_object($field) ? $field : $attribute->entity::field($field, $attribute->alias), $condition->getValue(), $condition->operator);
|
||||
$join->where(is_object($field) ? $field : $entity::field($field, $alias), $condition->getValue(), $condition->operator);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -521,12 +552,6 @@ class Repository implements RepositoryInterface
|
||||
}
|
||||
}
|
||||
|
||||
if ($canSelect) {
|
||||
if ( $selectObj ??= $this->queryBuilder->getFragment(Query\Select::class) ) {
|
||||
$selectObj->isInternalSelect = true;
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@ -544,7 +569,7 @@ class Repository implements RepositoryInterface
|
||||
# Apply FILTER annotation to this too !
|
||||
foreach(array_filter((array) $fields) as $item) {
|
||||
if ( $relation = $this->entityResolver->searchFieldAnnotation($item, [ Relation::class ]) ) {
|
||||
$relation->alias ??= $item;
|
||||
$alias = $relation->alias ?? $item;
|
||||
|
||||
if ( $relation->isManyToMany() ) {
|
||||
$entity = $relation->bridge;
|
||||
@ -553,14 +578,13 @@ class Repository implements RepositoryInterface
|
||||
|
||||
extract(Repository\RelationBuilder::relationAnnotations($item, $relation));
|
||||
|
||||
$repository->join(Query\Join::TYPE_INNER, $bridgeEntity->tableName(), $relation->bridge::field($relationRelation->key, $relation->bridgeField), $relationRelation->entity::field($relationRelation->foreignKey, $relation->alias), $relation->bridgeField)
|
||||
$repository->join(Query\Join::TYPE_INNER, $bridgeEntity->tableName(), $relation->bridge::field($relationRelation->key, $relation->bridgeField), $relationRelation->entity::field($relationRelation->foreignKey, $alias), $relation->bridgeField)
|
||||
->where( $entity::field($bridgeRelation->key, $relation->bridgeField), $entity::field($bridgeRelation->foreignKey, $this->alias))
|
||||
->selectJsonEntity($relationRelation->entity, $relation->alias)->open();
|
||||
->selectJsonEntity($relationRelation->entity, $alias)->open();
|
||||
}
|
||||
else {
|
||||
$relation->entity ??= $this->entityResolver->getPropertyEntityType($name);
|
||||
$entity = $relation->entity;
|
||||
$repository = $relation->entity::repository()->selectJsonEntity($entity, $relation->alias)->open();
|
||||
$entity = $relation->entity ?? $this->entityResolver->properties[$item]['type'];
|
||||
$repository = $entity::repository()->selectJsonEntity($entity, $alias)->open();
|
||||
}
|
||||
|
||||
# $relation->isManyToMany() and $repository->selectJsonEntity($relation->bridge, $relation->bridgeField, true);
|
||||
@ -569,21 +593,16 @@ class Repository implements RepositoryInterface
|
||||
$repository->where(is_object($condition->field) ? $condition->field : $entity::field($condition->field), $condition->getValue(), $condition->operator);
|
||||
}
|
||||
|
||||
|
||||
foreach($this->entityResolver->searchFieldAnnotationList($item, [ Having::class ] ) as $condition) {
|
||||
$repository->having(is_object($condition->field) ? $condition->field : $entity::field($condition->field), $condition->getValue(), $condition->operator);
|
||||
}
|
||||
|
||||
foreach ($this->entityResolver->searchFieldAnnotationList($item, [ Filter::class ]) as $filter) {
|
||||
call_user_func_array([$this->entityClass, $filter->method], [$this, $item, true]);
|
||||
}
|
||||
|
||||
$repository->close();
|
||||
|
||||
$key = is_string($relation->key) ? $this->entityClass::field($relation->key) : $relation->key;
|
||||
|
||||
if (! $relation->isManyToMany() ) {
|
||||
$foreignKey = is_string($relation->foreignKey) ? $entity::field($relation->foreignKey, $relation->alias) : $relation->foreignKey;
|
||||
$foreignKey = is_string($relation->foreignKey) ? $entity::field($relation->foreignKey, $alias) : $relation->foreignKey;
|
||||
|
||||
$repository->where( $foreignKey, $key);
|
||||
}
|
||||
@ -604,9 +623,8 @@ class Repository implements RepositoryInterface
|
||||
if (null !== ($relation = $this->entityResolver->searchFieldAnnotation($name, [ Relation::class ] ))) {
|
||||
$order = $this->entityResolver->searchFieldAnnotationList($name, [ OrderBy::class ]);
|
||||
$where = $this->entityResolver->searchFieldAnnotationList($name, [ Where::class ]);
|
||||
$filters = $this->entityResolver->searchFieldAnnotationList($name, [ Filter::class ]);
|
||||
|
||||
$baseEntity = $relation->entity ?? $relation->bridge ?? $this->entityResolver->getPropertyEntityType($name);
|
||||
$baseEntity = $relation->entity ?? $relation->bridge ?? $this->entityResolver->properties[$name]['type'];
|
||||
$baseEntityResolver = $baseEntity::resolveEntity();
|
||||
|
||||
$property = ($baseEntityResolver->field($relation->foreignKey, 01, false) ?: $baseEntityResolver->field($relation->foreignKey, 02))['name'];
|
||||
@ -625,10 +643,6 @@ class Repository implements RepositoryInterface
|
||||
$repository->where($condition->field, $condition->getValue(/* why repository sent here ??? $this */), $condition->operator, $condition->condition);
|
||||
}
|
||||
|
||||
foreach ($filters as $filter) {
|
||||
call_user_func_array([ $this->entityClass, $filter->method ], [ $repository, $name, true ]);
|
||||
}
|
||||
|
||||
foreach ($order as $item) {
|
||||
$repository->orderBy($item->field, $item->order);
|
||||
}
|
||||
@ -647,8 +661,7 @@ class Repository implements RepositoryInterface
|
||||
|
||||
$repository->where($key, $values);
|
||||
|
||||
$loadMethod = $relation->isOneToOne() ? 'loadAll' : $relation->function();
|
||||
$results = $repository->{$loadMethod}();
|
||||
$results = $repository->loadAll();
|
||||
|
||||
if ($relation->isOneToOne()) {
|
||||
foreach ($collection as $item) {
|
||||
@ -658,30 +671,13 @@ class Repository implements RepositoryInterface
|
||||
elseif ($relation->isOneToMany()) {
|
||||
foreach ($collection as $item) {
|
||||
$item->$name = $baseEntity::entityCollection();
|
||||
$search = $results->searchAll($item->$entityProperty, $property);
|
||||
$item->$name->mergeWith($search);
|
||||
$item->$name->mergeWith($results->searchAll($item->$entityProperty, $property));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
## AWAITING THE Closures in constant expression from PHP 8.5 !
|
||||
protected function evalClosure(mixed $content, string $entityClass, mixed $alias = self::DEFAULT_ALIAS) : mixed
|
||||
{
|
||||
if (is_string($content)) {
|
||||
if ( str_starts_with($content, 'fn(') ) {
|
||||
$closure = eval("return $content;");
|
||||
|
||||
return $closure($this);
|
||||
}
|
||||
|
||||
return $entityClass::field($content, $alias);
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
public function filterServerRequest(SearchRequest\SearchRequestInterface $searchRequest, bool $count = true) : self
|
||||
{
|
||||
if ($count) {
|
||||
@ -778,15 +774,7 @@ class Repository implements RepositoryInterface
|
||||
|
||||
public function instanciateEntity(? string $entityClass = null) : object
|
||||
{
|
||||
$entityClass ??= $this->entityClass;
|
||||
|
||||
try {
|
||||
$entity = new $entityClass();
|
||||
}
|
||||
catch (\Throwable $ex) {
|
||||
$entity = ( new \ReflectionClass($entityClass) )->newInstanceWithoutConstructor();
|
||||
}
|
||||
|
||||
$entity = ( new \ReflectionClass($entityClass ?? $this->entityClass) )->newInstanceWithoutConstructor();
|
||||
$entity->initializeEntity();
|
||||
|
||||
return $entity;
|
||||
|
||||
9
src/SearchRequest/Attribute/OrderByEnum.php
Normal file
9
src/SearchRequest/Attribute/OrderByEnum.php
Normal file
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\SearchRequest\Attribute;
|
||||
|
||||
enum OrderByEnum : string
|
||||
{
|
||||
case Ascending = "ASC";
|
||||
case Descending = "DESC";
|
||||
}
|
||||
@ -83,7 +83,7 @@ trait SearchRequestFromRequestTrait
|
||||
$this->page = $queryParams->offsetExists('page') ? $queryParams['page'] : 1;
|
||||
|
||||
$this->applyValues(
|
||||
fn($propertyName, $attribute) => $this->getValueFromSource($request, $propertyName, $attribute)
|
||||
fn($propertyName, $attribute) =>$this->getValueFromSource($request, $propertyName, $attribute)
|
||||
);
|
||||
|
||||
$operators = $request->getAttribute(SearchRequestInterface::SEARCH_REQUEST_OPERATORS);
|
||||
@ -227,6 +227,14 @@ trait SearchRequestFromRequestTrait
|
||||
|
||||
protected function getValueFromSource(RequestInterface $request, string $propertyName, SearchParameter $attribute) : mixed
|
||||
{
|
||||
$classAttributes = $this->objectReflection->getAttributes(SearchRequestParameter::class);
|
||||
$searchRequestAttribute = $classAttributes[0]->object;
|
||||
$className = $searchRequestAttribute->class;
|
||||
|
||||
if ( $override = $request->getAttribute(sprintf("searchRequest.%s:%s", $className, $propertyName)) ) {
|
||||
return $override;
|
||||
}
|
||||
|
||||
$queryParamName = $attribute->getParameters() ?: [ $propertyName ];
|
||||
|
||||
foreach($attribute->getSources() as $source) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user