Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
131 changes: 131 additions & 0 deletions CHANGELOG-AK7.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
## Added default Label & Image properties

He now have default properties that reflect Reference Entities...

You have to enable them to use them...

Here is an example with Color

```yaml
## grid example color
# */ReferenceDataBundle/Resources/config/datagrid/color.yml

datagrid:
color:
options:
entityHint: color
manageFilters: false
source:
type: pim_datasource_default
entity: Induxx\Bundle\ReferenceDataBundle\Entity\ReferenceIcon
repository_method: createDatagridQueryBuilder
columns:
code:
label: pim_custom_entity.form.tab.code.title
label:
label: pim_custom_entity.form.tab.label.title
filters:
columns:
code:
type: string
label: pim_custom_entity.form.tab.code.title
data_name: rd.code
label:
type: search
label: pim_custom_entity.form.tab.label.title
data_name: rd.label
sorters:
columns:
code:
data_name: rd.code
label:
data_name: rd.label
default:
code: '%oro_datagrid.extension.orm_sorter.class%::DIRECTION_ASC'
properties:
id: ~
edit_link:
type: url
route: pim_customentity_rest_get
params:
- id
- customEntityName
delete_link:
type: url
route: pim_customentity_rest_delete
params:
- id
- customEntityName
actions:
edit:
type: navigate
label: grid.action.label.edit
icon: edit
link: edit_link
rowAction: true
delete:
type: delete
label: grid.action.label.delete
icon: trash
link: delete_link
```

```yaml
## add label and image
# */ReferenceDataBundle/Resources/config/form_extensions/color/edit.yml
...
<project>-color-edit-form-properties-label:
module: pim/form/common/fields/text
parent: <project>-color-edit-form-properties-common
targetZone: content
position: 90
config:
fieldName: label
label: pim_custom_entity.form.tab.label.title

<project>-color-edit-form-properties-image:
module: referencedata/media-field
parent: <project>-color-edit-form-properties-common
targetZone: content
position: 130
config:
fieldName: image
label: pim_custom_entity.form.tab.image.title
required: false
readOnly: false
```

```yaml
# */ReferenceDataBundle/Resources/config/doctrine/Color.orm.yml
Induxx\Bundle\ReferenceDataBundle\Entity\Color:
type: entity
table: refdata_reference_color
changeTrackingPolicy: DEFERRED_EXPLICIT
repositoryClass: Pim\Bundle\CustomEntityBundle\Entity\Repository\CustomEntityRepository
fields:
id:
type: integer
id: true
generator:
strategy: AUTO
code:
type: string
length: 255
nullable: false
unique: true
label:
type: string
length: 255
nullable: true
oneToOne:
image:
targetEntity: Akeneo\Tool\Component\FileStorage\Model\FileInfoInterface
joinColumn:
name: Image
referencedColumnName: id
onDelete: 'SET NULL'
cascade:
- persist
```
After this you will have to generate a custom DB Integration which is a Case by Case Scenario.
Some might already have and Image or a Label ...
146 changes: 146 additions & 0 deletions Controller/Rest/AbstractRestApiAction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
<?php

namespace Pim\Bundle\CustomEntityBundle\Controller\Rest;

use Pim\Bundle\CustomEntityBundle\Action\ActionFactory;
use Pim\Bundle\CustomEntityBundle\Configuration\ConfigurationInterface;
use Pim\Bundle\CustomEntityBundle\Entity\AbstractCustomEntity;
use Pim\Bundle\CustomEntityBundle\Event\ActionEventManager;
use Pim\Bundle\CustomEntityBundle\Manager\ManagerInterface;
use Pim\Bundle\CustomEntityBundle\Manager\Registry as ManagerRegistry;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\OptionsResolver\OptionsResolver;

abstract class AbstractRestApiAction
{
protected ActionFactory $actionFactory;

protected ActionEventManager $eventManager;

protected ManagerRegistry $managerRegistry;

protected ConfigurationInterface $configuration;

protected array $options;

private array $referenceEntityCodes;
private array $referenceEntityNames;

public function __construct(
ActionFactory $actionFactory,
ActionEventManager $eventManager,
ManagerRegistry $managerRegistry,
array $referenceEntityCodes,
array $referenceEntityNames,
) {
$this->actionFactory = $actionFactory;
$this->eventManager = $eventManager;
$this->managerRegistry = $managerRegistry;
$this->referenceEntityCodes = $referenceEntityCodes;
$this->referenceEntityNames = $referenceEntityNames;
}

public function setConfiguration(ConfigurationInterface $configuration): void
{
$this->configuration = $configuration;
$resolver = new OptionsResolver();
$this->setDefaultOptions($resolver);
$this->eventManager->dipatchConfigureEvent($this, $resolver);
$this->options = $resolver->resolve($configuration->getActionOptions($this->getType()));
}

public function getConfiguration(): ConfigurationInterface
{
return $this->configuration;
}

public function getOptions(): array
{
return $this->options;
}

protected function getOption($optionKey)
{
if (isset($this->options[$optionKey])) {
return $this->options[$optionKey];
} else {
throw new \LogicException(
sprintf('Option "%s" is not defined', $optionKey)
);
}
}

public function execute(Request $request): Response
{
throw new \Exception('WE DON\'T USE EXECUTE, WE BYPASS IT');
}

protected function findEntity(Request $request): AbstractCustomEntity
{
$entity = $this->getManager()->find(
$this->configuration->getEntityClass(),
$request->attributes->get('id'),
$this->options['find_options']
);

if (null === $entity) {
throw new NotFoundHttpException();
}

return $entity;
}

protected function normalize(AbstractCustomEntity $entity): array
{
$manager = $this->getManager();
$entityName = $this->configuration->getName();
$editFormExtension = $this->configuration->getOptions()['edit_form_extension'];
$context = [
'customEntityName' => $entityName,
'form' => $editFormExtension,
];

return $manager->normalize($entity, 'standard', $context);
}

protected function getDecodedContent($content): array
{
$decodedContent = \json_decode($content, true);

if (null === $decodedContent) {
throw new BadRequestHttpException('Invalid json message received');
}

return $decodedContent;
}

protected function getManager(): ManagerInterface
{
return $this->managerRegistry->getFromConfiguration($this->configuration);
}

protected function setDefaultOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults(['find_options' => []]);
}

