Skip to content

Commit

Permalink
Deprecate using shortcut notation for user_model in favor of FQCN
Browse files Browse the repository at this point in the history
Instead of using shortcut notation for referring a user entity, now
we ask for the FQCN which allows us to not use a ManagerRegistry
dependency.
  • Loading branch information
franmomu authored and phansys committed Sep 26, 2020
1 parent 275e73a commit a3f119d
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 13 deletions.
5 changes: 5 additions & 0 deletions UPGRADE-3.x.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
UPGRADE 3.x
===========

### Deprecated using shortcut notation when specifying the `user_model` option in `sonata:admin:generate-object-acl` command.

The shortcut notation (`AppBundle:User`) has been deprecated in favor of the FQCN (`App\Model\User`) when passing
`user_model` option to `sonata:admin:generate-object-acl` command.

UPGRADE FROM 3.75 to 3.76
=========================

Expand Down
48 changes: 35 additions & 13 deletions src/Command/GenerateObjectAclCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\Question;
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
use Symfony\Component\Security\Acl\Domain\UserSecurityIdentity;

Expand Down Expand Up @@ -58,6 +59,8 @@ class GenerateObjectAclCommand extends QuestionableCommand
private $registry;

/**
* NEXT_MAJOR: Remove $registry argument.
*
* @param RegistryInterface|ManagerRegistry|null $registry
*/
public function __construct(Pool $pool, array $aclObjectManipulators, $registry = null)
Expand Down Expand Up @@ -94,7 +97,7 @@ public function configure()
->addOption('object_owner', null, InputOption::VALUE_OPTIONAL, 'If set, the task will set the object owner for each admin.')
// NEXT_MAJOR: Remove "user_entity" option.
->addOption('user_entity', null, InputOption::VALUE_OPTIONAL, '<error>DEPRECATED</error> Use <comment>user_model</comment> option instead.')
->addOption('user_model', null, InputOption::VALUE_OPTIONAL, 'Shortcut notation like <comment>AcmeDemoBundle:User</comment>. If not set, it will be asked the first time an object owner is set.')
->addOption('user_model', null, InputOption::VALUE_OPTIONAL, 'Fully qualified class name <comment>App\Model\User</comment>. If not set, it will be asked the first time an object owner is set.')
->addOption('step', null, InputOption::VALUE_NONE, 'If set, the task will ask for each admin if the ACLs need to be generated and what object owner to set, if any.')
;
}
Expand All @@ -107,7 +110,7 @@ public function execute(InputInterface $input, OutputInterface $output)
'This command helps you to generate ACL entities for the objects handled by the AdminBundle.',
'',
'If the step option is used, you will be asked if you want to generate the object ACL entities for each Admin.',
'You must use the shortcut notation like <comment>AcmeDemoBundle:User</comment> if you want to set an object owner.',
'You must use fully qualified class name like <comment>App\Model\User</comment> if you want to set an object owner.',
'',
]);

