Problem/Motivation
When you write a routing.yml file with a _custom_access check which points to a non existing method/class you get the following message:
InvalidArgumentException: The controller for URI "" is not callable. in Drupal\Core\Controller\ControllerResolver->getControllerFromDefinition() (line 81 of core/lib/Drupal/Core/Controller/ControllerResolver.php).
Drupal\Core\Access\CustomAccessCheck->access(Object, Object, Object)
call_user_func_array(Array, Array)
Drupal\Core\Access\AccessManager->performCheck('access_check.custom', Object)
Drupal\Core\Access\AccessManager->checkAll(Array, Object)
Drupal\Core\Access\AccessManager->check(Object, Object, Object, )
Drupal\Core\Access\AccessManager->checkRequest(Object, Object)
Drupal\Core\Routing\AccessAwareRouter->checkAccess(Object)
Drupal\Core\Routing\AccessAwareRo
Its not helpful
Proposed resolution
CustomAccessCheck should catch the InvalidArgumentException and convert it into a new exception
which explains which route / custom access check exactly is broken
Remaining tasks
User interface changes
API changes
Comments
Comment #3
dawehnerThis should be a php-novice task.
Comment #4
philipnorton42 commentedComment #5
philipnorton42 commentedI have added a \BadMethodCallException here, which is still part of the SPL library and seems to make sense in this context. This now produces a the following message when this situation is encountered:
Comment #6
philipnorton42 commentedComment #7
philipnorton42 commentedI did try to create a test for this particular exception being thrown, but due to the way in which the objects are mocked the exceptions are not produced when running under the testing environment. As a result I'm not sure this can be tested correctly in this instance.
For what it's worth here is the code I created for this:
Comment #8
dawehnerI'm wondering whether we should have a test for that.
Comment #9
philipnorton42 commentedJust realised that the original patch didn't follow Drupal coding standards. So I'm applying those standards in an updated patch :)
Comment #10
dawehnerA small test would still be nice
Comment #11
philipnorton42 commentedNot a problem. I will put something together soon and post it back :)
Comment #12
philipnorton42 commentedComment #13
philipnorton42 commentedOk, so I've had a go at writing the test for this. In order to properly simulate the conditions of the test I had to create the CustomAccessCheck object (i.e. instead of Mocking it). There is therefore quite a bit of object creation, but at least I was able to Mock some of the objects used in this process.
Attached is the patch containing the code change and the passing test :)
Comment #14
dawehnerA small suggestion: Move the setExpectedException right before the access call. This makes the overall test easier to read.
Comment #15
philipnorton42 commentedYeah, that makes sense to me. Corrected :)
Comment #16
dawehnerCool, thank you!
Comment #17
jibranFixed some cs issues. Moving it to 8.3.x so that it can be back ported after stable release of 8.2.x
Comment #19
jibranSeems like unrelated
Comment #22
ivan berezhnov commentedComment #24
rakesh.gectcrComment #25
philipnorton42 commentedRe-rolled the patch against Drupal 8.6.x-dev.
Also replaced the static object creation in the test class with mocking and added some comments to the class so that it was clear what was going on.
Comment #26
philipnorton42 commentedUploading a new version of the patch file with the file suffix of ".patch" in order to trigger the Drupal unit testing bot.
Comment #27
andrewmacpherson commented@philipnorton42 - patches just want a
.patchextension, not.patch.txt, otherwise the test bots don't pick it up. (EDIT: snap, we both posted in the same minute.)Can you upload a patch without the .txt extension, increment the comment number in the patch name, and set it back to needs-review? Then the test-bots will do their thing.
Also, it would be good to provide an interdiff between this and the earlier patch makes it easy to see how it is progressing. So we're looking for an interdiff-2405241-17-26.txt, say.
Review of patch 25:
+ $controllerResolver = $this->getMockBuilder(\Drupal\Core\DependencyInjection\ClassResolverInterface::class)->getMock();We already have a
use \Drupal\Core\DependencyInjection\ClassResolverInterface;, so do we need to pass the fully-qualified name here?+ $this->controllerResolver = $this->getMockBuilder(\Drupal\Core\Controller\ControllerResolver::class)We already have a
use \Drupal\Core\Controller\ControllerResolver;, so do we need to pass the fully-qualified name here?+use Symfony\Bridge\PsrHttpMessage\Factory\DiactorosFactory;Where's this being used? I don't see it being used by any of the new code added by this patch.
+use Symfony\Component\DependencyInjection\ContainerBuilder;Where's this being used? I don't see it being used by any of the new code added by this patch.
NonExistantController::nonexistantmethodThis is a real nitpick, but shouldn't this be
NonExistentController::nonExistentMethod- spelling "existent", and camel-case for method name.The comment is a bit redundant, we can understand this from the method name.
The test only checks what exception class we get. Should we check the error message formatting too?
Comment #28
philipnorton42 commentedThanks very much for the guidance Andrew, really appreciate it!
I'd spotted the .patch thing literally minutes before you commented on it, but I've sorted that as well.
Comment #29
dawehnerI'm curious, whether we could / should leverage https://github.com/symfony/debug/blob/122391f69203b96b0c92b4a4b58c89ed99... to provide a better error message.
Comment #30
philipnorton42 commentedPotentially. Using UndefinedFunctionFatalErrorHandler::handleError looks like a nice approach, but we would need to move the symfony/debug library from require-dev into require in the composer.json file. Would that have implications in other parts of Drupal?
I can see only one instance of this component actually being used in Drupal and that is in the testing class EntityReferenceSettingsTest.
Comment #31
dawehnerThat's a good point. Maybe it is worth exploring this in a follow up.
Comment #32
alexpottcredited @dawehner and @andrewmacpherson for reviews.
Comment #33
alexpottCommitted 7c1de1e and pushed to 8.6.x. Thanks!
Coding standards fixed on commit.