Skip to content

Commit

Permalink
Merge pull request #64 from youvo/architecture
Browse files Browse the repository at this point in the history
Improve project event architecture
  • Loading branch information
simonbaese authored Dec 17, 2024
2 parents a9b055a + 52d0d44 commit c522aae
Show file tree
Hide file tree
Showing 50 changed files with 1,368 additions and 705 deletions.
3 changes: 2 additions & 1 deletion composer-manifest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ packages:
guzzlehttp/guzzle: 7.9.2
guzzlehttp/promises: 2.0.4
guzzlehttp/psr7: 2.7.0
jangregor/phpstan-prophecy: 1.0.2
joachim-n/composer-manifest: 1.1.6
justinrainbow/json-schema: 5.3.0
lcobucci/clock: 3.0.0
Expand Down Expand Up @@ -159,7 +160,7 @@ packages:
ramsey/collection: 2.0.0
ramsey/uuid: 4.7.6
react/promise: v3.2.0
roave/security-advisories: '9999999-dev:233f7c395ac3b83e3c85aa304f3350bf8897aca5'
roave/security-advisories: 'dev-latest:233f7c395ac3b83e3c85aa304f3350bf8897aca5'
sebastian/cli-parser: 1.0.2
sebastian/code-unit: 1.0.8
sebastian/code-unit-reverse-lookup: 2.0.3
Expand Down
5 changes: 3 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,6 @@
}
},
"require-dev": {
"roave/security-advisories": "dev-latest",
"dealerdirect/phpcodesniffer-composer-installer": "^0.7",
"drupal/admin_toolbar": "^3.3",
"drupal/coder": "^8.3",
Expand All @@ -143,12 +142,14 @@
"drupal/openapi_ui_redoc": "^1.0@RC",
"drupal/restui": "^1.21",
"fakerphp/faker": "^1.21",
"jangregor/phpstan-prophecy": "^1.0",
"mglaman/phpstan-drupal": "^1.1",
"phpcompatibility/php-compatibility": "^9.3",
"phpspec/prophecy-phpunit": "^2",
"phpstan/extension-installer": "^1.2",
"phpstan/phpstan": "^1.10",
"phpstan/phpstan-deprecation-rules": "^1.1"
"phpstan/phpstan-deprecation-rules": "^1.1",
"roave/security-advisories": "dev-latest"
},
"scripts": {
"post-drupal-scaffold-cmd": [
Expand Down
61 changes: 60 additions & 1 deletion composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion phpunit.ddev.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,15 @@
<listener class="\Drupal\Tests\Listeners\DrupalListener">
</listener>
</listeners>
<coverage>
<coverage includeUncoveredFiles="false">
<include>
<directory>web/modules/custom</directory>
</include>
<exclude>
<directory>web/modules/custom/*/src/Tests</directory>
<directory>web/modules/custom/*/tests</directory>
<directory>web/modules/custom/*/*/src/Tests</directory>
<directory>web/modules/custom/*/*/tests</directory>
</exclude>
</coverage>
</phpunit>
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
permission_callbacks:
- \Drupal\lifecycle\Permissions::getPermissions
- \Drupal\lifecycle\WorkflowPermissions::getPermissions
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

namespace Drupal\lifecycle\Exception;

/**
* An exception thrown when transitions fail.
*/
class LifecycleTransitionException extends \RuntimeException {

/**
* Constructs a new LifecycleTransitionException event.
*/
public function __construct(
protected string $transition,
string $message = '',
int $code = 0,
?\Throwable $previous = NULL,
) {
parent::__construct($message, $code, $previous);
}

/**
* Gets the failing transition.
*/
public function getTransition(): string {
return $this->transition;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\TypedData\DataDefinition;
use Drupal\Core\TypedData\OptionsProviderInterface;
use Drupal\lifecycle\Permissions;
use Drupal\lifecycle\WorkflowPermissions;
use Drupal\workflows\Entity\Workflow;
use Drupal\workflows\StateInterface;
use Drupal\workflows\WorkflowInterface;
Expand Down Expand Up @@ -154,7 +154,8 @@ public function getSettableOptions(?AccountInterface $account = NULL): array {
// If we have an account object then ensure the user has permission to
// this transition and that it's a valid transition.
$transition = $current_state->getTransitionTo($state->id());
return Permissions::useTransition($account, $workflow->id(), $transition);
$permission = WorkflowPermissions::useTransition($workflow->id(), $transition);
return $account->hasPermission($permission);
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\lifecycle\Permissions;
use Drupal\lifecycle\Plugin\Field\FieldType\LifecycleItem;
use Drupal\lifecycle\WorkflowPermissions;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
Expand Down Expand Up @@ -86,7 +86,8 @@ public function validate(mixed $value, Constraint $constraint): void {
}
else {
$transition = $workflow_type->getTransitionFromStateToState($originalState, $newState);
if (!Permissions::useTransition($this->currentUser, $value->getWorkflow()->id(), $transition)) {
$permission = WorkflowPermissions::useTransition($value->getWorkflow()->id(), $transition);
if (!$this->currentUser->hasPermission($permission)) {
$this->context->addViolation($constraint->insufficientPermissionsTransition, [
'%transition' => $transition->label(),
]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

namespace Drupal\lifecycle;

use Drupal\Core\Session\AccountInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\workflows\Entity\Workflow;
use Drupal\workflows\TransitionInterface;
Expand All @@ -14,7 +13,7 @@
*
* @internal
*/
class Permissions {
class WorkflowPermissions {

use StringTranslationTrait;

Expand Down Expand Up @@ -46,21 +45,32 @@ public function getPermissions(): array {
}

/**
* Determines whether a user can use a transition.
* Determines permission for a workflow transition.
*
* @param \Drupal\Core\Session\AccountInterface $account
* The user accounts.
* @param string $workflowId
* @param string $workflow_id
* The workflow the transition belongs to.
* @param \Drupal\workflows\TransitionInterface|string $transition
* The transition or the transition ID.
*
* @return bool
* Whether the user can use the transition.
* @return string
* The matching workflow permission.
*/
public static function useTransition(AccountInterface $account, string $workflowId, TransitionInterface|string $transition): bool {
public static function useTransition(string $workflow_id, TransitionInterface|string $transition): string {
$transition_id = $transition instanceof TransitionInterface ? $transition->id() : $transition;
return $account->hasPermission(sprintf('use %s transition %s', $workflowId, $transition_id));
return sprintf('use %s transition %s', $workflow_id, $transition_id);
}

/**
* Determines permission to bypass a workflow transition.
*
* @param string $workflow_id
* The workflow the transition belongs to.
*
* @return string
* The matching workflow permission.
*/
public static function bypassTransition(string $workflow_id): string {
return sprintf('bypass %s transition access', $workflow_id);
}

}
22 changes: 6 additions & 16 deletions web/modules/custom/projects/projects/projects.routing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,21 @@ entity.project.settings:
requirements:
_permission: 'administer projects'

# Project Apply REST route is defined in ProjectApplyResource::routes.
# Transition REST routes are defined in ProjectTransitionRestResourceRoutesTrait::routes.
# REST routes inherit the transition default, _custom_access requirement
# and parameters option.
# The converter has to be set as paramconverter.uuid to resolve REST
# requests with UUIDs correctly.
# @todo Adjust access for project transition forms.
project.submit:
path: '/projects/{project}/submit'
defaults:
_form: '\Drupal\projects\Form\ProjectSubmitForm'
_title: 'Submit Project'
transition: 'submit'
requirements:
_custom_access: '\Drupal\projects\Access\ProjectTransitionAccess::accessTransition'
_permission: 'administer projects'
project: \d+
options:
_admin_route: TRUE
parameters:
project:
type: entity:project
converter: paramconverter.uuid

project.publish:
path: '/projects/{project}/publish'
Expand All @@ -35,14 +29,13 @@ project.publish:
_title: 'Publish Project'
transition: 'publish'
requirements:
_custom_access: '\Drupal\projects\Access\ProjectTransitionAccess::accessTransition'
_permission: 'administer projects'
project: \d+
options:
_admin_route: TRUE
parameters:
project:
type: entity:project
converter: paramconverter.uuid

project.mediate:
path: '/projects/{project}/mediate'
Expand All @@ -51,14 +44,13 @@ project.mediate:
_title: 'Mediate Project'
transition: 'mediate'
requirements:
_custom_access: '\Drupal\projects\Access\ProjectTransitionAccess::accessTransition'
_permission: 'administer projects'
project: \d+
options:
_admin_route: TRUE
parameters:
project:
type: entity:project
converter: paramconverter.uuid

project.complete:
path: '/projects/{project}/complete'
Expand All @@ -67,14 +59,13 @@ project.complete:
_title: 'Complete Project'
transition: 'complete'
requirements:
_custom_access: '\Drupal\projects\Access\ProjectTransitionAccess::accessTransition'
_permission: 'administer projects'
project: \d+
options:
_admin_route: TRUE
parameters:
project:
type: entity:project
converter: paramconverter.uuid

project.reset:
path: '/projects/{project}/reset'
Expand All @@ -83,11 +74,10 @@ project.reset:
_title: 'Reset Project'
transition: 'reset'
requirements:
_custom_access: '\Drupal\projects\Access\ProjectTransitionAccess::accessTransition'
_permission: 'administer projects'
project: \d+
options:
_admin_route: TRUE
parameters:
project:
type: entity:project
converter: paramconverter.uuid
24 changes: 23 additions & 1 deletion web/modules/custom/projects/projects/projects.services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ services:
tags:
- { name: event_subscriber }
project.lifecycle:
class: Drupal\projects\ProjectLifecycle
class: Drupal\projects\Service\ProjectLifecycle
arguments:
[ '@entity_type.manager' ]
project.route_subscriber:
Expand All @@ -22,3 +22,25 @@ services:
logger.channel.projects:
parent: logger.channel_base
arguments: [ 'projects' ]

# Project transition event subscribers.
projects.project_complete.event_subscriber:
class: Drupal\projects\EventSubscriber\Transition\ProjectCompleteSubscriber
tags:
- { name: event_subscriber }
projects.project_mediate.event_subscriber:
class: Drupal\projects\EventSubscriber\Transition\ProjectMediateSubscriber
tags:
- { name: event_subscriber }
projects.project_publish.event_subscriber:
class: Drupal\projects\EventSubscriber\Transition\ProjectPublishSubscriber
tags:
- { name: event_subscriber }
projects.project_reset.event_subscriber:
class: Drupal\projects\EventSubscriber\Transition\ProjectResetSubscriber
tags:
- { name: event_subscriber }
projects.project_submit.event_subscriber:
class: Drupal\projects\EventSubscriber\Transition\ProjectSubmitSubscriber
tags:
- { name: event_subscriber }
Loading

0 comments on commit c522aae

Please sign in to comment.