mirror of
https://github.com/Part-DB/Part-DB-server.git
synced 2025-06-21 17:39:06 +02:00
Fixed exception about non-persisted entities, when using the cached StructuralEntityType.
This commit is contained in:
parent
7608d5dbda
commit
c7e8fc9642
3 changed files with 115 additions and 4 deletions
|
@ -72,6 +72,9 @@ abstract class BaseAdminController extends AbstractController
|
|||
$em->flush();
|
||||
}
|
||||
|
||||
//Rebuild form, so it is based on the updated data. Important for the parent field!
|
||||
$form = $this->createForm($this->form_class, $entity);
|
||||
|
||||
return $this->render($this->twig_template, [
|
||||
'entity' => $entity,
|
||||
'form' => $form->createView()
|
||||
|
|
|
@ -37,12 +37,15 @@ use App\Entity\Parts\PartLot;
|
|||
use App\Entity\Parts\Storelocation;
|
||||
use App\Form\Type\StructuralEntityType;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\DataMapperInterface;
|
||||
use Symfony\Component\Form\Exception;
|
||||
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\NumberType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\Form\FormInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use function GuzzleHttp\Promise\queue;
|
||||
|
||||
|
@ -55,7 +58,8 @@ class PartLotType extends AbstractType
|
|||
|
||||
$builder->add('storage_location', StructuralEntityType::class, ['class' => Storelocation::class,
|
||||
'label' => 'part_lot.edit.location',
|
||||
'disable_not_selectable' => true, 'attr' => ['class' => 'form-control-sm']]);
|
||||
'disable_not_selectable' => true,
|
||||
'attr' => ['class' => 'selectpicker form-control-sm', 'data-live-search' => true]]);
|
||||
|
||||
$builder->add('amount',NumberType::class, [ 'html5' => true,
|
||||
'label' => 'part_lot.edit.amount',
|
||||
|
|
|
@ -38,13 +38,19 @@ use App\Repository\StructuralDBElementRepository;
|
|||
use App\Services\TreeBuilder;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\CallbackTransformer;
|
||||
use Symfony\Component\Form\ChoiceList\Loader\CallbackChoiceLoader;
|
||||
use Symfony\Component\Form\DataMapperInterface;
|
||||
use Symfony\Component\Form\DataTransformerInterface;
|
||||
use Symfony\Component\Form\Exception;
|
||||
use Symfony\Component\Form\Exception\TransformationFailedException;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\Form\FormInterface;
|
||||
use Symfony\Component\Form\FormView;
|
||||
use Symfony\Component\OptionsResolver\Options;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use function foo\func;
|
||||
|
||||
/**
|
||||
* This class provides a choice form type similar to EntityType, with the difference, that the tree structure
|
||||
|
@ -64,10 +70,19 @@ class StructuralEntityType extends AbstractType
|
|||
$this->builder = $builder;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{
|
||||
$builder->addModelTransformer(new CallbackTransformer(
|
||||
function ($value) use ($options){
|
||||
return $this->transform($value, $options);
|
||||
}, function ($value) use ($options) {
|
||||
return $this->reverseTransform($value, $options);
|
||||
}));
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver->setRequired(['class']);
|
||||
|
||||
$resolver->setDefaults(['attr' => ['class' => 'selectpicker', 'data-live-search' => true],
|
||||
'show_fullpath_in_subtext' => true, //When this is enabled, the full path will be shown in subtext
|
||||
'subentities_of' => null, //Only show entities with the given parent class
|
||||
|
@ -128,7 +143,6 @@ class StructuralEntityType extends AbstractType
|
|||
|
||||
$choices = $this->builder->typeToNodesList($options['class'], null);
|
||||
|
||||
|
||||
/** @var StructuralDBElementRepository $repo */
|
||||
/*$repo = $this->em->getRepository($options['class']);
|
||||
$choices = $repo->toNodesList(null); */
|
||||
|
@ -142,11 +156,101 @@ class StructuralEntityType extends AbstractType
|
|||
//See extendedBootstrap4_layout.html.twig for that...
|
||||
$view->vars['use_html_in_labels'] = true;
|
||||
|
||||
parent::buildView($view, $form, $options); // TODO: Change the autogenerated stub
|
||||
parent::buildView($view, $form, $options);
|
||||
}
|
||||
|
||||
public function getParent()
|
||||
{
|
||||
return ChoiceType::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a value from the original representation to a transformed representation.
|
||||
*
|
||||
* This method is called when the form field is initialized with its default data, on
|
||||
* two occasions for two types of transformers:
|
||||
*
|
||||
* 1. Model transformers which normalize the model data.
|
||||
* This is mainly useful when the same form type (the same configuration)
|
||||
* has to handle different kind of underlying data, e.g The DateType can
|
||||
* deal with strings or \DateTime objects as input.
|
||||
*
|
||||
* 2. View transformers which adapt the normalized data to the view format.
|
||||
* a/ When the form is simple, the value returned by convention is used
|
||||
* directly in the view and thus can only be a string or an array. In
|
||||
* this case the data class should be null.
|
||||
*
|
||||
* b/ When the form is compound the returned value should be an array or
|
||||
* an object to be mapped to the children. Each property of the compound
|
||||
* data will be used as model data by each child and will be transformed
|
||||
* too. In this case data class should be the class of the object, or null
|
||||
* when it is an array.
|
||||
*
|
||||
* All transformers are called in a configured order from model data to view value.
|
||||
* At the end of this chain the view data will be validated against the data class
|
||||
* setting.
|
||||
*
|
||||
* This method must be able to deal with empty values. Usually this will
|
||||
* be NULL, but depending on your implementation other empty values are
|
||||
* possible as well (such as empty strings). The reasoning behind this is
|
||||
* that data transformers must be chainable. If the transform() method
|
||||
* of the first data transformer outputs NULL, the second must be able to
|
||||
* process that value.
|
||||
*
|
||||
* @param mixed $value The value in the original representation
|
||||
*
|
||||
* @return mixed The value in the transformed representation
|
||||
*
|
||||
* @throws TransformationFailedException when the transformation fails
|
||||
*/
|
||||
public function transform($value, $options)
|
||||
{
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a value from the transformed representation to its original
|
||||
* representation.
|
||||
*
|
||||
* This method is called when {@link Form::submit()} is called to transform the requests tainted data
|
||||
* into an acceptable format.
|
||||
*
|
||||
* The same transformers are called in the reverse order so the responsibility is to
|
||||
* return one of the types that would be expected as input of transform().
|
||||
*
|
||||
* This method must be able to deal with empty values. Usually this will
|
||||
* be an empty string, but depending on your implementation other empty
|
||||
* values are possible as well (such as NULL). The reasoning behind
|
||||
* this is that value transformers must be chainable. If the
|
||||
* reverseTransform() method of the first value transformer outputs an
|
||||
* empty string, the second value transformer must be able to process that
|
||||
* value.
|
||||
*
|
||||
* By convention, reverseTransform() should return NULL if an empty string
|
||||
* is passed.
|
||||
*
|
||||
* @param mixed $value The value in the transformed representation
|
||||
*
|
||||
* @return mixed The value in the original representation
|
||||
*
|
||||
* @throws TransformationFailedException when the transformation fails
|
||||
*/
|
||||
public function reverseTransform($value, $options)
|
||||
{
|
||||
/* This step is important in combination with the caching!
|
||||
The elements deserialized from cache, are not known to Doctrinte ORM any more, so doctrine thinks,
|
||||
that the entity has changed (and so throws an exception about non-persited entities).
|
||||
This function just retrieves a fresh copy of the entity from database, so doctrine detect correctly that no
|
||||
change happened.
|
||||
The performance impact of this should be very small in comparison of the boost, caused by the caching.
|
||||
*/
|
||||
|
||||
if ($value === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$entity = $this->em->find($options['class'], $value->getID());
|
||||
|
||||
return $entity;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue