Skip to content

Commit

Permalink
Merge pull request #58 from smartbooster/better_smart_parameter_entit…
Browse files Browse the repository at this point in the history
…y_type

Better Smart Parameter type management and value validation
  • Loading branch information
mathieu-ducrot authored Mar 20, 2024
2 parents 432ebcc + b8f033f commit e9651f8
Show file tree
Hide file tree
Showing 18 changed files with 560 additions and 19 deletions.
41 changes: 40 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,44 @@
CHANGELOG for 1.x
CHANGELOG
===================
## v2.1.0 - (2024-03-17)

### Uprade guide

**The upgrade to this version needs some extra steps from your part to work properly. Please do the following :**
- Run a doctrine migration for the new properties added to the Smart Parameter Entity if you use them.
- Also add the following templates on your project if you use our ParameterAdmin
```twig
{# templates/admin/parameter_admin/list_value.html.twig #}
{% extends '@SonataAdmin/CRUD/base_list_field.html.twig' %}
{% block field %}
{% include '@SmartSonata/admin/parameter_admin/render_value.html.twig' %}
{% endblock %}
{# templates/admin/parameter_admin/timeline_history_field.html.twig #}
{% extends '@SmartSonata/admin/base_field/timeline_history_field.html.twig' %}
{% block render_value %}
{% include '@SmartSonata/admin/parameter_admin/render_value.html.twig' %}
{% endblock %}
```
- Once this is done, the ParameterAmin should work back as before. Update your smart_sonata.parameters types if you need to and you are good to go.

_Now back to what have changes on this version ..._

### Added
- `ParameterInterface` for a better following on Parameter method and type evolution
- It extends the `HistorizableInterface` which add the history field to the entity
- So when upgrading to this version make sure to run a doctrine migration to have your updated values properly logged.
- `ParameterInterface::type` Parameter can now have a type (text by default) which impact the validation and the return type of the getValue
- `ParameterInterface::getArrayValue` for list values and email chain, this method return the value as a proper array type
- `ParameterInterface::regex` used for value validation for text and list parameter type
- Add `yokai/enum-bundle` composer requirement for the ParameterTypeEnum

### Changed
- `ParameterProvider::getValue` now handle every new type added to the `ParameterInterface`
- `ParameterAdmin` impact of new type and regex property added to the `ParameterInterface`
- Changes made to the parameter value are now logged in the history of the Parameter
- The help field is now visible on the show/form only if it's not null

