Skip to content

Commit

Permalink
Workflow notifications (#4904)
Browse files Browse the repository at this point in the history
* fixed #4361 - [Workflows] Add notification option for Pimcore notification system

* fixed #128 - [DataObjects] DataQuality reports - docs

* Coding Standards Fixer Bot

* [Document] Support for Folders & Links as a Fallback Document (#4860)

* [Document] Support for folders & links as a fallback document

* [DOCS] added docs for #4860

* add a check in ElementListener for PageSnippet, otherwise this can lead to exceptions under certain conditions
  • Loading branch information
fashxp committed Aug 29, 2019
1 parent 89b9a7b commit fd36e47
Show file tree
Hide file tree
Showing 12 changed files with 281 additions and 105 deletions.
20 changes: 15 additions & 5 deletions bundles/CoreBundle/DependencyInjection/Configuration.php
Expand Up @@ -20,8 +20,8 @@
use Pimcore\Targeting\Storage\CookieStorage;
use Pimcore\Targeting\Storage\TargetingStorageInterface;
use Pimcore\Workflow\EventSubscriber\ChangePublishedStateSubscriber;
use Pimcore\Workflow\EventSubscriber\NotificationEmailSubscriber;
use Pimcore\Workflow\NotificationEmail\NotificationEmailService;
use Pimcore\Workflow\EventSubscriber\NotificationSubscriber;
use Pimcore\Workflow\Notification\NotificationEmailService;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
Expand Down Expand Up @@ -1597,13 +1597,23 @@ private function addWorkflowNode(ArrayNodeDefinition $rootNode)
->end()
->info('Send a email notification to a list of user roles (role names) when the transition get\'s applied')
->end()
->arrayNode('channelType')
->requiresAtLeastOneElement()
->enumPrototype()
->values([NotificationSubscriber::NOTIFICATION_CHANNEL_MAIL, NotificationSubscriber::NOTIFICATION_CHANNEL_PIMCORE_NOTIFICATION])
->cannotBeEmpty()
->defaultValue(NotificationSubscriber::NOTIFICATION_CHANNEL_MAIL)
->end()
->info('Define which channel notification should be sent to, possible values "' . NotificationSubscriber::NOTIFICATION_CHANNEL_MAIL . '" and "' . NotificationSubscriber::NOTIFICATION_CHANNEL_PIMCORE_NOTIFICATION . '", default value is "' . NotificationSubscriber::NOTIFICATION_CHANNEL_MAIL . '".')
->addDefaultChildrenIfNoneSet()
->end()
->enumNode('mailType')
->values([NotificationEmailSubscriber::MAIL_TYPE_TEMPLATE, NotificationEmailSubscriber::MAIL_TYPE_DOCUMENT])
->defaultValue(NotificationEmailSubscriber::MAIL_TYPE_TEMPLATE)
->values([NotificationSubscriber::MAIL_TYPE_TEMPLATE, NotificationSubscriber::MAIL_TYPE_DOCUMENT])
->defaultValue(NotificationSubscriber::MAIL_TYPE_TEMPLATE)
->info('Type of mail source.')
->end()
->scalarNode('mailPath')
->defaultValue(NotificationEmailSubscriber::DEFAULT_MAIL_TEMPLATE_PATH)
->defaultValue(NotificationSubscriber::DEFAULT_MAIL_TEMPLATE_PATH)
->info('Path to mail source - either Symfony path to template or fullpath to Pimcore document. Optional use ' . NotificationEmailService::MAIL_PATH_LANGUAGE_PLACEHOLDER . ' as placeholder for language.')
->end()
->end()
Expand Down
6 changes: 4 additions & 2 deletions bundles/CoreBundle/Resources/config/services_workflow.yml
Expand Up @@ -10,9 +10,11 @@ services:
Pimcore\Workflow\Place\StatusInfo:
public: true

Pimcore\Workflow\NotificationEmail\NotificationEmailService:
Pimcore\Workflow\Notification\NotificationEmailService:
public: true

Pimcore\Workflow\Notification\PimcoreNotificationService:

workflow.marking_store.state_table:
class: Pimcore\Workflow\MarkingStore\StateTableMarkingStore
abstract: true
Expand Down Expand Up @@ -43,7 +45,7 @@ services:
- '@validator'
public: true

Pimcore\Workflow\EventSubscriber\NotificationEmailSubscriber: ~
Pimcore\Workflow\EventSubscriber\NotificationSubscriber: ~

Pimcore\Workflow\EventSubscriber\NotesSubscriber: ~

Expand Down
Expand Up @@ -238,6 +238,13 @@ pimcore:
# Send a email notification to a list of user roles (role names) when the transition get's applied
notifyRoles: []

# Define which channel notification should be sent to, possible values "mail" and "pimcore_notification", default value is "mail".
channelType:

# Default:
- mail


# Type of mail source.
mailType: template # One of "template"; "pimcore_document"

Expand Down
14 changes: 10 additions & 4 deletions doc/Development_Documentation/07_Workflow_Management/README.md
Expand Up @@ -59,10 +59,11 @@ see [Working with PHP API](./09_Working_with_PHP_API.md).


## User Notifications
Email notifications can be configured to be sent to users when an transition takes place. To do this simply specify an
array of user(s) or role(s) that you would like to be notified in options section of the transition definition.
Notifications (via email or Pimcore notifications) can be configured to be sent to users when an transition takes place.
To do this simply specify an array of user(s) or role(s) that you would like to be notified in options section of the
transition definition.

Roles will send an email to every user with that role.
Roles will send an notification to every user with that role.

```yml
...
Expand All @@ -80,6 +81,11 @@ Roles will send an email to every user with that role.
# Send a email notification to a list of user roles (role names) when the transition get's applied
notifyRoles: ['projectmanagers', 'admins']

# Define which channel notification should be sent to, possible values "mail" and "pimcore_notification", default value is "mail".
channelType:
- mail
- pimcoreNotification

# Type of mail source.
mailType: 'template' # this is the default value, One of "template"; "pimcore_document"

Expand All @@ -94,7 +100,7 @@ To customize the e-mail template, following options are available:
- Overwrite the template `@PimcoreCore/Workflow/NotificationEmail/notificationEmail.html.twig` or configure your own
template path in settings. Default parameters available in the template are `subjectType`, `subject`, `action`, `workflow`,
`workflowName`, `deeplink`, `note_description`, `translator`, `lang`. If additional parameters are required, overwrite
the service `Pimcore\Workflow\NotificationEmail\NotificationEmailService`.
the service `Pimcore\Workflow\Notification\NotificationEmailService`.

- Configure a Pimcore Mail Document and use full power of Pimcore Mail Documents, with Controller, Action, Placeholders,
etc. In the mail document same parameters as above are available.
Expand Down
Expand Up @@ -3,6 +3,12 @@
## 6.2.0
- Support for links and folders as a fallback document, details see [#4860](https://github.com/pimcore/pimcore/pull/4860)

### Workflow Refactorings
- Notifications for workflows now support Pimcore notifications. Due to that, some namespaces
were renamed. If you don't have overwritten any of the internal classes, no action is needed.
- `Pimcore\Workflow\EventSubscriber\NotificationEmailSubscriber` became `Pimcore\Workflow\EventSubscriber\NotificationSubscriber`
- `Pimcore\Workflow\NotificationEmail\NotificationEmailInterface` became `Pimcore\Workflow\NotificationEmail\NotificationInterface`


## 6.1.2
- Sessions: the native PHP session mechanism is now the default (instead of `session.handler.native_file`).
Expand Down
Expand Up @@ -18,60 +18,69 @@
use Pimcore\Model\Element\Service;
use Pimcore\Model\Element\ValidationException;
use Pimcore\Workflow;
use Pimcore\Workflow\NotificationEmail\NotificationEmailService;
use Pimcore\Workflow\Notification\NotificationEmailService;
use Pimcore\Workflow\Transition;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Workflow\Event\Event;
use Symfony\Contracts\Translation\TranslatorInterface;

class NotificationEmailSubscriber implements EventSubscriberInterface
class NotificationSubscriber implements EventSubscriberInterface
{
const MAIL_TYPE_TEMPLATE = 'template';
const MAIL_TYPE_DOCUMENT = 'pimcore_document';

const NOTIFICATION_CHANNEL_MAIL = 'mail';
const NOTIFICATION_CHANNEL_PIMCORE_NOTIFICATION = 'pimcore_notification';

const DEFAULT_MAIL_TEMPLATE_PATH = '@PimcoreCore/Workflow/NotificationEmail/notificationEmail.html.twig';

/**
* @var TranslatorInterface
* @var NotificationEmailService
*/
protected $mailService;

/**
* @var Workflow\NotificationEmail\PimcoreNotificationService
*/
private $mailService;
protected $pimcoreNotificationService;

/**
* @var TranslatorInterface
*/
private $translator;
protected $translator;

/**
* @var bool
*/
private $enabled = true;
protected $enabled = true;

/**
* @var Workflow\ExpressionService
*/
private $expressionService;
protected $expressionService;

/**
* @var Workflow\Manager
*/
private $workflowManager;
protected $workflowManager;

/**
* NotificationEmailSubscriber constructor.
*
* @param NotificationEmailService $mailService
* @param Workflow\NotificationEmail\PimcoreNotificationService $pimcoreNotificationService
* @param TranslatorInterface $translator
* @param Workflow\ExpressionService $expressionService
* @param Workflow\Manager $manager
* @param Workflow\Manager $workflowManager
*/
public function __construct(NotificationEmailService $mailService, TranslatorInterface $translator, Workflow\ExpressionService $expressionService, Workflow\Manager $manager)
public function __construct(NotificationEmailService $mailService, Workflow\NotificationEmail\PimcoreNotificationService $pimcoreNotificationService, TranslatorInterface $translator, Workflow\ExpressionService $expressionService, Workflow\Manager $workflowManager)
{
$this->mailService = $mailService;
$this->pimcoreNotificationService = $pimcoreNotificationService;
$this->translator = $translator;
$this->expressionService = $expressionService;
$this->workflowManager = $manager;
$this->workflowManager = $workflowManager;
}


/**
* @param Event $event
*
Expand Down Expand Up @@ -99,7 +108,14 @@ public function onWorkflowCompleted(Event $event)
$notifyUsers = $notificationSetting['notifyUsers'] ?? [];
$notifyRoles = $notificationSetting['notifyRoles'] ?? [];

$this->handleNotifyPostWorkflow($transition, $workflow, $subject, $notificationSetting['mailType'], $notificationSetting['mailPath'], $notifyUsers, $notifyRoles);
if (in_array(self::NOTIFICATION_CHANNEL_MAIL, $notificationSetting['channelType'])) {
$this->handleNotifyPostWorkflowEmail($transition, $workflow, $subject, $notificationSetting['mailType'], $notificationSetting['mailPath'], $notifyUsers, $notifyRoles);
}

if (in_array(self::NOTIFICATION_CHANNEL_PIMCORE_NOTIFICATION, $notificationSetting['channelType'])) {
$this->handleNotifyPostWorkflowPimcoreNotification($transition, $workflow, $subject, $notifyUsers, $notifyRoles);
}

}
}
}
Expand All @@ -111,7 +127,7 @@ public function onWorkflowCompleted(Event $event)
* @param string $mailType
* @param string $mailPath
*/
private function handleNotifyPostWorkflow(Transition $transition, \Symfony\Component\Workflow\Workflow $workflow, AbstractElement $subject, string $mailType, string $mailPath, array $notifyUsers, array $notifyRoles)
private function handleNotifyPostWorkflowEmail(Transition $transition, \Symfony\Component\Workflow\Workflow $workflow, AbstractElement $subject, string $mailType, string $mailPath, array $notifyUsers, array $notifyRoles)
{
//notify users
$subjectType = (Service::getType($subject) == 'object' ? $subject->getClassName() : Service::getType($subject));
Expand All @@ -128,6 +144,20 @@ private function handleNotifyPostWorkflow(Transition $transition, \Symfony\Compo
);
}

private function handleNotifyPostWorkflowPimcoreNotification(Transition $transition, \Symfony\Component\Workflow\Workflow $workflow, AbstractElement $subject, array $notifyUsers, array $notifyRoles)
{
$subjectType = (Service::getType($subject) == 'object' ? $subject->getClassName() : Service::getType($subject));
$this->pimcoreNotificationService->sendPimcoreNotification(
$notifyUsers,
$notifyRoles,
$workflow,
$subjectType,
$subject,
$transition->getLabel()
);

}

/**
* check's if the event subscriber should be executed
*
Expand Down
92 changes: 92 additions & 0 deletions lib/Workflow/Notification/AbstractNotificationService.php
@@ -0,0 +1,92 @@
<?php
/**
* Pimcore
*
* This source file is available under two different licenses:
* - GNU General Public License version 3 (GPLv3)
* - Pimcore Enterprise License (PEL)
* Full copyright and license information is available in
* LICENSE.md which is distributed with this source code.
*
* @copyright Copyright (c) Pimcore GmbH (http://www.pimcore.org)
* @license http://www.pimcore.org/license GPLv3 and PEL
*/

namespace Pimcore\Workflow\Notification;

use Pimcore\Model\Element\Note;
use Pimcore\Model\User;


class AbstractNotificationService
{
protected function getNoteInfo($id): string
{
$noteList = new Note\Listing();
$noteList->addConditionParam('(cid = ?)', [$id]);
$noteList->setOrderKey('date');
$noteList->setOrder('desc');
$noteList->setLimit(1);

$notes = $noteList->load();

if (count($notes) == 1) {
// found matching note
return $notes[0]->getDescription();
}

return '';
}

/**
* Returns a list of distinct users given an user- and role array containing their respective names
*
* @param $users
* @param $roles
*
* @return User[][]
*/
protected function getNotificationUsersByName($users, $roles, $includeAllUsers = false): array
{
$notifyUsers = [];

//get roles
$roleList = new User\Role\Listing();
$roleList->setCondition('FIND_IN_SET(name, ?)', [implode(',', $roles)]);

foreach ($roleList->load() as $role) {
$userList = new User\Listing();
$userList->setCondition('FIND_IN_SET(?, roles) > 0', [$role->getId()]);

foreach ($userList->load() as $user) {
if ($includeAllUsers || $user->getEmail()) {
$notifyUsers[$user->getLanguage()][$user->getId()] = $user;
}
}
}

//get users
$userList = new User\Listing();
if($includeAllUsers) {
$userList->setCondition('FIND_IN_SET(name, ?)', [implode(',', $users)]);
} else {
$userList->setCondition('FIND_IN_SET(name, ?) and email is not null', [implode(',', $users)]);
}

foreach ($userList->load() as $user) {
/**
* @var User $user
*/
if ($includeAllUsers || $user->getEmail()) {
$notifyUsers[$user->getLanguage()][$user->getId()] = $user;
}
}

foreach ($notifyUsers as $language => $usersPerLanguage) {
$notifyUsers[$language] = array_values($notifyUsers[$language]);
}

return $notifyUsers;
}

}

0 comments on commit fd36e47

Please sign in to comment.