Skip to content

Commit

Permalink
Adds readonly compatibility with Doctrine Mongo ODM documents
Browse files Browse the repository at this point in the history
  • Loading branch information
alterphp committed Jan 24, 2020
1 parent a168154 commit ec95fad
Show file tree
Hide file tree
Showing 45 changed files with 1,348 additions and 372 deletions.
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -233,20 +233,20 @@ easy_admin_extension:

#### Options

Embedded lists are useful to show relations to en entity in its *NEW/EDIT/FORM* or *SHOW* view. It relies on the *LIST* view of the related entities you want to embed in the parent EDIT/SHOW view. Options must be defined in `type_options` key for a *NEW/EDIT/FORM* view, or in `template_options` for a *SHOW* view.
Embedded lists are useful to show relations to an object in its *NEW/EDIT/FORM* or *SHOW* view. It relies on the *LIST* view of the related objects you want to embed in the parent EDIT/SHOW view. Options must be defined in `type_options` key for a *NEW/EDIT/FORM* view, or in `template_options` for a *SHOW* view.

Available options are :

- `entity`: Entity config name (key under the EasyAdmin `entities` config)
- `entity`/`document`: Entity/Document config name (key under the EasyAdmin `entities`/`documents` config)
- `ext_filters`: Request filters to apply on the list
- `hidden_fields`: List of fields (columns) to hide from list fields config
- `max_results`: Number of items par page (list.max_results config is used if not defined)
- `sort`: Sort to apply
- `parent_entity_fqcn`: Parent entity FQCN in order to guess default filters (only when embedded in *SHOW* view, almost never required)
- `parent_entity_property`: Matching property name on parent entity FQCN (only when embedded in *SHOW* view, if `property` is not an ORM field)
- `entity_fqcn`: Listed entities FQCN in order to guess default filters (only when embedded in *SHOW* view, almost never required)
- `parent_object_fqcn`: Parent object FQCN in order to guess default filters (only when embedded in *SHOW* view, almost never required)
- `parent_object_property`: Matching property name on parent object FQCN (only when embedded in *SHOW* view, if `property` is not an ORM/ODM field)
- `object_fqcn`: Listed entities FQCN in order to guess default filters (only when embedded in *SHOW* view, almost never required)

#### Options guesser based on ORM metadata
#### Options guesser based on ORM metadata (for entities only)

Service EmbeddedListHelper is intended to guess `entity` entry for embedded_list. It's reads ORM metadata, based on parent entity (the one that embeds the list) and property name.

Expand Down
12 changes: 12 additions & 0 deletions TODO_mongo_odm.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Utiliser les functions Twig object

# Menu entries (entry type = document)

# Passer les configPass en mongo_odm
- EmbeddedListViewConfigPass: OK
- ExcludeFieldsConfigPass
- ListFormFiltersConfigPass OK
- ShortFormTypeConfigPass: OK
- ShowViewConfigPass: ?

