- Merged getValue override
This commit is contained in:
1 parent
b0b3aca6d9
commit
fd5d31fa17
11 files changed
+183
-106
No files matched your search
+79
-91
@@ -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;
|
||||
|
||||
Reference in new issue
Block a user