Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement FieldDescriptionFactory #531

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion UPGRADE-3.x.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,30 @@ UPGRADE FROM 3.x to 3.x

Deprecated `modelReverseTransform()` method, use `reverseTransform()` instead.

### Sonata\DoctrineMongoDBAdminBundle\Builder\ListBuilder

Deprecated `buildActionFieldDescription()` method without replacement.

### Sonata\DoctrineMongoDBAdminBundle\Guesser\TypeGuesser

Deprecated `guessType()` method, you should use `guess()` method instead.

### Sonata\DoctrineMongoDBAdminBundle\Guesser\FilterTypeGuesser

Deprecated `guessType()` method, you should use `guess()` method instead.

### Sonata\DoctrineMongoDBAdminBundle\Guesser\AbstractTypeGuesser

This class has been deprecated without replacement.

### Sonata\DoctrineMongoDBAdminBundle\Model\ModelManager

Deprecated `getParentMetadataForProperty()` method.
Deprecated `getNewFieldDescriptionInstance()` method, you SHOULD use `FieldDescriptionFactory::create()` instead.

### Sonata\DoctrineMongoDBAdminBundle\Filter\Filter

Deprecate passing an instance of `Sonata\AdminBundle\Datagrid\ProxyQueryInterface`
Deprecated passing an instance of `Sonata\AdminBundle\Datagrid\ProxyQueryInterface`
which is not an instance of `Sonata\DoctrineMongoDBAdminBundle\Datagrid\ProxyQueryInterface` as
argument 1 to the `Sonata\DoctrineMongoDBAdminBundle\Filter\Filter::filter()` method.

Expand Down
2 changes: 2 additions & 0 deletions src/Admin/FieldDescription.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public function setAssociationMapping($associationMapping)

$this->associationMapping = $associationMapping;

// NEXT_MAJOR: Remove next line.
$this->type = $this->type ?: $associationMapping['type'];
$this->mappingType = $this->mappingType ?: $associationMapping['type'];
$this->fieldName = $associationMapping['fieldName'];
Expand Down Expand Up @@ -77,6 +78,7 @@ public function setFieldMapping($fieldMapping)

$this->fieldMapping = $fieldMapping;

// NEXT_MAJOR: Remove next line.
$this->type = $this->type ?: $fieldMapping['type'];
$this->mappingType = $this->mappingType ?: $fieldMapping['type'];
$this->fieldName = $this->fieldName ?: $fieldMapping['fieldName'];
Expand Down
29 changes: 22 additions & 7 deletions src/Builder/DatagridBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@
use Sonata\AdminBundle\Builder\DatagridBuilderInterface;
use Sonata\AdminBundle\Datagrid\Datagrid;
use Sonata\AdminBundle\Datagrid\DatagridInterface;
use Sonata\AdminBundle\FieldDescription\TypeGuesserInterface;
use Sonata\AdminBundle\Filter\FilterFactoryInterface;
use Sonata\AdminBundle\Guesser\TypeGuesserInterface;
use Sonata\AdminBundle\Guesser\TypeGuesserInterface as DeprecatedTypeGuesserInterface;
use Sonata\DoctrineMongoDBAdminBundle\Datagrid\Pager;
use Sonata\DoctrineMongoDBAdminBundle\Model\ModelManager;
use Symfony\Component\Form\Extension\Core\Type\FormType;
Expand All @@ -42,7 +43,9 @@ class DatagridBuilder implements DatagridBuilderInterface
protected $formFactory;

/**
* @var TypeGuesserInterface
* NEXT_MAJOR: Remove DeprecatedTypeGuesserInterface type.
*
* @var DeprecatedTypeGuesserInterface|TypeGuesserInterface
*/
protected $guesser;

Expand All @@ -54,9 +57,12 @@ class DatagridBuilder implements DatagridBuilderInterface
protected $csrfTokenEnabled;

