Skip to content

Commit

Permalink
Merge branch 'master' into feature/BB-22791
Browse files Browse the repository at this point in the history
  • Loading branch information
ValeriyYustunyk committed Dec 3, 2024
2 parents 1b086b3 + 346ca20 commit 2f1000e
Show file tree
Hide file tree
Showing 209 changed files with 8,564 additions and 1,111 deletions.
166 changes: 166 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,100 @@ The current file describes significant changes in the code that may affect the u

### Changed

#### ActionBundle

##### Operations

- added ability to define operation logic as a service instead of having it in YAML
- Added `OperationServiceInterface` and `OperationServiceAbstract` for operation services
- added new tag `oro_operation_service` to gather operation services in a separate service locator
- updated OperationAssembler and Operation to work with services
- Moved acl_resource check to the announce event listener instead of constantly adding it to pre-conditions
- Moved operation feature availability check to the announce event listener instead of constantly adding it to pre-conditions

###### Operation Events

Operation execution events added for better extensibility and control of operation execution flow

- `announce` event is triggered during checking pre-conditions
- `guard` event is triggered during checking conditions
- `pre_execute` and `execute` events are triggered before and after operation logic execution

For all event types 2 events are triggered: `oro_operation.<event_name>` and `oro_operation.<operation_name>.<event_name>`.

##### Action Group Changes

* Added `ActionExecutor` to be able to run actions and action groups from PHP code without a need to work with ActionData, context, PropertyPaths, etc.
* Added `ActionGroupWrapper` to be able to call a service method as an action group. All such services should be added to service locator with tag `oro_action_group_service`. If service needs to add/change some context variables it has to return an array with an appropriate keys. Note that argument names are used to map data from context to method arguments and must be named same to call parameters.
* Moved logic from action groups YAML definitions to PHP services for checkout-related action_groups
* Added ability to define action group as a service + method config parameters
* added `return_value_name` for `action_group` to map value to action group result correctly for action group services
* added `method_argument_name` to parameter config to map action group parameter to service method argument
* Moved `acl_resource` check to the guard event listener instead of constantly adding it to pre-conditions (this check was lost for service-based action_groups)
* Action group execution events added for better extensibility and control of execution flow

* `guard` event is triggered during checking conditions
*`pre_execute` and `execute` events are triggered before and after operation logic execution

For all event types 2 events are triggered. `oro_action_group.<event_name>` and `oro_action_group.<operation_name>.<event_name>`

#### WorkflowBundle

* added `conditional_steps_to` to allow to transit workflow to different steps with single transition based on condition per-step
* `conditional_steps_to` are shown in workflow UI
* Improved workflow config importing, allowed to reference files in bundles with `@BundleName/path/to/configs/workflow.yml` syntax

##### Transition services

* added ability to define transition logic as a transition service instead of having it in YAML transition_definition
* Added `TransitionServiceInterface` and `TransitionServiceAbstract` for transition services
* added new tag `oro_workflow.transition_service` to gather transition services in a separate service locator
* updated `TransitionAssembler`, Transition and Workflow configuration to work with transition services
* implemented `ContinueToShippingAddress` for b2b checkout workflow as a transition service example
* added evaluateExpression to ActionExecutor service to cover whole transition needs: run an action, action group, evaluate condition expression
* Improved QuoteAcceptable condition to support default as a property path

##### Workflow Events

Added workflow events
* `pre_announce`, `announce`. These events are triggered during checking pre-conditions
* `pre_guard`, `guard`. These events are triggered during checking conditions

Next event are triggered during transition execution:
* `start` (workflow)
* `leave` (step)
* `enter` (step)
* `entered` (step)
* `transition` (transition)
* `completed` (transition)

For all events except start 3 events are triggered. `oro_workflow.<event_name>`, `oro_workflow.<workflow_name>.<event_name>` and `oro_workflow.<workflow_name>.<event_name>.<step_name|transition_name>`

##### Workflow ACL checks

