@@ -30,7 +30,7 @@ public static function setUpBeforeClass(): void
3030
3131 protected function tearDown (): void
3232 {
33- ClassExistsMock::withMockedClasses ([FieldVote::class => true ]);
33+ ClassExistsMock::withMockedClasses ([FieldVote::class => true , AccessDecision::class => true ]);
3434 }
3535
3636 #[DataProvider('provideObjectFieldAclCases ' )]
@@ -115,6 +115,122 @@ public function testIsGrantedForUserThrowsWhenFieldNotNullAndFieldVoteClassDoesN
115115 $ securityExtension ->isGrantedForUser ($ this ->createMock (UserInterface::class), 'ROLE ' , 'object ' , 'bar ' );
116116 }
117117
118+ public function testAccessDecision ()
119+ {
120+ if (!class_exists (AccessDecision::class)) {
121+ $ this ->markTestSkipped ('This test requires symfony/security-core 7.3 or superior. ' );
122+ }
123+
124+ $ securityChecker = $ this ->createMock (AuthorizationCheckerInterface::class);
125+ $ securityChecker
126+ ->expects ($ this ->once ())
127+ ->method ('isGranted ' )
128+ ->with ('ROLE ' , 'object ' , $ this ->isInstanceOf (AccessDecision::class))
129+ ->willReturnCallback (function ($ attribute , $ subject , $ accessDecision ) {
130+ $ accessDecision ->isGranted = true ;
131+
132+ return true ;
133+ });
134+
135+ $ securityExtension = new SecurityExtension ($ securityChecker );
136+ $ accessDecision = $ securityExtension ->getAccessDecision ('ROLE ' , 'object ' );
137+
138+ $ this ->assertInstanceOf (AccessDecision::class, $ accessDecision );
139+ $ this ->assertTrue ($ accessDecision ->isGranted );
140+ }
141+
142+ public function testAccessDecisionWithField ()
143+ {
144+ if (!class_exists (AccessDecision::class)) {
145+ $ this ->markTestSkipped ('This test requires symfony/security-core 7.3 or superior. ' );
146+ }
147+
148+ $ securityChecker = $ this ->createMock (AuthorizationCheckerInterface::class);
149+ $ securityChecker
150+ ->expects ($ this ->once ())
151+ ->method ('isGranted ' )
152+ ->with ('ROLE ' , $ this ->isInstanceOf (FieldVote::class), $ this ->isInstanceOf (AccessDecision::class))
153+ ->willReturnCallback (function ($ attribute , $ subject , $ accessDecision ) {
154+ $ accessDecision ->isGranted = false ;
155+
156+ return false ;
157+ });
158+
159+ $ securityExtension = new SecurityExtension ($ securityChecker );
160+ $ accessDecision = $ securityExtension ->getAccessDecision ('ROLE ' , 'object ' , 'field ' );
161+
162+ $ this ->assertInstanceOf (AccessDecision::class, $ accessDecision );
163+ $ this ->assertFalse ($ accessDecision ->isGranted );
164+ }
165+
166+ public function testAccessDecisionThrowsWhenAccessDecisionClassDoesNotExist ()
167+ {
168+ ClassExistsMock::withMockedClasses ([AccessDecision::class => false ]);
169+
170+ $ securityChecker = $ this ->createMock (AuthorizationCheckerInterface::class);
171+
172+ $ this ->expectException (\LogicException::class);
173+ $ this ->expectExceptionMessage ('Using the "access_decision()" function requires symfony/security-core >= 7.3. Try running "composer update symfony/security-core". ' );
174+
175+ $ securityExtension = new SecurityExtension ($ securityChecker );
176+ $ securityExtension ->getAccessDecision ('ROLE ' , 'object ' );
177+ }
178+
179+ public function testAccessDecisionForUser ()
180+ {
181+ if (!interface_exists (UserAuthorizationCheckerInterface::class) || !class_exists (AccessDecision::class)) {
182+ $ this ->markTestSkipped ('This test requires symfony/security-core 7.3 or superior. ' );
183+ }
184+
185+ $ user = $ this ->createMock (UserInterface::class);
186+ $ securityChecker = $ this ->createMockAuthorizationChecker ();
187+
188+ $ securityExtension = new SecurityExtension ($ securityChecker );
189+ $ accessDecision = $ securityExtension ->getAccessDecisionForUser ($ user , 'ROLE ' , 'object ' );
190+
191+ $ this ->assertInstanceOf (AccessDecision::class, $ accessDecision );
192+ $ this ->assertTrue ($ accessDecision ->isGranted );
193+ $ this ->assertSame ($ user , $ securityChecker ->user );
194+ $ this ->assertSame ('ROLE ' , $ securityChecker ->attribute );
195+ $ this ->assertSame ('object ' , $ securityChecker ->subject );
196+ }
197+
198+ public function testAccessDecisionForUserWithField ()
199+ {
200+ if (!interface_exists (UserAuthorizationCheckerInterface::class) || !class_exists (AccessDecision::class)) {
201+ $ this ->markTestSkipped ('This test requires symfony/security-core 7.3 or superior. ' );
202+ }
203+
204+ $ user = $ this ->createMock (UserInterface::class);
205+ $ securityChecker = $ this ->createMockAuthorizationChecker ();
206+
207+ $ securityExtension = new SecurityExtension ($ securityChecker );
208+ $ accessDecision = $ securityExtension ->getAccessDecisionForUser ($ user , 'ROLE ' , 'object ' , 'field ' );
209+
210+ $ this ->assertInstanceOf (AccessDecision::class, $ accessDecision );
211+ $ this ->assertTrue ($ accessDecision ->isGranted );
212+ $ this ->assertSame ($ user , $ securityChecker ->user );
213+ $ this ->assertSame ('ROLE ' , $ securityChecker ->attribute );
214+ $ this ->assertEquals (new FieldVote ('object ' , 'field ' ), $ securityChecker ->subject );
215+ }
216+
217+ public function testAccessDecisionForUserThrowsWhenAccessDecisionClassDoesNotExist ()
218+ {
219+ if (!interface_exists (UserAuthorizationCheckerInterface::class)) {
220+ $ this ->markTestSkipped ('This test requires symfony/security-core 7.3 or superior. ' );
221+ }
222+
223+ ClassExistsMock::withMockedClasses ([AccessDecision::class => false ]);
224+
225+ $ securityChecker = $ this ->createMockAuthorizationChecker ();
226+ $ securityExtension = new SecurityExtension ($ securityChecker );
227+
228+ $ this ->expectException (\LogicException::class);
229+ $ this ->expectExceptionMessage ('Using the "access_decision_for_user()" function requires symfony/security-core >= 7.3. Try running "composer update symfony/security-core". ' );
230+
231+ $ securityExtension ->getAccessDecisionForUser ($ this ->createMock (UserInterface::class), 'ROLE ' , 'object ' );
232+ }
233+
118234 private function createMockAuthorizationChecker (): AuthorizationCheckerInterface &UserAuthorizationCheckerInterface
119235 {
120236 return new class implements AuthorizationCheckerInterface, UserAuthorizationCheckerInterface {
@@ -133,6 +249,10 @@ public function isGrantedForUser(UserInterface $user, mixed $attribute, mixed $s
133249 $ this ->attribute = $ attribute ;
134250 $ this ->subject = $ subject ;
135251
252+ if ($ accessDecision ) {
253+ $ accessDecision ->isGranted = true ;
254+ }
255+
136256 return true ;
137257 }
138258 };
0 commit comments