Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rewrite demoextendsymfonyform1 module without CQRS #35

Merged
merged 5 commits into from
Feb 2, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions demoextendsymfonyform1/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Demonstration of how to insert an inputs inside the Symfony form

Learn using identifiable object and grid hooks as well as combining CQRS pattern from module
Learn using identifiable object and grid hooks.

## About

Expand All @@ -12,21 +12,23 @@ This new field appears:
This modules demonstrates
- how to add this field, manage its content and its
properties using modern hooks in Symfony pages
- how to use custom [CQRS](https://devdocs.prestashop.com/1.7/development/architecture/domain/cqrs/) Commands and Queries to separate your domain from your application*
- how to use Translator inside modern Symfony module

*This part is only demonstrated as a possibility for your module, this is
not mandatory to be done this way.
### Details

### Supported PrestaShop versions
This module uses an ObjectModel entity to persist the data submitted by the user.
[Other modules](https://github.com/PrestaShop/example-modules/tree/master/demoextendsymfonyform2) demonstrate
how to use DoctrineORM.

### Supported PrestaShop versions

This module is compatible with and 1.7.6.0 and above versions.

### Requirements
### Requirements

1. Composer, see [Composer](https://getcomposer.org/) to learn more

### How to install
### How to install

1. Download or clone module into `modules` directory of your PrestaShop installation
2. Rename the directory to make sure that module directory is named `demoextendsymfonyform1`*
Expand All @@ -35,5 +37,3 @@ not mandatory to be done this way.
4. Install module from Back Office

*Because the name of the directory and the name of the main module file must match.


14 changes: 11 additions & 3 deletions demoextendsymfonyform1/composer.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
{
"name": "prestashop/democqrshooksusage",
"description": "Help developers to understand how to create module using new hooks and apply best practices when using CQRS",
"name": "prestashop/demoextendsymfonyform1",
"authors": [
{
"name": "Tomas Ilginis"
},
{
"name": "PrestaShop Core Team"
}
],
"description": "Help developers to understand how to create module using Symfony hooks",
"autoload": {
"psr-4": {
"DemoCQRSHooksUsage\\": "src/"
"PrestaShop\\Module\\DemoHowToExtendSymfonyForm\\": "src/"
}
},
"license": "MIT",
Expand Down
6 changes: 3 additions & 3 deletions demoextendsymfonyform1/config/routes.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# @see https://devdocs.prestashop.com/1.7/modules/concepts/controllers/admin-controllers/#how-to-map-an-action-of-your-controller-to-a-uri
ps_democqrshooksusage_toggle_is_allowed_for_review:
path: demo-cqrs-hook-usage/{customerId}/toggle-is-allowed-for-review
ps_demoextendsymfonyform_toggle_is_allowed_for_review:
path: ps_demoextendsymfonyform/{customerId}/toggle-is-allowed-for-review
methods: [POST]
defaults:
_controller: 'DemoCQRSHooksUsage\Controller\Admin\CustomerReviewController::toggleIsAllowedForReviewAction'
_controller: 'PrestaShop\Module\DemoHowToExtendSymfonyForm\Controller\Admin\CustomerReviewController::toggleIsAllowedForReviewAction'
requirements:
customerId: \d+
29 changes: 2 additions & 27 deletions demoextendsymfonyform1/config/services.yml
Original file line number Diff line number Diff line change
@@ -1,33 +1,8 @@
services:
_defaults:
public: true
# @see https://devdocs.prestashop.com/1.7/development/architecture/migration-guide/forms/cqrs-usage-in-forms/ for CQRS pattern usage examples.
democqrshooksusage.domain.reviewer.command_handler.toggle_is_allowed_to_review_handler:
class: 'DemoCQRSHooksUsage\Domain\Reviewer\CommandHandler\ToggleIsAllowedToReviewHandler'
arguments:
- '@democqrshooksusage.repository.reviewer'
tags:
- name: tactician.handler
command: 'DemoCQRSHooksUsage\Domain\Reviewer\Command\ToggleIsAllowedToReviewCommand'

democqrshooksusage.domain.reviewer.query_handler.get_reviewer_settings_for_form_handler:
class: 'DemoCQRSHooksUsage\Domain\Reviewer\QueryHandler\GetReviewerSettingsForFormHandler'
arguments:
- '@democqrshooksusage.repository.reviewer'
tags:
- name: tactician.handler
command: 'DemoCQRSHooksUsage\Domain\Reviewer\Query\GetReviewerSettingsForForm'

democqrshooksusage.domain.reviewer.command_handler.update_is_allowed_to_review_handler:
class: 'DemoCQRSHooksUsage\Domain\Reviewer\CommandHandler\UpdateIsAllowedToReviewHandler'
arguments:
- '@democqrshooksusage.repository.reviewer'
tags:
- name: tactician.handler
command: 'DemoCQRSHooksUsage\Domain\Reviewer\Command\UpdateIsAllowedToReviewCommand'

democqrshooksusage.repository.reviewer:
class: 'DemoCQRSHooksUsage\Repository\ReviewerRepository'
ps_demoextendsymfonyform.repository.reviewer:
class: 'PrestaShop\Module\DemoHowToExtendSymfonyForm\Repository\ReviewerRepository'
arguments:
- '@doctrine.dbal.default_connection'
- '%database_prefix%'
160 changes: 70 additions & 90 deletions demoextendsymfonyform1/demoextendsymfonyform1.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,11 @@
* It is also available through the world-wide-web at this URL: https://opensource.org/licenses/AFL-3.0
*/

use DemoCQRSHooksUsage\Domain\Reviewer\Command\UpdateIsAllowedToReviewCommand;
use DemoCQRSHooksUsage\Domain\Reviewer\Exception\CannotCreateReviewerException;
use DemoCQRSHooksUsage\Domain\Reviewer\Exception\CannotToggleAllowedToReviewStatusException;
use DemoCQRSHooksUsage\Domain\Reviewer\Exception\ReviewerException;
use DemoCQRSHooksUsage\Domain\Reviewer\Query\GetReviewerSettingsForForm;
use DemoCQRSHooksUsage\Domain\Reviewer\QueryResult\ReviewerSettingsForForm;

use Doctrine\DBAL\Query\QueryBuilder;
use PrestaShop\PrestaShop\Core\CommandBus\CommandBusInterface;
use PrestaShop\Module\DemoHowToExtendSymfonyForm\Entity\Reviewer;
use PrestaShop\Module\DemoHowToExtendSymfonyForm\Exception\CannotCreateReviewerException;
use PrestaShop\Module\DemoHowToExtendSymfonyForm\Exception\CannotToggleAllowedToReviewStatusException;
use PrestaShop\PrestaShop\Core\Domain\Customer\Exception\CustomerException;
use PrestaShop\PrestaShop\Core\Grid\Column\Type\Common\ToggleColumn;
use PrestaShop\PrestaShop\Core\Grid\Definition\GridDefinitionInterface;
Expand All @@ -24,34 +21,32 @@
use PrestaShopBundle\Form\Admin\Type\SwitchType;
use PrestaShopBundle\Form\Admin\Type\YesAndNoChoiceType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface;

/**
* Class DemoExtendSymfonyForm1 demonstrates the usage of CQRS pattern and hooks.
* Class DemoExtendSymfonyForm1 demonstrates the usage of Symfony hooks.
*/
class DemoExtendSymfonyForm1 extends Module
matks marked this conversation as resolved.
Show resolved Hide resolved
{
public function __construct()
{
$this->name = 'demoextendsymfonyform1';
$this->version = '1.0.0';
$this->author = 'Tomas Ilginis';
$this->version = '1.1.0';
$this->author = 'PrestaShop';
$this->need_instance = 0;

parent::__construct();

$this->displayName = $this->getTranslator()->trans(
'Demo Symfony Forms #1',
[],
'Modules.Democqrshooksusage.Admin'
'Modules.DemoHowToExtendSymfonyForm.Admin'
matks marked this conversation as resolved.
Show resolved Hide resolved
);

$this->description =
$this->getTranslator()->trans(
'Help developers to understand how to create module using new hooks and apply best practices when using CQRS',
'Help developers to understand how to create module using Symfony page hooks',
matks marked this conversation as resolved.
Show resolved Hide resolved
[],
'Modules.Democqrshooksusage.Admin'
'Modules.DemoHowToExtendSymfonyForm.Admin'
);

$this->ps_versions_compliancy = [
Expand Down Expand Up @@ -96,8 +91,7 @@ public function install()
$this->registerHook('actionCustomerFormBuilderModifier') &&
$this->registerHook('actionAfterCreateCustomerFormHandler') &&
$this->registerHook('actionAfterUpdateCustomerFormHandler') &&
$this->installTables()
;
$this->installTables();
}

public function uninstall()
Expand All @@ -123,19 +117,18 @@ public function hookActionCustomerGridDefinitionModifier(array $params)
->addAfter(
'optin',
(new ToggleColumn('is_allowed_for_review'))
->setName($translator->trans('Allowed for review', [], 'Modules.Democqrshooksusage.Admin'))
->setName($translator->trans('Allowed for review', [], 'Modules.DemoHowToExtendSymfonyForm.Admin'))
->setOptions([
'field' => 'is_allowed_for_review',
'primary_field' => 'id_customer',
'route' => 'ps_democqrshooksusage_toggle_is_allowed_for_review',
'route' => 'ps_demoextendsymfonyform_toggle_is_allowed_for_review',
'route_param_name' => 'customerId',
])
)
;
);

$definition->getFilters()->add(
(new Filter('is_allowed_for_review', YesAndNoChoiceType::class))
->setAssociatedColumn('is_allowed_for_review')
->setAssociatedColumn('is_allowed_for_review')
);
}

Expand All @@ -158,7 +151,7 @@ public function hookActionCustomerGridQueryBuilderModifier(array $params)

$searchQueryBuilder->leftJoin(
'c',
'`' . pSQL(_DB_PREFIX_) . 'democqrshooksusage_reviewer`',
'`' . pSQL(_DB_PREFIX_) . 'demoextendsymfonyform_reviewer`',
'dcur',
'dcur.`id_customer` = c.`id_customer`'
);
Expand Down Expand Up @@ -189,28 +182,16 @@ public function hookActionCustomerFormBuilderModifier(array $params)
/** @var FormBuilderInterface $formBuilder */
$formBuilder = $params['form_builder'];
$formBuilder->add('is_allowed_for_review', SwitchType::class, [
'label' => $this->getTranslator()->trans('Allow reviews', [], 'Modules.Democqrshooksusage.Admin'),
'label' => $this->getTranslator()->trans('Allow reviews', [], 'Modules.DemoHowToExtendSymfonyForm.Admin'),
'required' => false,
]);

/**
* @var CommandBusInterface
*/
$queryBus = $this->get('prestashop.core.query_bus');

/**
* This part demonstrates the usage of CQRS pattern query to perform read operation from Reviewer entity.
*
* @see https://devdocs.prestashop.com/1.7/development/architecture/cqrs/ for more detailed information.
*
* As this is our recommended approach of reading the data but we not force to use this pattern in modules -
* you can use directly an entity here or wrap it in custom service class.
*
* @var ReviewerSettingsForForm
*/
$reviewerSettings = $queryBus->handle(new GetReviewerSettingsForForm($params['id']));

$params['data']['is_allowed_for_review'] = $reviewerSettings->isAllowedForReview();
$result = false;
if (null !== $params['id']) {
$result = $this->get('ps_demoextendsymfonyform.repository.reviewer')->getIsAllowedToReviewStatus($params['id']);
matks marked this conversation as resolved.
Show resolved Hide resolved
}

$params['data']['is_allowed_for_review'] = $result;

$formBuilder->setData($params['data']);
}
Expand Down Expand Up @@ -249,25 +230,26 @@ private function updateCustomerReviewStatus(array $params)
$customerId = $params['id'];
/** @var array $customerFormData */
$customerFormData = $params['form_data'];
$isAllowedForReview = (bool) $customerFormData['is_allowed_for_review'];
$isAllowedForReview = (bool)$customerFormData['is_allowed_for_review'];
matks marked this conversation as resolved.
Show resolved Hide resolved

/** @var CommandBusInterface $commandBus */
$commandBus = $this->get('prestashop.core.command_bus');
$reviewerId = $this->get('ps_demoextendsymfonyform.repository.reviewer')->findIdByCustomer($customerId);

$reviewer = new Reviewer($reviewerId);
if (0 >= $reviewer->id) {
$reviewer = $this->createReviewer($customerId);
}
$reviewer->is_allowed_for_review = $isAllowedForReview;

try {
/*
* This part demonstrates the usage of CQRS pattern command to perform write operation for Reviewer entity.
* @see https://devdocs.prestashop.com/1.7/development/architecture/cqrs/ for more detailed information.
*
* As this is our recommended approach of writing the data but we not force to use this pattern in modules -
* you can use directly an entity here or wrap it in custom service class.
*/
$commandBus->handle(new UpdateIsAllowedToReviewCommand(
$customerId,
$isAllowedForReview
));
} catch (ReviewerException $exception) {
$this->handleException($exception);
if (false === $reviewer->update()) {
throw new CannotToggleAllowedToReviewStatusException(
sprintf('Failed to change status for reviewer with id "%s"', $reviewer->id)
);
}
} catch (PrestaShopException $exception) {
throw new CannotToggleAllowedToReviewStatusException(
'An unexpected error occurred when updating reviewer status'
);
}
}

Expand All @@ -279,7 +261,7 @@ private function updateCustomerReviewStatus(array $params)
private function installTables()
{
$sql = '
CREATE TABLE IF NOT EXISTS `' . pSQL(_DB_PREFIX_) . 'democqrshooksusage_reviewer` (
CREATE TABLE IF NOT EXISTS `' . pSQL(_DB_PREFIX_) . 'demoextendsymfonyform_reviewer` (
`id_reviewer` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`id_customer` INT(10) UNSIGNED NOT NULL,
`is_allowed_for_review` TINYINT(1) NOT NULL,
Expand All @@ -297,48 +279,46 @@ private function installTables()
*/
private function uninstallTables()
{
$sql = 'DROP TABLE IF EXISTS `' . pSQL(_DB_PREFIX_) . 'democqrshooksusage_reviewer`';
$sql = 'DROP TABLE IF EXISTS `' . pSQL(_DB_PREFIX_) . 'demoextendsymfonyform_reviewer`';

return Db::getInstance()->execute($sql);
}

/**
* Handles exceptions and displays message in more user friendly form.
* Creates a reviewer.
*
* @param ReviewerException $exception
* @param $customerId
matks marked this conversation as resolved.
Show resolved Hide resolved
*
* @throws \PrestaShop\PrestaShop\Core\Module\Exception\ModuleErrorException
* @return Reviewer
*
* @throws CannotCreateReviewerException
*/
private function handleException(ReviewerException $exception)
protected function createReviewer($customerId)
matks marked this conversation as resolved.
Show resolved Hide resolved
{
$exceptionDictionary = [
CannotCreateReviewerException::class => $this->getTranslator()->trans(
'Failed to create a record for customer',
[],
'Modules.Democqrshooksusage.Admin'
),
CannotToggleAllowedToReviewStatusException::class => $this->getTranslator()->trans(
'Failed to toggle is allowed to review status',
[],
'Modules.Democqrshooksusage.Admin'
),
];

$exceptionType = get_class($exception);

if (isset($exceptionDictionary[$exceptionType])) {
$message = $exceptionDictionary[$exceptionType];
} else {
$message = $this->getTranslator()->trans(
'An unexpected error occurred. [%type% code %code%]',
[
'%type%' => $exceptionType,
'%code%' => $exception->getCode(),
],
'Admin.Notifications.Error'
try {
$reviewer = new Reviewer();
$reviewer->id_customer = $customerId;
$reviewer->is_allowed_for_review = 0;

if (false === $reviewer->save()) {
throw new CannotCreateReviewerException(
sprintf(
'An error occurred when creating reviewer with customer id "%s"',
$customerId
)
);
}
} catch (PrestaShopException $exception) {
throw new CannotCreateReviewerException(
sprintf(
'An unexpected error occurred when creating reviewer with customer id "%s"',
$customerId
),
0,
$exception
);
}

throw new \PrestaShop\PrestaShop\Core\Module\Exception\ModuleErrorException($message);
return $reviewer;
}
}
Loading