* Moved `acl_resource` check to pre_announce event listener instead of constantly adding it to pre-conditions
* Moved `is_granted_workflow_transition` check for steps to pre_announce event listener
* Moved `resolve_destination_page` from actions to oro_workflow.transition listener for all workflows to support usage of this option with transition_service
* ResolveDestinationPage was updated to support destination as variable in workflows
* `aclResource` and `aclMessages` were added to Transition model

##### Workflow Definition Load CLI command

* Added `--watch` and `--watch-interval` options to `oro:workflow:definition:load` command to periodically reload the workflow definition(s). Can be used during development to not bother the developer who might forget to reload the definition.

##### ExtendableCondition and ExtendableAction changes

* removed dependency on WorkflowItem/ActionData in listeners which limited those listeners to a place from which event is triggered (workflow definition or action group)
* extracted extendable condition errors processing to a separate service to not depend on the translator and request stack directly
* added ability to trigger checkout events directly using event dispatcher without a need to use extendable action|condition
* introduced determined set of data available in listeners, access to current execution context was limited in order to remove untraceable dependencies on the inner workflow implementations and improve listeners re-usability

##### Configuration import directive filters

* Added `import_condition` (Expression Language syntax same to on used in DI) option for workflow import
* Added import filters that may be registered via `WorkflowConfigurationImportsProcessor::addImportFilter` and should implement the `ImportFilterInterface`


#### ThemeBundle
* Changed a field value of the `type` field on a string instead of the removed `\Oro\Bundle\ThemeBundle\Entity\Enum\ThemeConfigurationType` enum for `\Oro\Bundle\ThemeBundle\Entity\ThemeConfiguration` entity.

Expand All @@ -58,6 +152,78 @@ The current file describes significant changes in the code that may affect the u
- changed return value for `getAll` method from `array [filter key => FilterValue, ...]` to `array [filter key => [FilterValue, ...], ...]`
* Outdated format of API filters like `filter[id]>=1` is not supported from now, use `filter[field][operator]=value` syntax instead, e.g. `filter[id][gte]=1`.

#### ActionBundle

##### Action Group Changes

* Added ActionExecutor to be able to run actions and action groups from PHP code without a need to work with ActionData, context, PropertyPaths, etc.
* Added ActionGroupWrapper to be able to call a service method as an action group. All such services should be added to service locator with tag oro_action_group_service. If service needs to add/change some context variables it has to return an array with an appropriate keys. Note that argument names are used to map data from context to method arguments and must be named same to call parameters.
* Moved logic from action groups YAML definitions to PHP services for checkout-related action_groups
* Added ability to define action group as a service + method config parameters
* Added `return_value_name` for action_group to map value to action group result correctly for action group services
* Added `method_argument_name` to parameter config to map action group parameter to service method argument

#### WorkflowBundle

* Added `conditional_steps_to` to allow to transit workflow to different steps with single transition based on condition per-step
* `conditional_steps_to` are shown in workflow UI
* Improved workflow config importing, allowed to reference files in bundles with `@BundleName/path/to/configs/workflow.yml` syntax
* Disallowed to transit workflow in pre-conditions or pre-actions.

##### Transition services

* Added ability to define transition logic as a transition service instead of having it in YAML transition_definition
* Added TransitionServiceInterface and TransitionServiceAbstract for transition services
* Added new tag oro_workflow.transition_service to gather transition services in a separate service locator
* Updated TransitionAssembler, Transition and Workflow configuration to work with transition services
* Implemented ContinueToShippingAddress for b2b checkout workflow as a transition service example
* Added evaluateExpression to ActionExecutor service to cover whole transition needs: run an action, action group, evaluate condition expression
* Improved QuoteAcceptable condition to support default as a property path

##### Workflow Events

Added workflow events
* pre_announce, announce. These event are triggered during checking pre-conditions
* pre_guard, guard. These event are triggered during checking pre-conditions

Next event are triggered during transition execution:
* start (workflow)
* leave (step)
* enter (step)
* entered (step)
* transition (transition)
* completed (transition)

