From 2afc10f1477ce0f7a800c12a27c80d8eefb90509 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frank=20Bru=CC=88ckner?= Date: Sat, 24 Apr 2021 20:51:06 +0200 Subject: [PATCH] Adds delegator to set ACL for helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The delegator allows the setting a ACL for navigation helpers by using a registered `Laminas\Permissions\Acl\AclInterface` service. Signed-off-by: Frank Brückner --- src/View/PermissionAclDelegatorFactory.php | 57 +++++++ .../PermissionAclDelegatorFactoryTest.php | 155 ++++++++++++++++++ 2 files changed, 212 insertions(+) create mode 100644 src/View/PermissionAclDelegatorFactory.php create mode 100644 test/View/PermissionAclDelegatorFactoryTest.php diff --git a/src/View/PermissionAclDelegatorFactory.php b/src/View/PermissionAclDelegatorFactory.php new file mode 100644 index 00000000..ace67bca --- /dev/null +++ b/src/View/PermissionAclDelegatorFactory.php @@ -0,0 +1,57 @@ +aclName = $aclName; + } + + public static function __set_state(array $state): self + { + return new self($state['aclName'] ?? AclInterface::class); + } + + public function __invoke( + ContainerInterface $container, + string $name, + callable $callback, + array $options = null + ) { + /** @var AbstractHelper|mixed $instance */ + $helper = $callback(); + + if (! $helper instanceof AbstractHelper) { + return $helper; + } + if (! $container->has($this->aclName)) { + return $helper; + } + + $acl = $container->get($this->aclName); + if (! $acl instanceof AclInterface) { + return $helper; + } + + $helper->setAcl($acl); + + return $helper; + } +} diff --git a/test/View/PermissionAclDelegatorFactoryTest.php b/test/View/PermissionAclDelegatorFactoryTest.php new file mode 100644 index 00000000..50aaf857 --- /dev/null +++ b/test/View/PermissionAclDelegatorFactoryTest.php @@ -0,0 +1,155 @@ +createMock(ContainerInterface::class); + $container->expects($this->once()) + ->method('has') + ->with(AclInterface::class) + ->willReturn(true); + $container->expects($this->once()) + ->method('get') + ->with(AclInterface::class) + ->willReturn($this->createMock(AclInterface::class)); + + /** @var Navigation $result */ + $result = (new PermissionAclDelegatorFactory())( + $container, + 'name', + static function () { + return new Navigation(); + } + ); + + $this->assertInstanceOf( + AclInterface::class, + $result->getAcl() + ); + } + + public function testAclWithCustomNameShouldBeSetForHelper(): void + { + $customName = 'alternate-acl'; + + $container = $this->createMock(ContainerInterface::class); + $container->expects($this->once()) + ->method('has') + ->with($customName) + ->willReturn(true); + $container->expects($this->once()) + ->method('get') + ->with($customName) + ->willReturn($this->createMock(AclInterface::class)); + + /** @var Navigation $result */ + $result = (new PermissionAclDelegatorFactory($customName))( + $container, + 'name', + static function () { + return new Navigation(); + } + ); + + $this->assertInstanceOf( + AclInterface::class, + $result->getAcl() + ); + } + + public function testNoneNavigationHelperPassedAsGiven(): void + { + $class = new stdClass(); + + /** @var Navigation $result */ + $result = (new PermissionAclDelegatorFactory())( + $this->createMock(ContainerInterface::class), + 'name', + static function () use ($class) { + return $class; + } + ); + + $this->assertSame($class, $result); + } + + public function testNoneExistingAclWillHelperPassedAsGiven(): void + { + $container = $this->createMock(ContainerInterface::class); + $container->expects($this->once()) + ->method('has') + ->with(AclInterface::class) + ->willReturn(false); + + /** @var Navigation $result */ + $result = (new PermissionAclDelegatorFactory())( + $container, + 'name', + static function () { + return new Navigation(); + } + ); + + $this->assertNull($result->getAcl()); + } + + public function testWrongAclWillHelperPassedAsGiven(): void + { + $container = $this->createMock(ContainerInterface::class); + $container->expects($this->once()) + ->method('has') + ->with(AclInterface::class) + ->willReturn(true); + $container->expects($this->once()) + ->method('get') + ->with(AclInterface::class) + ->willReturn(null); + + /** @var Navigation $result */ + $result = (new PermissionAclDelegatorFactory())( + $container, + 'name', + static function () { + return new Navigation(); + } + ); + + $this->assertNull($result->getAcl()); + } + + public function testMagicMethodSetStateShouldContainAclClassName(): void + { + $this->assertStringContainsString( + 'Laminas\\\Permissions\\\Acl\\\AclInterface', + var_export(new PermissionAclDelegatorFactory(), true) + ); + } + + public function testMagicMethodSetStateShouldContainCustomNameIfSet(): void + { + $customName = 'alternate-name'; + + $this->assertStringContainsString( + $customName, + var_export(new PermissionAclDelegatorFactory($customName), true) + ); + } +}