/**
* @param bool $csrfTokenEnabled
* NEXT_MAJOR: Remove DeprecatedTypeGuesserInterface type and add TypeGuesserInterface to the constructor.
*
* @param DeprecatedTypeGuesserInterface|TypeGuesserInterface $guesser
* @param bool $csrfTokenEnabled
*/
public function __construct(FormFactoryInterface $formFactory, FilterFactoryInterface $filterFactory, TypeGuesserInterface $guesser, $csrfTokenEnabled = true)
public function __construct(FormFactoryInterface $formFactory, FilterFactoryInterface $filterFactory, $guesser, $csrfTokenEnabled = true)
{
$this->formFactory = $formFactory;
$this->filterFactory = $filterFactory;
Expand All @@ -69,7 +75,7 @@ public function __construct(FormFactoryInterface $formFactory, FilterFactoryInte
*/
public function fixFieldDescription(AdminInterface $admin, FieldDescriptionInterface $fieldDescription)
{
// set default values
// NEXT_MAJOR: Remove this call.
$fieldDescription->setAdmin($admin);

// NEXT_MAJOR: Remove the following 2 lines.
Expand All @@ -78,7 +84,7 @@ public function fixFieldDescription(AdminInterface $admin, FieldDescriptionInter

// NEXT_MAJOR: Remove this block.
if ($modelManager->hasMetadata($admin->getClass(), 'sonata_deprecation_mute')) {
[$metadata, $lastPropertyName, $parentAssociationMappings] = $modelManager->getParentMetadataForProperty($admin->getClass(), $fieldDescription->getName());
[$metadata, $lastPropertyName, $parentAssociationMappings] = $modelManager->getParentMetadataForProperty($admin->getClass(), $fieldDescription->getName(), 'sonata_deprecation_mute');

// set the default field mapping
if (isset($metadata->fieldMappings[$lastPropertyName])) {
Expand Down Expand Up @@ -127,7 +133,16 @@ public function fixFieldDescription(AdminInterface $admin, FieldDescriptionInter
public function addFilter(DatagridInterface $datagrid, $type, FieldDescriptionInterface $fieldDescription, AdminInterface $admin)
{
if (null === $type) {
$guessType = $this->guesser->guessType($admin->getClass(), $fieldDescription->getName(), $admin->getModelManager());
// NEXT_MAJOR: Remove the condition and keep the if part.
if ($this->guesser instanceof TypeGuesserInterface) {
$guessType = $this->guesser->guess($fieldDescription);
} else {
$guessType = $this->guesser->guessType(
$admin->getClass(),
$fieldDescription->getName(),
$admin->getModelManager()
);
}

$type = $guessType->getType();

Expand Down
2 changes: 2 additions & 0 deletions src/Builder/FormContractor.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ public function fixFieldDescription(AdminInterface $admin, FieldDescriptionInter
}
}

// NEXT_MAJOR: Remove this block.
if (!$fieldDescription->getType()) {
throw new \RuntimeException(sprintf(
'Please define a type for field `%s` in `%s`',
Expand All @@ -82,6 +83,7 @@ public function fixFieldDescription(AdminInterface $admin, FieldDescriptionInter
));
}

// NEXT_MAJOR: Remove this call.
$fieldDescription->setAdmin($admin);
$fieldDescription->setOption('edit', $fieldDescription->getOption('edit', 'standard'));

Expand Down
43 changes: 38 additions & 5 deletions src/Builder/ListBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,34 @@
use Sonata\AdminBundle\Admin\FieldDescriptionCollection;
use Sonata\AdminBundle\Admin\FieldDescriptionInterface;
use Sonata\AdminBundle\Builder\ListBuilderInterface;
use Sonata\AdminBundle\Guesser\TypeGuesserInterface;
use Sonata\AdminBundle\FieldDescription\TypeGuesserInterface;
use Sonata\AdminBundle\Guesser\TypeGuesserInterface as DeprecatedTypeGuesserInterface;
use Sonata\DoctrineMongoDBAdminBundle\Model\ModelManager;

/**
* @final since sonata-project/doctrine-mongodb-admin-bundle 3.5.
*/
class ListBuilder implements ListBuilderInterface
{
/**
* NEXT_MAJOR: Remove DeprecatedTypeGuesserInterface type.
*
* @var DeprecatedTypeGuesserInterface|TypeGuesserInterface
*/
protected $guesser;

/**
* @var string[]
*/
protected $templates = [];

public function __construct(TypeGuesserInterface $guesser, array $templates = [])
/**
* NEXT_MAJOR: Remove DeprecatedTypeGuesserInterface type and add TypeGuesserInterface to the constructor.
*
* @param DeprecatedTypeGuesserInterface|TypeGuesserInterface $guesser
* @param string[] $templates
*/
public function __construct($guesser, array $templates = [])
{
$this->guesser = $guesser;
$this->templates = $templates;
Expand All @@ -47,7 +62,16 @@ public function getBaseList(array $options = [])
public function buildField($type, FieldDescriptionInterface $fieldDescription, AdminInterface $admin)
{
if (null === $type) {
$guessType = $this->guesser->guessType($admin->getClass(), $fieldDescription->getName(), $admin->getModelManager());
// NEXT_MAJOR: Remove the condition and keep the if part.
if ($this->guesser instanceof TypeGuesserInterface) {
$guessType = $this->guesser->guess($fieldDescription);
} else {
$guessType = $this->guesser->guessType(
$admin->getClass(),
$fieldDescription->getName(),
$admin->getModelManager()
);
}
$fieldDescription->setType($guessType->getType());
} else {
$fieldDescription->setType($type);
Expand All @@ -73,9 +97,10 @@ public function addField(FieldDescriptionCollection $list, $type, FieldDescripti
public function fixFieldDescription(AdminInterface $admin, FieldDescriptionInterface $fieldDescription)
{
if ('_action' === $fieldDescription->getName() || 'actions' === $fieldDescription->getType()) {
$this->buildActionFieldDescription($fieldDescription);
$this->buildActionFieldDescription($fieldDescription, 'sonata_deprecation_mute');
}

// NEXT_MAJOR: Remove this call.
$fieldDescription->setAdmin($admin);

// NEXT_MAJOR: Remove the following 2 lines.
Expand All @@ -84,7 +109,7 @@ public function fixFieldDescription(AdminInterface $admin, FieldDescriptionInter

// NEXT_MAJOR: Remove this block.
if ($modelManager->hasMetadata($admin->getClass(), 'sonata_deprecation_mute')) {
[$metadata, $lastPropertyName, $parentAssociationMappings] = $modelManager->getParentMetadataForProperty($admin->getClass(), $fieldDescription->getName());
[$metadata, $lastPropertyName, $parentAssociationMappings] = $modelManager->getParentMetadataForProperty($admin->getClass(), $fieldDescription->getName(), 'sonata_deprecation_mute');
$fieldDescription->setParentAssociationMappings($parentAssociationMappings);

// set the default field mapping
Expand Down Expand Up @@ -154,6 +179,14 @@ public function fixFieldDescription(AdminInterface $admin, FieldDescriptionInter
*/
public function buildActionFieldDescription(FieldDescriptionInterface $fieldDescription)
{
if ('sonata_deprecation_mute' !== (\func_get_args()[1] ?? null)) {
@trigger_error(sprintf(
'The "%s()" method is deprecated since sonata-project/doctrine-mongodb-admin-bundle 3.x and'
.' will be removed in version 4.0.',
__METHOD__
), \E_USER_DEPRECATED);
}

if (null === $fieldDescription->getTemplate()) {
$fieldDescription->setTemplate('@SonataAdmin/CRUD/list__action.html.twig');
}
Expand Down
33 changes: 29 additions & 4 deletions src/Builder/ShowBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,34 @@
use Sonata\AdminBundle\Admin\FieldDescriptionCollection;
use Sonata\AdminBundle\Admin\FieldDescriptionInterface;
use Sonata\AdminBundle\Builder\ShowBuilderInterface;
use Sonata\AdminBundle\Guesser\TypeGuesserInterface;
use Sonata\AdminBundle\FieldDescription\TypeGuesserInterface;
use Sonata\AdminBundle\Guesser\TypeGuesserInterface as DeprecatedTypeGuesserInterface;
use Sonata\DoctrineMongoDBAdminBundle\Model\ModelManager;

/**
* @final since sonata-project/doctrine-mongodb-admin-bundle 3.5.
*/
class ShowBuilder implements ShowBuilderInterface
{
/**
* NEXT_MAJOR: Remove DeprecatedTypeGuesserInterface type.
*
* @var DeprecatedTypeGuesserInterface|TypeGuesserInterface
*/
protected $guesser;

/**
* @var string[]
*/
protected $templates;

public function __construct(TypeGuesserInterface $guesser, array $templates)
/**
* NEXT_MAJOR: Remove DeprecatedTypeGuesserInterface type and add TypeGuesserInterface to the constructor.
*
* @param DeprecatedTypeGuesserInterface|TypeGuesserInterface $guesser
* @param string[] $templates
*/
public function __construct($guesser, array $templates)
{
$this->guesser = $guesser;
$this->templates = $templates;
Expand All @@ -47,7 +62,16 @@ public function getBaseList(array $options = [])
public function addField(FieldDescriptionCollection $list, $type, FieldDescriptionInterface $fieldDescription, AdminInterface $admin)
{
if (null === $type) {
$guessType = $this->guesser->guessType($admin->getClass(), $fieldDescription->getName(), $admin->getModelManager());
// NEXT_MAJOR: Remove the condition and keep the if part.
if ($this->guesser instanceof TypeGuesserInterface) {
$guessType = $this->guesser->guess($fieldDescription);
} else {
$guessType = $this->guesser->guessType(
$admin->getClass(),
$fieldDescription->getName(),
$admin->getModelManager()
);
}
$fieldDescription->setType($guessType->getType());
} else {
$fieldDescription->setType($type);
Expand All @@ -64,6 +88,7 @@ public function addField(FieldDescriptionCollection $list, $type, FieldDescripti
*/
public function fixFieldDescription(AdminInterface $admin, FieldDescriptionInterface $fieldDescription)
{
// NEXT_MAJOR: Remove this call.
$fieldDescription->setAdmin($admin);

// NEXT_MAJOR: Remove the following 2 lines.
Expand All @@ -72,7 +97,7 @@ public function fixFieldDescription(AdminInterface $admin, FieldDescriptionInter

// NEXT_MAJOR: Remove this block.
if ($modelManager->hasMetadata($admin->getClass(), 'sonata_deprecation_mute')) {
[$metadata, $lastPropertyName, $parentAssociationMappings] = $modelManager->getParentMetadataForProperty($admin->getClass(), $fieldDescription->getName());
[$metadata, $lastPropertyName, $parentAssociationMappings] = $modelManager->getParentMetadataForProperty($admin->getClass(), $fieldDescription->getName(), 'sonata_deprecation_mute');
$fieldDescription->setParentAssociationMappings($parentAssociationMappings);

// set the default field mapping
Expand Down
96 changes: 96 additions & 0 deletions src/FieldDescription/FieldDescriptionFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<?php

declare(strict_types=1);

/*
* This file is part of the Sonata Project package.
*
* (c) Thomas Rabaix <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Sonata\DoctrineMongoDBAdminBundle\FieldDescription;

use Doctrine\ODM\MongoDB\DocumentManager;
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
use Doctrine\Persistence\ManagerRegistry;
use Sonata\AdminBundle\Admin\FieldDescriptionInterface;
use Sonata\AdminBundle\FieldDescription\FieldDescriptionFactoryInterface;
use Sonata\DoctrineMongoDBAdminBundle\Admin\FieldDescription;

final class FieldDescriptionFactory implements FieldDescriptionFactoryInterface
{
/**
* @var ManagerRegistry
*/
private $registry;

public function __construct(ManagerRegistry $registry)
{
$this->registry = $registry;
}

public function create(string $class, string $name, array $options = []): FieldDescriptionInterface
{
if (!isset($options['route']['name'])) {
$options['route']['name'] = 'edit';
}

if (!isset($options['route']['parameters'])) {
$options['route']['parameters'] = [];
}

[$metadata, $propertyName, $parentAssociationMappings] = $this->getParentMetadataForProperty($class, $name);

return new FieldDescription(
$name,
$options,
$metadata->fieldMappings[$propertyName] ?? [],
$metadata->associationMappings[$propertyName] ?? [],
$parentAssociationMappings,
$propertyName
);
}

private function getParentMetadataForProperty(string $baseClass, string $propertyFullName): array
{
$nameElements = explode('.', $propertyFullName);
$lastPropertyName = array_pop($nameElements);
$class = $baseClass;
$parentAssociationMappings = [];

foreach ($nameElements as $nameElement) {
$metadata = $this->getMetadata($class);
$parentAssociationMappings[] = $metadata->associationMappings[$nameElement];
$class = $metadata->getAssociationTargetClass($nameElement);
}

return [$this->getMetadata($class), $lastPropertyName, $parentAssociationMappings];
}

/**
* @param class-string $class
*/
private function getMetadata(string $class): ClassMetadata
{
return $this->getDocumentManager($class)->getClassMetadata($class);
}

/**
* @param class-string $class
*
* @throw \RuntimeException
*/
private function getDocumentManager(string $class): DocumentManager
{
$dm = $this->registry->getManagerForClass($class);

if (!$dm instanceof DocumentManager) {
throw new \RuntimeException(sprintf('No document manager defined for class %s', $class));
}

return $dm;
}
}
Loading