## v2.0.1 - (2024-02-22)
### Fixed
- Fix clear cache error on `EmailProvider` locale -> can be nullable and check `$requestStack->getCurrentRequest()` is not null.
Expand Down
5 changes: 3 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@
"yokai/security-token-bundle": "^3.3",
"sentry/sentry-symfony": "^4.1",
"symfony/expression-language": "^4.4 || ^5.4 || ^6.0",
"smartbooster/core-bundle": "^1.0"
"smartbooster/core-bundle": "^1.0",
"yokai/enum-bundle": "^3.3 || ^4.1"
},
"require-dev": {
"smartbooster/standard-bundle": "^1.0",
Expand All @@ -49,7 +50,7 @@
},
"extra": {
"branch-alias": {
"dev-master": "1.3.x-dev"
"dev-master": "2.1.x-dev"
},
"symfony": {
"endpoint": ["https://api.github.com/repos/smartbooster/standard-bundle/contents/recipes.json"]
Expand Down
1 change: 1 addition & 0 deletions config/bundles.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,5 @@
Symfony\WebpackEncoreBundle\WebpackEncoreBundle::class => ['prod' => true],
Yokai\SecurityTokenBundle\YokaiSecurityTokenBundle::class => ['all' => true],
Sonata\BlockBundle\SonataBlockBundle::class => ['all' => true],
Yokai\EnumBundle\YokaiEnumBundle::class => ['all' => true],
];
9 changes: 9 additions & 0 deletions config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ services:
- ~
- Smart\SonataBundle\Entity\Parameter
- ~
- '@Smart\SonataBundle\Enum\ParameterTypeEnum'
- '@Smart\SonataBundle\Logger\HistoryLogger'
tags:
- { name: sonata.admin, manager_type: orm, label: dashboard.label_parameter }

Expand Down Expand Up @@ -155,3 +157,10 @@ services:
# The "Symfony\Component\DependencyInjection\ContainerInterface" autowiring alias is deprecated. Define it explicitly in your app if you want to keep using it.
# It's not a good way, but it's practical for the moment. It's used in AbstractAdmin::get. Need to replace all get call by injection
Symfony\Component\DependencyInjection\ContainerInterface: '@service_container'

# Enum
Smart\SonataBundle\Enum\ParameterTypeEnum:
arguments:
- '@translator'
tags:
- {name: yokai_enum.enum}
140 changes: 134 additions & 6 deletions src/Admin/ParameterAdmin.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,48 @@

namespace Smart\SonataBundle\Admin;

use Doctrine\ORM\UnitOfWork;
use Smart\CoreBundle\Validator\Constraints\EmailChain;
use Smart\SonataBundle\Entity\Log\HistorizableInterface;
use Smart\SonataBundle\Entity\ParameterInterface;
use Smart\SonataBundle\Enum\ParameterTypeEnum;
use Smart\SonataBundle\Logger\HistoryLogger;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\FieldDescription\FieldDescriptionInterface;
use Sonata\AdminBundle\Form\FormMapper;
use Sonata\AdminBundle\Route\RouteCollectionInterface;
use Sonata\AdminBundle\Show\ShowMapper;
use Sonata\DoctrineORMAdminBundle\Filter\ChoiceFilter;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Validator\Constraints\Email;
use Yokai\EnumBundle\Form\Type\EnumType;

/**
* @author Mathieu Ducrot <[email protected]>
* @method ParameterInterface getSubject()
*/
class ParameterAdmin extends AbstractAdmin
{
private ParameterTypeEnum $typeEnum;
private HistoryLogger $historyLogger;
private array $updateInitialData = [];

public function __construct(
string $code,
?string $class,
string $baseControllerName,
ParameterTypeEnum $typeEnum,
HistoryLogger $historyLogger,
) {
parent::__construct($code, $class, $baseControllerName);
$this->typeEnum = $typeEnum;
$this->historyLogger = $historyLogger;
}

protected function configureRoutes(RouteCollectionInterface $collection): void
{
$collection
Expand All @@ -27,8 +58,16 @@ protected function configureListFields(ListMapper $list): void
$list
->addIdentifier('id', null, ['label' => 'field.label_id'])
->addIdentifier('code', null, ['label' => 'field.label_code'])
->add('type', FieldDescriptionInterface::TYPE_CHOICE, [
'label' => 'field.label_type',
'choices' => array_flip($this->typeEnum->getChoices()),
'catalog' => false, // enum is self translated
])
->add('help', null, ['label' => 'field.label_help'])
->add('value', null, ['label' => 'field.label_value'])
->add('value', null, [
'label' => 'field.label_value',
'template' => 'admin/parameter_admin/list_value.html.twig'
])
;
}

Expand All @@ -39,36 +78,108 @@ protected function configureDatagridFilters(DatagridMapper $filter): void
'show_filter' => true,
'label' => 'field.label_code'
])
->add('type', ChoiceFilter::class, [
'field_type' => EnumType::class,
'field_options' => ['enum' => ParameterTypeEnum::class],
'show_filter' => true,
'label' => 'field.label_type',
])
;
}