# Tests !
6 changes: 4 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@
"twig/twig": "^2.11.3|^3.0"
},
"require-dev": {
"doctrine/data-fixtures": "^1.3",
"alterphp/easyadmin-mongo-odm-bundle": "dev-master",
"doctrine/doctrine-fixtures-bundle": "^3.0",
"doctrine/mongodb-odm-bundle": "^4.0",
"friendsofphp/php-cs-fixer": "^2.11",
"php-coveralls/php-coveralls": "^2.0",
"phpstan/phpstan": "dev-master",
Expand All @@ -58,7 +59,8 @@
"sort-packages": true,
"platform": {
"php": "7.1.3",
"ext-intl": "1.0"
"ext-intl": "1.0",
"ext-mongodb": "1.6.1"
}
},
"autoload": {
Expand Down
6 changes: 6 additions & 0 deletions docker/phpunit/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,11 @@ RUN apt-get update && \

RUN curl --silent --show-error https://getcomposer.org/installer | php

RUN docker-php-ext-install -j$(nproc) mysqli

# Install MONGO
RUN pecl install mongodb \
&& docker-php-ext-enable mongodb

# RUN apk --no-cache add php7-iconv
# RUN apk --no-cache add php7-simplexml
62 changes: 37 additions & 25 deletions src/Configuration/EmbeddedListViewConfigPass.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
use EasyCorp\Bundle\EasyAdminBundle\Configuration\ConfigPassInterface;

/**
* Initializes the configuration for all the views of each entity, which is
* needed when some entity relies on the default configuration for some view.
* Initializes the configuration for all the views of each object of type "%s", which is
* needed when some object of type "%s" relies on the default configuration for some view.
*/
class EmbeddedListViewConfigPass implements ConfigPassInterface
{
Expand All @@ -31,9 +31,13 @@ public function process(array $backendConfig)
*/
private function processOpenNewTabConfig(array $backendConfig)
{
foreach ($backendConfig['entities'] as $entityName => $entityConfig) {
if (!isset($entityConfig['embeddedList']['open_new_tab'])) {
$backendConfig['entities'][$entityName]['embeddedList']['open_new_tab'] = $this->defaultOpenNewTab;
foreach (['entities', 'documents'] as $objectTypeRootKey) {
if (isset($backendConfig[$objectTypeRootKey]) && \is_array($backendConfig[$objectTypeRootKey])) {
foreach ($backendConfig[$objectTypeRootKey] as $objectName => $objectConfig) {
if (!isset($objectConfig['embeddedList']['open_new_tab'])) {
$backendConfig[$objectTypeRootKey][$objectName]['embeddedList']['open_new_tab'] = $this->defaultOpenNewTab;
}
}
}
}

Expand All @@ -45,25 +49,29 @@ private function processOpenNewTabConfig(array $backendConfig)
*/
private function processSortingConfig(array $backendConfig)
{
foreach ($backendConfig['entities'] as $entityName => $entityConfig) {
if (
!isset($entityConfig['embeddedList']['sort'])
&& isset($entityConfig['list']['sort'])
) {
$backendConfig['entities'][$entityName]['embeddedList']['sort'] = $entityConfig['list']['sort'];
} elseif (isset($entityConfig['embeddedList']['sort'])) {
$sortConfig = $entityConfig['embeddedList']['sort'];
if (!\is_string($sortConfig) && !\is_array($sortConfig)) {
throw new \InvalidArgumentException(\sprintf('The "sort" option of the "embeddedList" view of the "%s" entity contains an invalid value (it can only be a string or an array).', $entityName));
}
foreach (['entities', 'documents'] as $objectTypeRootKey) {
if (isset($backendConfig[$objectTypeRootKey]) && \is_array($backendConfig[$objectTypeRootKey])) {
foreach ($backendConfig[$objectTypeRootKey] as $objectName => $objectConfig) {
if (
!isset($objectConfig['embeddedList']['sort'])
&& isset($objectConfig['list']['sort'])
) {
$backendConfig[$objectTypeRootKey][$objectName]['embeddedList']['sort'] = $objectConfig['list']['sort'];
} elseif (isset($objectConfig['embeddedList']['sort'])) {
$sortConfig = $objectConfig['embeddedList']['sort'];
if (!\is_string($sortConfig) && !\is_array($sortConfig)) {
throw new \InvalidArgumentException(\sprintf('The "sort" option of the "embeddedList" view of the "%s" object contains an invalid value (it can only be a string or an array).', $objectName));
}

if (\is_string($sortConfig)) {
$sortConfig = ['field' => $sortConfig, 'direction' => 'DESC'];
} else {
$sortConfig = ['field' => $sortConfig[0], 'direction' => \strtoupper($sortConfig[1])];
}
if (\is_string($sortConfig)) {
$sortConfig = ['field' => $sortConfig, 'direction' => 'DESC'];
} else {
$sortConfig = ['field' => $sortConfig[0], 'direction' => \strtoupper($sortConfig[1])];
}

$backendConfig['entities'][$entityName]['embeddedList']['sort'] = $sortConfig;
$backendConfig[$objectTypeRootKey][$objectName]['embeddedList']['sort'] = $sortConfig;
}
}
}
}

Expand All @@ -72,9 +80,13 @@ private function processSortingConfig(array $backendConfig)

private function processTemplateConfig(array $backendConfig)
{
foreach ($backendConfig['entities'] as $entityName => $entityConfig) {
if (!isset($entityConfig['embeddedList']['template'])) {
$backendConfig['entities'][$entityName]['embeddedList']['template'] = '@EasyAdminExtension/default/embedded_list.html.twig';
foreach (['entities', 'documents'] as $objectTypeRootKey) {
if (isset($backendConfig[$objectTypeRootKey]) && \is_array($backendConfig[$objectTypeRootKey])) {
foreach ($backendConfig[$objectTypeRootKey] as $objectName => $objectConfig) {
if (!isset($objectConfig['embeddedList']['template'])) {
$backendConfig[$objectTypeRootKey][$objectName]['embeddedList']['template'] = '@EasyAdminExtension/default/embedded_list.html.twig';
}
}
}
}

Expand Down
59 changes: 34 additions & 25 deletions src/Configuration/ListFormFiltersConfigPass.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,29 +27,42 @@ public function __construct(ManagerRegistry $doctrine)

public function process(array $backendConfig): array
{
if (!isset($backendConfig['entities'])) {
return $backendConfig;
if (isset($backendConfig['entities']) && \is_array($backendConfig['entities'])) {
$this->processObjectListFormFilters('entity', $backendConfig['entities']);
}

foreach ($backendConfig['entities'] as $entityName => $entityConfig) {
if (!isset($entityConfig['list']['form_filters'])) {
if (isset($backendConfig['documents']) && \is_array($backendConfig['documents'])) {
$this->processObjectListFormFilters('document', $backendConfig['documents']);
}

return $backendConfig;
}

private function processObjectListFormFilters(string $objectType, array &$objectConfigs)
{
foreach ($objectConfigs as $objectName => $objectConfig) {
if (!isset($objectConfig['list']['form_filters'])) {
continue;
}

$formFilters = [];

foreach ($entityConfig['list']['form_filters'] as $i => $formFilter) {
foreach ($objectConfig['list']['form_filters'] as $key => $formFilter) {
// Detects invalid config node
if (!\is_string($formFilter) && !\is_array($formFilter)) {
throw new \RuntimeException(\sprintf('The values of the "form_filters" option for the list view of the "%s" entity can only be strings or arrays.', $entityConfig['class']));
throw new \RuntimeException(\sprintf('The values of the "form_filters" option for the list view of the "%s" object of type "%s" can only be strings or arrays.', $objectConfig['class'], $objectType));
}

// Key mapping
if (\is_string($formFilter)) {
$filterConfig = ['property' => $formFilter];
} else {
if (!\array_key_exists('property', $formFilter)) {
throw new \RuntimeException(\sprintf('One of the values of the "form_filters" option for the "list" view of the "%s" entity does not define the mandatory option "property".', $entityConfig['class']));
if (\is_string($key)) {
$formFilter['property'] = $key;
} else {
throw new \RuntimeException(\sprintf('One of the values of the "form_filters" option for the "list" view of the "%s" object of type "%s" does not define the mandatory option "property".', $objectConfig['class'], $objectType));
}
}

$filterConfig = $formFilter;
Expand All @@ -60,9 +73,11 @@ public function process(array $backendConfig): array
// Auto set label with name value
$filterConfig['label'] = $filterConfig['label'] ?? $filterConfig['name'];
// Auto-set translation_domain
$filterConfig['translation_domain'] = $filterConfig['translation_domain'] ?? $entityConfig['translation_domain'];
$filterConfig['translation_domain'] = $filterConfig['translation_domain'] ?? $objectConfig['translation_domain'];

$this->configureFilter($entityConfig['class'], $filterConfig);
if ('entity' === $objectType) {
$this->configureEntityFormFilter($objectConfig['class'], $filterConfig);
}

// If type is not configured at this steps => not guessable
if (!isset($filterConfig['type'])) {
Expand All @@ -73,13 +88,11 @@ public function process(array $backendConfig): array
}

// set form filters config and form !
$backendConfig['entities'][$entityName]['list']['form_filters'] = $formFilters;
$objectConfigs[$objectName]['list']['form_filters'] = $formFilters;
}

return $backendConfig;
}

private function configureFilter(string $entityClass, array &$filterConfig)
private function configureEntityFormFilter(string $entityClass, array &$filterConfig)
{
$em = $this->doctrine->getManagerForClass($entityClass);
$entityMetadata = $em->getMetadataFactory()->getMetadataFor($entityClass);
Expand All @@ -92,20 +105,16 @@ private function configureFilter(string $entityClass, array &$filterConfig)
return;
}

// Only applicable to ORM ClassMetadataInfo instances
if ($entityMetadata instanceof ClassMetadataInfo) {
if ($entityMetadata->hasField($filterConfig['property'])) {
$this->configureFieldFilter(
$entityClass, $entityMetadata->getFieldMapping($filterConfig['property']), $filterConfig);
} elseif ($entityMetadata->hasAssociation($filterConfig['property'])) {
$this->configureAssociationFilter(
$entityClass, $entityMetadata->getAssociationMapping($filterConfig['property']), $filterConfig
);
}
if ($entityMetadata->hasField($filterConfig['property'])) {
$this->configureEntityPropertyFilter($entityClass, $entityMetadata->getFieldMapping($filterConfig['property']), $filterConfig);
} elseif ($entityMetadata->hasAssociation($filterConfig['property'])) {
$this->configureEntityAssociationFilter(
$entityClass, $entityMetadata->getAssociationMapping($filterConfig['property']), $filterConfig
);
}
}

private function configureFieldFilter(string $entityClass, array $fieldMapping, array &$filterConfig)
private function configureEntityPropertyFilter(string $entityClass, array $fieldMapping, array &$filterConfig)
{
$defaultFilterConfigTypeOptions = [];

Expand Down Expand Up @@ -160,7 +169,7 @@ private function configureFieldFilter(string $entityClass, array $fieldMapping,
);
}

private function configureAssociationFilter(string $entityClass, array $associationMapping, array &$filterConfig)
private function configureEntityAssociationFilter(string $entityClass, array $associationMapping, array &$filterConfig)
{
$defaultFilterConfigTypeOptions = [];

Expand Down
15 changes: 8 additions & 7 deletions src/Configuration/ShortFormTypeConfigPass.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,16 @@ public function process(array $backendConfig)

private function replaceShortNameTypes(array $backendConfig)
{
if (
!isset($backendConfig['entities'])
|| !\is_array($backendConfig['entities'])
) {
return $backendConfig;
if (isset($backendConfig['entities']) && \is_array($backendConfig['entities'])) {
foreach ($backendConfig['entities'] as &$entityConfig) {
$entityConfig = $this->replaceShortFormTypesInObjectConfig($entityConfig);
}
}

foreach ($backendConfig['entities'] as &$entity) {
$entity = $this->replaceShortFormTypesInObjectConfig($entity);
if (isset($backendConfig['documents']) && \is_array($backendConfig['documents'])) {
foreach ($backendConfig['documents'] as &$documentConfig) {
$documentConfig = $this->replaceShortFormTypesInObjectConfig($documentConfig);
}
}

return $backendConfig;
Expand Down
Loading

0 comments on commit ec95fad

Please sign in to comment.