/**
* @param string $referenceEntityCode
* @return string
*/
protected function getEntityClass(string $referenceEntityCode): ?string
{
return $this->referenceEntityCodes[$referenceEntityCode] ?? null;
}

/**
* TODO extract these params outside the class
*/
protected function getConfigurationAlias(string $referenceEntityCode): ?string
{
return $this->referenceEntityNames[$referenceEntityCode] ?? null;
}
}
110 changes: 110 additions & 0 deletions Controller/Rest/PartialUpdateAction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
<?php

namespace Pim\Bundle\CustomEntityBundle\Controller\Rest;

use Doctrine\ORM\EntityManager;
use Pim\Bundle\CustomEntityBundle\Action\ActionFactory;
use Pim\Bundle\CustomEntityBundle\Action\ActionInterface;
use Pim\Bundle\CustomEntityBundle\Configuration\Registry;
use Pim\Bundle\CustomEntityBundle\Event\ActionEventManager;
use Pim\Bundle\CustomEntityBundle\Manager\Registry as ManagerRegistry;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;

class PartialUpdateAction extends AbstractRestApiAction implements ActionInterface
{
protected ValidatorInterface $validator;
protected NormalizerInterface $violationNormalizer;
private RouterInterface $router;
private EntityManager $entityManager;
private Registry $configurationRegistry;

public function __construct(
ActionFactory $actionFactory,
ActionEventManager $eventManager,
ManagerRegistry $managerRegistry,
Registry $configurationRegistry,
RouterInterface $router,
EntityManager $entityManager,
ValidatorInterface $validator,
NormalizerInterface $violationNormalizer,
array $referenceEntityCodes,
array $referenceEntityNames,
) {
parent::__construct($actionFactory, $eventManager, $managerRegistry, $referenceEntityCodes, $referenceEntityNames);
$this->validator = $validator;
$this->violationNormalizer = $violationNormalizer;
$this->router = $router;
$this->entityManager = $entityManager;
$this->configurationRegistry = $configurationRegistry;
}

public function __invoke(Request $request, string $referenceCode, string $code): Response
{
$referenceEntityClass = $this->getEntityClass($referenceCode);
if (null === $referenceEntityClass) {
throw new NotFoundHttpException(sprintf('Reference entity "%s" does not exist.', $referenceCode));
}

$this->setConfiguration($this->configurationRegistry->get($this->getConfigurationAlias($referenceCode)));
$manager = $this->getManager();
$data = $this->getDecodedContent($request->getContent());
unset($data['reference-code']);

$entityRepository = $this->entityManager->getRepository($referenceEntityClass);

$referenceEntityRecord = $entityRepository->findOneByIdentifier($code);
$isCreation = null === $referenceEntityRecord;

if ($isCreation) {
$referenceEntityRecord = $manager->create($referenceEntityClass, $data);
} else {
$manager->update($referenceEntityRecord, $data);
}

$errors = $this->validator->validate($referenceEntityRecord);
if (count($errors) > 0) {
$normalizedViolations = [];
foreach ($errors as $error) {
$normalizedViolations[] = $this->violationNormalizer->normalize(
$error,
'standard'
);
}

return new JsonResponse(['values' => $normalizedViolations], Response::HTTP_BAD_REQUEST);
}

$manager->save($referenceEntityRecord);
$status = $isCreation ? Response::HTTP_CREATED : Response::HTTP_NO_CONTENT;

return $this->getResponse($referenceCode, $code, $status);
}

private function getResponse(string $referenceCode, string $code, int $status): Response
{
$response = new Response(null, $status);
$route = $this->router->generate(
'api_reference_entity_get',
[
'referenceCode' => $referenceCode,
'code' => $code,
],
UrlGeneratorInterface::ABSOLUTE_URL
);
$response->headers->set('Location', $route);

return $response;
}

public function getType(): string
{
return 'rest_create';
}
}
Loading