For all events except start 3 events are triggered. oro_workflow.<event_name>, oro_workflow.<workflow_name>.<event_name> and oro_workflow.<workflow_name>.<event_name>.<step_name|transition_name>

##### Workflow ACL checks

* Moved `acl_resource` check to pre_announce event listener instead of constantly adding it to pre-conditions. After this change, `acl_resource` checks will be done *before* pre-actions. It's no longer possible to reference variables in `acl_resource`, such checks must be moved to pre-conditions.
* Moved `is_granted_workflow_transition` check for steps to `pre_announce` event listener
* Moved `resolve_destination_page` from actions to `oro_workflow.transition` listener for all workflows to support usage of this option with transition_service
* `ResolveDestinationPage` was updated to support destination as variable in workflows
* `aclResource` and `aclMessages` were added to Transition model

##### Workflow Definition Load CLI command

* Added `--watch` and `--watch-interval` options to `oro:workflow:definition:load` command to periodically reload the workflow definition(s). Can be used during development to not bother the developer who might forget to reload the definition.

##### ExtendableCondition and ExtendableAction changes

* ExtendableCondition does not work directly with context, accepting only the data needed for event listeners.
* ExtendableConditionEvent `getContext` replaced by `getData`. It's no longer possible to work directly with the workflow/action execution context.
* ExtendableAction does not work directly with context, accepting only the data needed for event listeners.
* ExtendableActionEvent `getContext` replaced by `getData`. It's no longer possible to work directly with the workflow/action execution context.
* Introduced determined set of data available in listeners, access to current execution context was limited in order to remove untraceable dependencies on the inner workflow implementations and improve listeners re-usability
* Removed dependency on WorkflowItem/ActionData in listeners which limited those listeners to a place from which event is triggered (workflow definition or action group)
* Extracted extendable condition errors processing to a separate service to not depend on the translator and request stack directly
* Added ability to trigger checkout events directly using event dispatcher without a need to use extendable action|condition

##### Configuration import directive filters

* Added `import_condition` (Expression Language syntax same to on used in DI) option for workflow import
* Added import filters that may be registered via `WorkflowConfigurationImportsProcessor::addImportFilter` and should implement the `ImportFilterInterface`

#### EntityBundle
* Changed `\Oro\Bundle\EntityBundle\Provider\EntityNameProvider` to make it work with enum fields.

Expand Down
44 changes: 44 additions & 0 deletions src/Oro/Bundle/ActionBundle/Configuration/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ public function getConfigTreeBuilder(): TreeBuilder
return $treeBuilder;
}

