Skip to content

Commit

Permalink
Use PropertyAccess to populate model and deprecate camelize
Browse files Browse the repository at this point in the history
  • Loading branch information
franmomu authored and jordisala1991 committed Jul 26, 2020
1 parent 1d19ff6 commit b382c81
Show file tree
Hide file tree
Showing 6 changed files with 175 additions and 74 deletions.
6 changes: 6 additions & 0 deletions UPGRADE-3.x.md
Expand Up @@ -4,6 +4,12 @@ UPGRADE 3.x
UPGRADE FROM 3.x to 3.x
=======================

### Sonata\DoctrineMongoDBAdminBundle\Model\ModelManager

Deprecated `camelize()` method.

Deprecated not passing an instance of `PropertyAccessInterface` as second argument in the constructor.

### Sonata\DoctrineMongoDBAdminBundle\Admin\FieldDescription

Deprecated `getTargetEntity()`, use `getTargetModel()` instead.
Expand Down
1 change: 1 addition & 0 deletions composer.json
Expand Up @@ -36,6 +36,7 @@
"symfony/doctrine-bridge": "^4.4",
"symfony/form": "^4.4",
"symfony/http-kernel": "^4.4",
"symfony/property-access": "^4.4",
"twig/twig": "^2.6"
},
"provide": {
Expand Down
93 changes: 60 additions & 33 deletions src/Model/ModelManager.php
Expand Up @@ -14,7 +14,9 @@
namespace Sonata\DoctrineMongoDBAdminBundle\Model;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Persistence\Mapping\ClassMetadata as CommonClassMetadata;
use Doctrine\ODM\MongoDB\Query\Builder;
use Doctrine\Persistence\Mapping\ClassMetadata;
use Sonata\AdminBundle\Admin\FieldDescriptionInterface;
use Sonata\AdminBundle\Datagrid\DatagridInterface;
use Sonata\AdminBundle\Datagrid\ProxyQueryInterface;
Expand All @@ -23,15 +25,44 @@
use Sonata\DoctrineMongoDBAdminBundle\Datagrid\ProxyQuery;
use Sonata\Exporter\Source\DoctrineODMQuerySourceIterator;
use Symfony\Bridge\Doctrine\ManagerRegistry;
use Symfony\Component\PropertyAccess\PropertyAccess;
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;

class ModelManager implements ModelManagerInterface
{
public const ID_SEPARATOR = '-';

/**
* @var ManagerRegistry
*/
protected $registry;

public function __construct(ManagerRegistry $registry)
/**
* @var PropertyAccessorInterface
*/
private $propertyAccessor;

/**
* NEXT_MAJOR: Make $propertyAccessor mandatory.
*/
public function __construct(ManagerRegistry $registry, ?PropertyAccessorInterface $propertyAccessor = null)
{
$this->registry = $registry;

// NEXT_MAJOR: Remove this block.
if (!$propertyAccessor instanceof PropertyAccessorInterface) {
@trigger_error(sprintf(
'Not passing an object implementing "%s" as argument 2 for "%s()" is deprecated since'
.' sonata-project/doctrine-mongodb-admin-bundle 3.x and will throw a %s error in 4.0.',
PropertyAccessorInterface::class,
__METHOD__,
\TypeError::class
), E_USER_DEPRECATED);

$propertyAccessor = PropertyAccess::createPropertyAccessor();
}

$this->propertyAccessor = $propertyAccessor;
}

/**
Expand Down Expand Up @@ -452,39 +483,10 @@ public function modelReverseTransform($class, array $array = [])
$instance = $this->getModelInstance($class);
$metadata = $this->getMetadata($class);

$reflClass = $metadata->reflClass;
foreach ($array as $name => $value) {
$reflection_property = false;
// property or association ?
if (\array_key_exists($name, $metadata->fieldMappings)) {
$property = $metadata->fieldMappings[$name]['fieldName'];
$reflection_property = $metadata->reflFields[$name];
} elseif (\array_key_exists($name, $metadata->associationMappings)) {
$property = $metadata->associationMappings[$name]['fieldName'];
} else {
$property = $name;
}
$property = $this->getFieldName($metadata, $name);

$setter = 'set'.$this->camelize($name);

if ($reflClass->hasMethod($setter)) {
if (!$reflClass->getMethod($setter)->isPublic()) {
throw new \BadMethodCallException(sprintf('Method "%s()" is not public in class "%s"', $setter, $reflClass->getName()));
}

$instance->$setter($value);
} elseif ($reflClass->hasMethod('__set')) {
// needed to support magic method __set
$instance->$property = $value;
} elseif ($reflClass->hasProperty($property)) {
if (!$reflClass->getProperty($property)->isPublic()) {
throw new \BadMethodCallException(sprintf('Property "%s" is not public in class "%s". Maybe you should create the method "set%s()"?', $property, $reflClass->getName(), ucfirst($property)));
}

$instance->$property = $value;
} elseif ($reflection_property) {
$reflection_property->setValue($instance, $value);
}
$this->propertyAccessor->setValue($instance, $property, $value);
}

return $instance;
Expand Down Expand Up @@ -531,17 +533,42 @@ public function collectionRemoveElement(&$collection, &$element)
}

/**
* method taken from PropertyPath.
* NEXT_MAJOR: Remove this method.
*
* @deprecated since sonata-project/doctrine-mongodb-admin-bundle 3.x, to be removed in 4.0.'.
*
* @param string $property
*
* @return mixed
*/
protected function camelize($property)
{
@trigger_error(sprintf(
'Method "%s()" is deprecated since sonata-project/doctrine-mongodb-admin-bundle 3.x and will be removed in version 4.0.',
__METHOD__
), E_USER_DEPRECATED);

return str_replace(' ', '', ucwords(str_replace('_', ' ', $property)));
}

/**
* NEXT_MAJOR: Remove CommonClassMetadata and add ClassMetadata as type hint when dropping doctrine/mongodb-odm 1.3.x.
*
* @param ClassMetadata|CommonClassMetadata $metadata
*/
private function getFieldName($metadata, string $name): string
{
if (\array_key_exists($name, $metadata->fieldMappings)) {
return $metadata->fieldMappings[$name]['fieldName'];
}

if (\array_key_exists($name, $metadata->associationMappings)) {
return $metadata->associationMappings[$name]['fieldName'];
}

return $name;
}

private function isFieldAlreadySorted(FieldDescriptionInterface $fieldDescription, DatagridInterface $datagrid): bool
{
$values = $datagrid->getValues();
Expand Down
1 change: 1 addition & 0 deletions src/Resources/config/doctrine_mongodb.xml
Expand Up @@ -3,6 +3,7 @@
<services>
<service id="sonata.admin.manager.doctrine_mongodb" class="Sonata\DoctrineMongoDBAdminBundle\Model\ModelManager">
<argument type="service" id="doctrine_mongodb" on-invalid="ignore"/>
<argument type="service" id="property_accessor"/>
<tag name="sonata.admin.manager"/>
</service>
<!-- FormBuilder -->
Expand Down
34 changes: 34 additions & 0 deletions tests/Fixtures/Document/SimpleDocumentWithPrivateSetter.php
@@ -0,0 +1,34 @@
<?php

declare(strict_types=1);

/*
* This file is part of the Sonata Project package.
*
* (c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Sonata\DoctrineMongoDBAdminBundle\Tests\Fixtures\Document;

final class SimpleDocumentWithPrivateSetter
{
private $schmeckles;

public function __construct(int $schmeckles)
{
$this->setSchmeckles($schmeckles);
}

public function getSchmeckles(): int
{
return $this->schmeckles;
}

private function setSchmeckles($value): void
{
$this->schmeckles = $value;
}
}

0 comments on commit b382c81

Please sign in to comment.