So, what I ended up doing is extending the Page Manager PageAccessCheck service:
services:
custom_route_access.page_access_check:
class: Drupal\custom_route_access\Entity\PageAccessCheck
tags:
- { name: access_check, applies_to: _page_access }
And then:
<?php
namespace Drupal\custom_route_access\Entity;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Entity\EntityAccessCheck;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Session\AccountInterface;
use Symfony\Component\Routing\Route;
/**
* We're overriding the page access checks so that we can add our own.
* Mimics the generic entity access but with a custom key to prevent collisions.
*/
class PageAccessCheck extends EntityAccessCheck {
/**
* {@inheritdoc}
*/
public function access(Route $route, RouteMatchInterface $route_match, AccountInterface $account) {
// Backup the original requirements.
$original_requirements = $route->getRequirements();
// Replace it with our entity access value and run the parent access check.
$route->setRequirement('_entity_access', $route->getRequirement('_page_access'));
if($route->getPath() === '/project/{node}/take_attendance'){
return self::takeAttendanceAccess($account);
}
$access = parent::access($route, $route_match, $account);
// Restore the original requirements.
$route->setRequirements($original_requirements);
return $access;
}
/**
* Check that user is admin or staff OR has an active team leader registration.
*/
private static function takeAttendanceAccess($account){
// ... my custom access check code
}
}