/**
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
protected function appendActionGroups(NodeBuilder $builder)
{
$builder->arrayNode('action_groups')
Expand Down Expand Up @@ -58,6 +61,13 @@ protected function appendActionGroups(NodeBuilder $builder)
->end()
->validate()
->always(function ($config) {
if (!empty($value['service']) && (!empty($value['actions']) || !empty($value['conditions']))) {
throw new \Exception(
'Conditions and actions are not allowed to be used when "service" is configured ' .
'for action_group'
);
}

if (!empty($config['return_value_name']) && empty($config['service'])) {
throw new \Exception(
'"return_value_name" can be used only with "service" parameter'
Expand All @@ -81,6 +91,9 @@ protected function appendActionGroups(NodeBuilder $builder)
->end();
}

/**
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
*/
protected function appendOperations(NodeBuilder $builder)
{
$children = $builder
Expand All @@ -90,6 +103,7 @@ protected function appendOperations(NodeBuilder $builder)
->children();

$children
->scalarNode('service')->end()
->arrayNode('replace')
->beforeNormalization()
->always(
Expand Down Expand Up @@ -147,6 +161,36 @@ function ($replace) {
->append($this->getFrontendOptionsNode())
->append($this->getDatagridOptionsNode())
->append($this->getFormOptionsNode())
->end()
->validate()
->always(function ($value) {
if (!empty($value['service'])
&& (
!empty($value[OperationDefinition::PRECONDITIONS])
|| !empty($value[OperationDefinition::PREACTIONS])
|| !empty($value[OperationDefinition::CONDITIONS])
|| !empty($value[OperationDefinition::ACTIONS])
)
) {
throw new \Exception(
sprintf(
'Individual logical sections %s are not allowed when "service" is configured',
implode(
', ',
[
OperationDefinition::PRECONDITIONS,
OperationDefinition::PREACTIONS,
OperationDefinition::CONDITIONS,
OperationDefinition::ACTIONS,
]
)
)
);
}

return $value;
})
->end()
->end();

$this->appendActionsNodes($children);
Expand Down
36 changes: 36 additions & 0 deletions src/Oro/Bundle/ActionBundle/Event/ActionDataAwareEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

namespace Oro\Bundle\ActionBundle\Event;

use Doctrine\Common\Collections\Collection;
use Oro\Bundle\ActionBundle\Model\ActionData;
use Symfony\Contracts\EventDispatcher\Event;

/**
* Action Bundle event containing ActionData entity.
*/
abstract class ActionDataAwareEvent extends Event
{
public function __construct(
private ActionData $actionData,
private ?Collection $errors = null
) {
}

abstract public function getName(): string;

public function getActionData(): ActionData
{
return $this->actionData;
}

public function setActionData(ActionData $actionData): void
{
$this->actionData = $actionData;
}

public function getErrors(): ?Collection
{
return $this->errors;
}
}
26 changes: 26 additions & 0 deletions src/Oro/Bundle/ActionBundle/Event/ActionGroupEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

namespace Oro\Bundle\ActionBundle\Event;

use Doctrine\Common\Collections\Collection;
use Oro\Bundle\ActionBundle\Model\ActionData;
use Oro\Bundle\ActionBundle\Model\ActionGroupDefinition;

/**
* Action Bundle event containing ActionData and ActionGroupDefinition.
*/
abstract class ActionGroupEvent extends ActionDataAwareEvent
{
public function __construct(
ActionData $actionData,
private ActionGroupDefinition $actionGroupDefinition,
?Collection $errors = null
) {
parent::__construct($actionData, $errors);
}

public function getActionGroupDefinition(): ActionGroupDefinition
{
return $this->actionGroupDefinition;
}
}
31 changes: 31 additions & 0 deletions src/Oro/Bundle/ActionBundle/Event/ActionGroupEventDispatcher.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

namespace Oro\Bundle\ActionBundle\Event;

use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;

/**
* Event dispatcher wrapper for action groups to dispatch a set of related events.
*/
class ActionGroupEventDispatcher
{
private const EVENT_PREFIX = 'oro_action_group';

public function __construct(
private EventDispatcherInterface $eventDispatcher
) {
}

public function dispatch(
ActionGroupEvent $event
): void {
$eventName = $event->getName();
$this->eventDispatcher->dispatch($event, sprintf('%s.%s', static::EVENT_PREFIX, $eventName));

$actionGroupName = $event->getActionGroupDefinition()->getName();
$this->eventDispatcher->dispatch(
$event,
sprintf('%s.%s.%s', static::EVENT_PREFIX, $actionGroupName, $eventName)
);
}
}
14 changes: 14 additions & 0 deletions src/Oro/Bundle/ActionBundle/Event/ActionGroupExecuteEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

namespace Oro\Bundle\ActionBundle\Event;

/**
* Action group event that is triggered after the execution.
*/
final class ActionGroupExecuteEvent extends ActionGroupEvent
{
public function getName(): string
{
return 'execute';
}
}
27 changes: 27 additions & 0 deletions src/Oro/Bundle/ActionBundle/Event/ActionGroupGuardEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

namespace Oro\Bundle\ActionBundle\Event;

/**
* Action Group guard event used to disallow availability/execution.
*/
class ActionGroupGuardEvent extends ActionGroupEvent
{
private bool $allowed = true;

#[\Override]
public function getName(): string
{
return 'guard';
}

public function setAllowed(bool $allowed): void
{
$this->allowed = $allowed;
}

public function isAllowed(): bool
{
return $this->allowed;
}
}
Loading

0 comments on commit 2f1000e

Please sign in to comment.