Skip to content

Commit

Permalink
Improve the way we append parent object if any (#6171)
Browse files Browse the repository at this point in the history
  • Loading branch information
VincentLanglet authored Jul 13, 2020
1 parent 54122f5 commit 77c7c68
Show file tree
Hide file tree
Showing 16 changed files with 563 additions and 482 deletions.
15 changes: 15 additions & 0 deletions UPGRADE-3.x.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
UPGRADE 3.x
===========

## Deprecated `SonataAdminBundle\Admin\AdminHelper::addNewInstance()`

Use
```
$instance = $fieldDescription->getAssociationAdmin()->getNewInstance();
SonataAdminBundle\Admin\AdminHelper::addInstance($object, $fieldDescription, $instance);
```
Instead of
```
$this->adminHelper->addNewInstance($object, $fieldDescription);
```

The static method `addInstance()` avoids the need to inject the admin helper dependency,
and adds more flexibility with the instance you're adding to the object.

UPGRADE FROM 3.68 to 3.69
=========================

Expand Down
56 changes: 36 additions & 20 deletions src/Admin/AbstractAdmin.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
use Sonata\AdminBundle\Filter\Persister\FilterPersisterInterface;
use Sonata\AdminBundle\Form\FormMapper;
use Sonata\AdminBundle\Form\Type\ModelHiddenType;
use Sonata\AdminBundle\Manipulator\ObjectManipulator;
use Sonata\AdminBundle\Model\ModelManagerInterface;
use Sonata\AdminBundle\Object\Metadata;
use Sonata\AdminBundle\Route\RouteCollection;
Expand Down Expand Up @@ -1365,6 +1366,9 @@ public function getTemplate($name)
public function getNewInstance()
{
$object = $this->getModelManager()->getModelInstance($this->getClass());

$this->appendParentObject($object);

foreach ($this->getExtensions() as $extension) {
$extension->alterNewInstance($this, $object);
}
Expand Down Expand Up @@ -3382,26 +3386,6 @@ protected function buildForm()

$this->loaded['form'] = true;

// append parent object if any
// todo : clean the way the Admin class can retrieve set the object
if ($this->isChild() && $this->getParentAssociationMapping()) {
$parent = $this->getParent()->getObject($this->request->get($this->getParent()->getIdParameter()));

$propertyAccessor = $this->getConfigurationPool()->getPropertyAccessor();
$propertyPath = new PropertyPath($this->getParentAssociationMapping());

$object = $this->getSubject();

$value = $propertyAccessor->getValue($object, $propertyPath);

if (\is_array($value) || $value instanceof \ArrayAccess) {
$value[] = $parent;
$propertyAccessor->setValue($object, $propertyPath, $value);
} else {
$propertyAccessor->setValue($object, $propertyPath, $parent);
}
}

$formBuilder = $this->getFormBuilder();
$formBuilder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) {
$this->preValidate($event->getData());
Expand Down Expand Up @@ -3531,6 +3515,38 @@ protected function configureDefaultSortValues(array &$sortValues)
{
}

/**
* Set the parent object, if any, to the provided object.
*/
final protected function appendParentObject(object $object): void
{
if ($this->isChild() && $this->getParentAssociationMapping()) {
$parentAdmin = $this->getParent();
$parentObject = $parentAdmin->getObject($this->request->get($parentAdmin->getIdParameter()));

if (null !== $parentObject) {
$propertyAccessor = $this->getConfigurationPool()->getPropertyAccessor();
$propertyPath = new PropertyPath($this->getParentAssociationMapping());

$value = $propertyAccessor->getValue($object, $propertyPath);

if (\is_array($value) || $value instanceof \ArrayAccess) {
$value[] = $parentObject;
$propertyAccessor->setValue($object, $propertyPath, $value);
} else {
$propertyAccessor->setValue($object, $propertyPath, $parentObject);
}
}
} elseif ($this->hasParentFieldDescription()) {
$parentAdmin = $this->getParentFieldDescription()->getAdmin();
$parentObject = $parentAdmin->getObject($this->request->get($parentAdmin->getIdParameter()));

if (null !== $parentObject) {
ObjectManipulator::setObject($object, $parentObject, $this->getParentFieldDescription());
}
}
}

/**
* Build all the related urls to the current admin.
*/
Expand Down
66 changes: 17 additions & 49 deletions src/Admin/AdminHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@
namespace Sonata\AdminBundle\Admin;

use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Util\ClassUtils;
use Doctrine\Inflector\Inflector;
use Doctrine\Inflector\InflectorFactory;
use Doctrine\ODM\MongoDB\PersistentCollection;
use Doctrine\ORM\PersistentCollection as DoctrinePersistentCollection;
use Sonata\AdminBundle\Exception\NoValueException;
use Sonata\AdminBundle\Manipulator\ObjectManipulator;
use Sonata\AdminBundle\Util\FormBuilderIterator;
use Sonata\AdminBundle\Util\FormViewIterator;
use Symfony\Component\Form\FormBuilderInterface;
Expand Down Expand Up @@ -180,16 +180,17 @@ public function appendFormFieldElement(AdminInterface $admin, $subject, $element
$objectCount = null === $value ? 0 : \count($value);
$postCount = \count($data[$childFormBuilder->getName()]);

$associationAdmin = $fieldDescription->getAssociationAdmin();

// add new elements to the subject
while ($objectCount < $postCount) {
// append a new instance into the object
$this->addNewInstance($form->getData(), $fieldDescription);
ObjectManipulator::addInstance($form->getData(), $associationAdmin->getNewInstance(), $fieldDescription);
++$objectCount;
}

$newInstance = $this->addNewInstance($form->getData(), $fieldDescription);
$newInstance = ObjectManipulator::addInstance($form->getData(), $associationAdmin->getNewInstance(), $fieldDescription);

$associationAdmin = $fieldDescription->getAssociationAdmin();
$associationAdmin->setSubject($newInstance);
}

Expand All @@ -214,6 +215,10 @@ public function appendFormFieldElement(AdminInterface $admin, $subject, $element
}

/**
* NEXT_MAJOR: remove this method.
*
* @deprecated since sonata-project/admin-bundle 3.x, use to be removed with 4.0.
*
* Add a new instance to the related FieldDescriptionInterface value.
*
* @param object $object
Expand All @@ -224,53 +229,16 @@ public function appendFormFieldElement(AdminInterface $admin, $subject, $element
*/
public function addNewInstance($object, FieldDescriptionInterface $fieldDescription)
{
$instance = $fieldDescription->getAssociationAdmin()->getNewInstance();
$mapping = $fieldDescription->getAssociationMapping();
$parentMappings = $fieldDescription->getParentAssociationMappings();

$inflector = InflectorFactory::create()->build();

foreach ($parentMappings as $parentMapping) {
$method = sprintf('get%s', $inflector->classify($parentMapping['fieldName']));

if (!(\is_callable([$object, $method]) && method_exists($object, $method))) {
/*
* NEXT_MAJOR: Use BadMethodCallException instead
*/
throw new \RuntimeException(sprintf(
'Method %s::%s() does not exist.',
ClassUtils::getClass($object),
$method
));
}

$object = $object->$method();
}

$method = sprintf('add%s', $inflector->classify($mapping['fieldName']));

if (!(\is_callable([$object, $method]) && method_exists($object, $method))) {
$method = rtrim($method, 's');

if (!(\is_callable([$object, $method]) && method_exists($object, $method))) {
$method = sprintf('add%s', $inflector->classify($inflector->singularize($mapping['fieldName'])));

if (!(\is_callable([$object, $method]) && method_exists($object, $method))) {
/*
* NEXT_MAJOR: Use BadMethodCallException instead
*/
throw new \RuntimeException(sprintf(
'Method %s::%s() does not exist.',
ClassUtils::getClass($object),
$method
));
}
}
}
@trigger_error(sprintf(
'Method %s() is deprecated since sonata-project/admin-bundle 3.x. It will be removed in version 4.0.'
.' Use %s::addInstance() instead.',
__METHOD__,
ObjectManipulator::class
), E_USER_DEPRECATED);

$object->$method($instance);
$instance = $fieldDescription->getAssociationAdmin()->getNewInstance();

return $instance;
return ObjectManipulator::addInstance($object, $instance, $fieldDescription);
}

/**
Expand Down
22 changes: 10 additions & 12 deletions src/Form/Type/AdminType.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use Sonata\AdminBundle\Admin\AdminInterface;
use Sonata\AdminBundle\Admin\FieldDescriptionInterface;
use Sonata\AdminBundle\Form\DataTransformer\ArrayToModelTransformer;
use Sonata\AdminBundle\Manipulator\ObjectManipulator;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\FormBuilderInterface;
Expand All @@ -36,22 +37,22 @@
class AdminType extends AbstractType
{
/**
* @var AdminHelper
* NEXT_MAJOR: Remove this property.
*
* @var AdminHelper|null
*/
private $adminHelper;

/**
* NEXT_MAJOR: Allow only `AdminHelper` for argument 1 and remove the default null value.
* NEXT_MAJOR: Remove the __construct method.
*/
public function __construct(?AdminHelper $adminHelper = null)
{
// NEXT_MAJOR: Remove this condition.
if (null === $adminHelper) {
if (null !== $adminHelper) {
@trigger_error(sprintf(
'Calling %s without passing an %s as argument is deprecated since sonata-project/admin-bundle 3.66'
.' and will throw an exception in 4.0.',
__METHOD__,
AdminHelper::class
'Passing argument 1 to %s() is deprecated since sonata-project/admin-bundle 3.x'
.' and will be ignored in version 4.0.',
__METHOD__
), E_USER_DEPRECATED);
}

Expand Down Expand Up @@ -107,10 +108,7 @@ static function (array $associationMapping): string {
$subject = $p->getValue($parentSubject, $parentPath.$path);
} catch (NoSuchIndexException $e) {
// no object here, we create a new one
// NEXT_MAJOR: Remove the null check.
if (null !== $this->adminHelper) {
$subject = $this->adminHelper->addNewInstance($parentSubject, $parentFieldDescription);
}
$subject = ObjectManipulator::setObject($admin->getNewInstance(), $parentSubject, $parentFieldDescription);
}
}
}
Expand Down
Loading

0 comments on commit 77c7c68

Please sign in to comment.