protected function configureShowFields(ShowMapper $show): void
{
$parameter = $this->getSubject();
$show
->with('fieldset.label_general', ['label' => 'fieldset.label_general'])
->add('id', null, ['label' => 'field.label_id'])
->add('code', null, ['label' => 'field.label_code'])
->add('help', null, ['label' => 'field.label_help'])
->add('value', null, ['label' => 'field.label_value'])
->add('type', FieldDescriptionInterface::TYPE_CHOICE, [
'label' => 'field.label_type',
'choices' => array_flip($this->typeEnum->getChoices()),
'catalog' => false, // enum is self translated
])
;
if ($parameter->getHelp()) {
$show->add('help', null, ['label' => 'field.label_help']);
}
if ($parameter->getRegex() !== null) {
$show->add('regex', null, ['label' => 'field.label_regex']);
}
$valueType = null;
if ($parameter->isBooleanType()) {
$valueType = FieldDescriptionInterface::TYPE_BOOLEAN;
} elseif ($parameter->isTextareaType()) {
$valueType = FieldDescriptionInterface::TYPE_HTML;
}
$show
->add('value', $valueType, ['label' => 'field.label_value'])
->end()
->with('fieldset.label_history', ['class' => 'col-md-12', 'label' => 'fieldset.label_history'])
->add('history', null, ['template' => 'admin/parameter_admin/timeline_history_field.html.twig'])
->end()
;
}

protected function configureFormFields(FormMapper $form): void
{
$parameter = $this->getSubject();
$form
->with('fieldset.label_general', ['label' => 'fieldset.label_general'])
->add('code', null, [
'label' => 'field.label_code',
'disabled' => true
])
->add('type', EnumType::class, [
'label' => 'field.label_type',
'enum' => ParameterTypeEnum::class,
'disabled' => true,
])
;

if ($parameter->getHelp()) {
$form
->add('help', null, [
'label' => 'field.label_help',
'disabled' => true
])
->add('value', null, ['label' => 'field.label_value'])
->end()
;
;
}
if ($parameter->getRegex() !== null) {
$form->add('regex', null, [
'label' => 'field.label_regex',
'disabled' => true,
]);
}

$valueType = TextType::class;
$valueOptions = [];
if ($parameter->isBooleanType()) {
$valueType = CheckboxType::class;
$valueOptions = ['required' => false];
} elseif ($parameter->isEmailChainType() || $parameter->isListType() || $parameter->isTextareaType()) {
$valueType = TextareaType::class;
$valueOptions = ['attr' => ['rows' => 10]];
if (!$parameter->isTextareaType()) {
$valueOptions['help'] = 'field.help_parameter_array_values';
}
if ($parameter->isEmailChainType()) {
$valueOptions['constraints'] = [new EmailChain(separator: PHP_EOL)];
}
} elseif ($parameter->isFloatType() || $parameter->isIntegerType()) {
$valueType = NumberType::class;
$valueOptions = ['html5' => true];
if ($parameter->isIntegerType()) {
$valueOptions['scale'] = 0;
}
} elseif ($parameter->isEmailType()) {
// MDT Should be converted with Assert\When for when we drop support for SF 5.4
$valueOptions['constraints'] = [new Email()];
}
$form->add('value', $valueType, [
'label' => 'field.label_value',
...$valueOptions,
])->end();
}

public function getExportFormats(): array
Expand All @@ -84,4 +195,21 @@ protected function configureExportFields(): array
$this->trans('field.label_help') => 'help',
];
}

protected function preUpdate(object $object): void
{
/** @var UnitOfWork $uow @phpstan-ignore-next-line */
$uow = $this->getModelManager()->getEntityManager($this->getClass())->getUnitOfWork();
$this->updateInitialData = [
'value' => $uow->getOriginalEntityData($object)['value'],
];
}

protected function postUpdate(object $object): void
{
/** @var HistorizableInterface $object */
$this->historyLogger->logDiff($object, $this->updateInitialData, [
'author' => $this->getUser()->getFullName(), // @phpstan-ignore-line
]);
}
}
2 changes: 2 additions & 0 deletions src/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ private function getParametersNode(): ArrayNodeDefinition
->useAttributeAsKey('name')
->arrayPrototype()
->children()
->scalarNode('type')->defaultValue('text')->end()
->scalarNode('value')->isRequired()->end()
->scalarNode('regex')->end()
->scalarNode('help')->end()
->end()
->end()
Expand Down
Loading

0 comments on commit e9651f8

Please sign in to comment.