Expand Down Expand Up @@ -226,25 +229,44 @@ protected function getUserEntityClass(InputInterface $input, OutputInterface $ou

if ('' === $this->userEntityClass) {
if ($input->getOption('user_model')) {
[$userBundle, $userModel] = Validators::validateEntityName($input->getOption('user_model'));
$userModelFromInput = $input->getOption('user_model');
} else {
[$userBundle, $userModel] = $this->askAndValidate(
$userModelFromInput = $this->getQuestionHelper()->ask(
$input,
$output,
'Please enter the User Entity shortcut name: ',
'',
'Sonata\AdminBundle\Command\Validators::validateEntityName'
new Question('Please enter the User Model fully qualified class name: ', '')
);
}

// Entity exists?
if ($this->registry instanceof RegistryInterface) {
$namespace = $this->registry->getEntityNamespace($userBundle);
if (!class_exists($userModelFromInput)) {
// NEXT_MAJOR: Remove the trigger, uncomment the exception and remove the code below the exception
// until "else".
@trigger_error(sprintf(
'Passing a model shortcut name ("%s" given) as "user_model" option is deprecated since'
.' sonata-project/admin-bundle 3.x and will throw an exception in 4.x.'
.' Pass a fully qualified class name instead (e.g. App\Model\User).',
$userModelFromInput
), E_USER_DEPRECATED);

// throw new \InvalidArgumentException(sprintf(
// 'The "user_model" name be a fully qualified class name'
// .' ("%s" given, expecting something like App\Model\User)',
// $userModelFromInput
// ));

[$userBundle, $userModel] = Validators::validateEntityName($userModelFromInput);

// Model exists?
if ($this->registry instanceof RegistryInterface) {
$namespace = $this->registry->getEntityNamespace($userBundle);
} else {
$namespace = $this->registry->getAliasNamespace($userBundle);
}

$this->userEntityClass = sprintf('%s\%s', $namespace, $userModel);
} else {
$namespace = $this->registry->getAliasNamespace($userBundle);
$this->userEntityClass = $userModelFromInput;
}

$this->userEntityClass = sprintf('%s\%s', $namespace, $userModel);
}

return $this->userEntityClass;
Expand Down
1 change: 1 addition & 0 deletions src/Resources/config/commands.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
new ReferenceConfigurator('validator'),
])

// NEXT_MAJOR: Remove "doctrine" argument.
->set(GenerateObjectAclCommand::class, GenerateObjectAclCommand::class)
->public()
->tag('console.command')
Expand Down
79 changes: 79 additions & 0 deletions tests/Command/GenerateObjectAclCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use Sonata\AdminBundle\Admin\AbstractAdmin;
use Sonata\AdminBundle\Admin\Pool;
use Sonata\AdminBundle\Command\GenerateObjectAclCommand;
use Sonata\AdminBundle\Tests\Fixtures\Entity\Foo;
use Sonata\AdminBundle\Util\ObjectAclManipulatorInterface;
use Symfony\Bridge\Doctrine\RegistryInterface;
use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
Expand All @@ -26,6 +27,7 @@
use Symfony\Component\Console\Tester\CommandTester;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
use Symfony\Component\Security\Acl\Domain\UserSecurityIdentity;

/**
* @author Javier Spagnoletti <[email protected]>
Expand Down Expand Up @@ -203,4 +205,81 @@ public function testExecuteWithManipulator(): void
$commandTester = new CommandTester($command);
$commandTester->execute(['command' => $command->getName()]);
}

/**
* NEXT_MAJOR: Remove this test.
*
* @group legacy
*/
public function testExecuteWithDeprecatedUserModelNotation(): void
{
$pool = new Pool($this->container, '', '');

$registry = $this->createStub(ManagerRegistry::class);
$command = new GenerateObjectAclCommand($pool, [], $registry);

$application = new Application();
$application->add($command);

$command = $application->find(GenerateObjectAclCommand::getDefaultName());
$commandTester = new CommandTester($command);

$this->expectDeprecation(
'Passing a model shortcut name ("AppBundle:User" given) as "user_model" option is deprecated'
.' since sonata-project/admin-bundle 3.x and will throw an exception in 4.x.'
.' Pass a fully qualified class name instead (e.g. App\Model\User).'
);
$commandTester->execute([
'command' => $command->getName(),
'--user_model' => 'AppBundle:User',
]);
}

public function testExecuteWithUserModel(): void
{
$admin = $this->createStub(AbstractAdmin::class);
$registry = $this->createStub(ManagerRegistry::class);
$pool = $this->createStub(Pool::class);

$admin
->method('getManagerType')
->willReturn('bar');

$pool
->method('getAdminServiceIds')
->willReturn(['acme.admin.foo']);

$pool
->method('getInstance')
->willReturn($admin);

$manipulator = $this->createMock(ObjectAclManipulatorInterface::class);
$manipulator
->expects($this->once())
->method('batchConfigureAcls')
->with(
$this->isInstanceOf(StreamOutput::class),
$admin,
$this->callback(static function (UserSecurityIdentity $userSecurityIdentity): bool {
return Foo::class === $userSecurityIdentity->getClass();
})
);

$aclObjectManipulators = [
'sonata.admin.manipulator.acl.object.bar' => $manipulator,
];

$command = new GenerateObjectAclCommand($pool, $aclObjectManipulators, $registry);

$application = new Application();
$application->add($command);

$command = $application->find(GenerateObjectAclCommand::getDefaultName());
$commandTester = new CommandTester($command);
$commandTester->execute([
'command' => $command->getName(),
'--user_model' => Foo::class,
'--object_owner' => true,
]);
}
}

0 comments on commit a3f119d

Please sign in to comment.