diff --git a/src/Datagrid/Datagrid.php b/src/Datagrid/Datagrid.php index 5316edd..d126846 100644 --- a/src/Datagrid/Datagrid.php +++ b/src/Datagrid/Datagrid.php @@ -189,6 +189,18 @@ public function hasActiveFilters(): bool return false; } + public function hasDisplayableFilters(): bool + { + foreach ($this->filters as $name => $filter) { + $showFilter = $filter->getOption('show_filter', null); + if (($filter->isActive() && null === $showFilter) || (true === $showFilter)) { + return true; + } + } + + return false; + } + public function getQuery(): ProxyQueryInterface { return $this->query; diff --git a/src/Datagrid/DatagridInterface.php b/src/Datagrid/DatagridInterface.php index cd9f9a0..33662b2 100644 --- a/src/Datagrid/DatagridInterface.php +++ b/src/Datagrid/DatagridInterface.php @@ -50,4 +50,6 @@ public function hasFilter(string $name): bool; public function removeFilter(string $name): void; public function hasActiveFilters(): bool; + + public function hasDisplayableFilters(): bool; } diff --git a/src/Filter/BaseFilter.php b/src/Filter/BaseFilter.php index 2f62338..7ec29f9 100644 --- a/src/Filter/BaseFilter.php +++ b/src/Filter/BaseFilter.php @@ -91,6 +91,20 @@ public function getFieldOptions(): array return $this->getOption('field_options', ['required' => false]); } + public function getFieldOption(string $name, $default = null) + { + if (isset($this->options['field_options'][$name]) && \is_array($this->options['field_options'])) { + return $this->options['field_options'][$name]; + } + + return $default; + } + + public function setFieldOption(string $name, $value): void + { + $this->options['field_options'][$name] = $value; + } + public function getLabel(): ?string { return $this->getOption('label'); @@ -112,6 +126,33 @@ public function getFieldName(): string return $fieldName; } + public function getParentAssociationMappings(): array + { + return $this->getOption('parent_association_mappings', []); + } + + public function getFieldMapping(): array + { + $fieldMapping = $this->getOption('field_mapping'); + + if (!$fieldMapping) { + throw new \RuntimeException(sprintf('The option `field_mapping` must be set for field: `%s`', $this->getName())); + } + + return $fieldMapping; + } + + public function getAssociationMapping(): array + { + $associationMapping = $this->getOption('association_mapping'); + + if (!$associationMapping) { + throw new \RuntimeException(sprintf('The option `association_mapping` must be set for field: `%s`', $this->getName())); + } + + return $associationMapping; + } + public function setOptions(array $options): void { $this->options = array_merge($this->getDefaultOptions(), $options); diff --git a/src/Filter/FilterFactoryInterface.php b/src/Filter/FilterFactoryInterface.php index 1a6cde4..bd4561d 100644 --- a/src/Filter/FilterFactoryInterface.php +++ b/src/Filter/FilterFactoryInterface.php @@ -15,8 +15,5 @@ interface FilterFactoryInterface { - /** - * @return mixed - */ - public function create(string $name, string $type, array $options = []); + public function create(string $name, string $type, array $options = []): FilterInterface; } diff --git a/src/Filter/FilterInterface.php b/src/Filter/FilterInterface.php index 2cb3f57..5781919 100644 --- a/src/Filter/FilterInterface.php +++ b/src/Filter/FilterInterface.php @@ -58,8 +58,35 @@ public function initialize(string $name, array $options = []): void; public function getFieldName(): string; + /** + * @return array array of mappings + */ + public function getParentAssociationMappings(): array; + + /** + * @return array field mapping + */ + public function getFieldMapping(): array; + + /** + * @return array association mapping + */ + public function getAssociationMapping(): array; + public function getFieldOptions(): array; + /** + * @param mixed $default + * + * @return mixed + */ + public function getFieldOption(string $name, $default = null); + + /** + * @param mixed $value + */ + public function setFieldOption(string $name, $value): void; + public function getFieldType(): string; /** diff --git a/src/ProxyQuery/BaseProxyQuery.php b/src/ProxyQuery/BaseProxyQuery.php index 81147a3..f44d7b5 100644 --- a/src/ProxyQuery/BaseProxyQuery.php +++ b/src/ProxyQuery/BaseProxyQuery.php @@ -28,14 +28,24 @@ abstract class BaseProxyQuery implements ProxyQueryInterface protected $results = []; /** - * @var array + * @var int */ - private $sortBy = []; + protected $uniqueParameterId = 0; /** - * @var array + * @var string[] + */ + protected $entityJoinAliases = []; + + /** + * @var string|null + */ + private $sortBy; + + /** + * @var string|null */ - private $sortOrder = []; + private $sortOrder; /** * @var int|null @@ -62,38 +72,27 @@ public function __call(string $name, array $args) return \call_user_func_array([$this->queryBuilder, $name], $args); } - /** - * @param mixed $sortBy - */ - public function setSortBy($sortBy): ProxyQueryInterface + public function setSortBy(array $parentAssociationMappings, array $fieldMapping): ProxyQueryInterface { - $this->sortBy = $sortBy; + $alias = $this->entityJoin($parentAssociationMappings); + $this->sortBy = $alias.'.'.$fieldMapping['fieldName']; return $this; } - /** - * @return mixed - */ - public function getSortBy() + public function getSortBy(): ?string { return $this->sortBy; } - /** - * @param mixed $sortOrder - */ - public function setSortOrder($sortOrder): ProxyQueryInterface + public function setSortOrder(string $sortOrder): ProxyQueryInterface { $this->sortOrder = $sortOrder; return $this; } - /** - * @return mixed - */ - public function getSortOrder() + public function getSortOrder(): ?string { return $this->sortOrder; } @@ -122,10 +121,7 @@ public function getMaxResults(): ?int return $this->maxResults; } - /** - * @return mixed - */ - public function getQueryBuilder() + public function getQueryBuilder(): QueryBuilder { return $this->queryBuilder; } @@ -134,4 +130,44 @@ public function getResults(): array { return $this->results; } + + public function getUniqueParameterId(): int + { + return $this->uniqueParameterId++; + } + + public function entityJoin(array $associationMappings): string + { + $alias = current($this->queryBuilder->getRootAliases()); + + $newAlias = 's'; + + $joinedEntities = $this->queryBuilder->getDQLPart('join'); + + foreach ($associationMappings as $associationMapping) { + // Do not add left join to already joined entities with custom query + foreach ($joinedEntities as $joinExprList) { + foreach ($joinExprList as $joinExpr) { + $newAliasTmp = $joinExpr->getAlias(); + + if (sprintf('%s.%s', $alias, $associationMapping['fieldName']) === $joinExpr->getJoin()) { + $this->entityJoinAliases[] = $newAliasTmp; + $alias = $newAliasTmp; + + continue 3; + } + } + } + + $newAlias .= '_'.$associationMapping['fieldName']; + if (!\in_array($newAlias, $this->entityJoinAliases, true)) { + $this->entityJoinAliases[] = $newAlias; + $this->queryBuilder->leftJoin(sprintf('%s.%s', $alias, $associationMapping['fieldName']), $newAlias); + } + + $alias = $newAlias; + } + + return $alias; + } } diff --git a/src/ProxyQuery/ProxyQueryInterface.php b/src/ProxyQuery/ProxyQueryInterface.php index 394f3e6..6e02b8b 100644 --- a/src/ProxyQuery/ProxyQueryInterface.php +++ b/src/ProxyQuery/ProxyQueryInterface.php @@ -28,25 +28,13 @@ public function __call(string $name, array $args); */ public function execute(array $params = [], ?int $hydrationMode = null); - /** - * @param mixed $sortBy - */ - public function setSortBy($sortBy): self; + public function setSortBy(array $parentAssociationMappings, array $fieldMapping): self; - /** - * @return mixed - */ - public function getSortBy(); + public function getSortBy(): ?string; - /** - * @param mixed $sortOrder - */ - public function setSortOrder($sortOrder): self; + public function setSortOrder(string $sortOrder): self; - /** - * @return mixed - */ - public function getSortOrder(); + public function getSortOrder(): ?string; public function setFirstResult(?int $firstResult): self; @@ -57,4 +45,8 @@ public function setMaxResults(?int $maxResults): self; public function getMaxResults(): ?int; public function getResults(): array; + + public function getUniqueParameterId(): int; + + public function entityJoin(array $associationMappings): string; }