Symfony2 - list of translated values - symfony

I'm using symfony2.4 + sonata + gedmo + a2 lix 1.x
I have one entity name "propriete" with his own translation entity (AbstractPersonalTranslation)
I'm able to create a admin form to CRUD the entity with translation tab (OK).
Now I want to display a part (filter on famille for instance) of the translated values of Propriete in an other admin form.
I tried to create a QueryBuilder
->add('firingTypes', 'entity', array(
'class' => 'Sal\RefBundle\Entity\Propriete',
'query_builder' => function(ProprieteRepository $er) {
return $er->queryMyProprieteEn('u');
}))
From repository:
public function queryMyProprieteEn() {
$qb = $this->createQueryBuilder('u')
->andWhere("u.famille=:famille")
->setParameter("famille", "139");
$query = $qb->getQuery();
$query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, 'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker');
$query->setHint(\Gedmo\Translatable\TranslatableListener::HINT_TRANSLATABLE_LOCALE, 'en');
return $query->getResult();
}
But of course I have the following error "Expected argument of type Doctrine\ORM\QueryBuilder", "array" given"
How to handle to create a combobox/checkbox of translated values from a main form ?
Please help
Regards

Related

Symfony 5 / Easy Admin 3 - FormBuilder added field not displaying appropiate input

I am building a form using Easy Admin's FormBuilder. My goal is to have an AssociationField which represents a OneToMany relationship, for example, to assign multiple products to a shop. Additionally, I only want some filtered products to be listed, so I overrode the createEditFormBuilder method in the CrudController, I used this question as reference, and this is the code for the overridden function :
public function createEditFormBuilder(EntityDto $entityDto, KeyValueStore $formOptions, AdminContext $context): FormBuilderInterface
{
$formBuilder = parent::createEditFormBuilder($entityDto, $formOptions, $context);
$filteredProducts = $context->getEntity()->getInstance()->getFilteredProducts();
$formBuilder->add('products', EntityType::class, ['class' => 'App\Entity\Product', 'choices' => $filteredProducts, 'multiple' => true]);
return $formBuilder;
}
I expected an Association field as the ones configured in the configureFields() function, however, the displayed field doesn't allow text search or autocomplete features, plus has incorrect height.
Expected:
Actual:
I tried to change the second argument in the $formBuilder->Add() function, but all specific EasyAdmin types threw errors.
UPDATE: I also tried using EasyAdmin's CrudFormType instead of EntityType, which doesn't support the 'choice' parameter. Still, the result was the same.
There is setQueryBuilder on the field, you can use it for filtering entities like this
<?php
// ...
public function configureFields(string $pageName): iterable
{
// ...
yield new AssociationField::new('products')->setQueryBuilder(function($queryBuilder) {
$queryBuilder
->andWhere('entity.id IN (1,2,3)')
;
})
;
// ...
}

Symfony2 findBy+indexBy

In query builder you can specify which field should be used as array index:
$qb = $em->createQueryBuilder();
$qb->select('s');
$qb->from('models\Settings', 's', 's.key'); // here the magic
$result = $qb->getQuery()->getResult();
//here $result[key] is entity
Anybody knows how to add indexBy(not in DB, but index of array of results) to the findBy method, or make findBy-like method for repository, something like:
$clients = $clientRepository->findBy(['id' => $clients], [indexBy=>id]);
OR
$clients = $clientRepository->myFindByWithIndexBy(['id' => $clients], 'id');
I need a method with filter criteria (where) and it should return entities indexed by id.
Second argument to findBy is for ordering results (indexing in database context is another thing).
$repo->findBy(['id'=>$clients], ['id'=>'asc']); // reverse by changing 'asc' to 'desc'

Sortable Sonata Type Model in Admin

Did someone tried the tutorial about Sortable Sonata Type Model in Admin.
I've followed it step by step without missing anything (I'm pretty sure) but can't get a good result at the end.
Basically what I'm trying to do is : I have 3 entities, Article, Tag and ArticleTag (eq to User, Expectation and UserHasExpectation in the tutorial)
Everything seems good until the UserHasExpectationAdmin:
protected function configureFormFields(FormMapper $formMapper){
// ...
$formMapper
->add('userHasExpectations', 'sonata_type_model', array(
'label' => 'User\'s expectations',
'query' => $this->modelManager->createQuery('UserBundle\Entity\Expectation'),
'required' => false,
'multiple' => true,
'by_reference' => false,
'sortable' => true,
))
;
$formMapper->get('userHasExpectations')->addModelTransformer(new ExpectationDataTransformer($this->getSubject(), $this->modelManager));}
I think an attribute 'class' => 'UserBundle\Entity\Expectation' should be added to 'userHasExpectations' field else Symfony says that it's an invalid value.
Then the other problem is in the dataTransformer:
It launch me the error:
Attempted to call an undefined method named "create" of class "Main\CoreBundle\Form\DataTransformer\TagDataTransformer"
I think a use statement should be added but I don't know which one. More over, suppose I have the right use statement I don't realize what the writer is aiming to do, if it's creating UserHasExpectation records why don't he add a userHasExpectations->setUser($this->User) ???
Also I want to add after "vardumping" $this->Subject before :
$formMapper->get('userHasExpectations')->addModelTransformer(new ExpectationDataTransformer($this->getSubject(), $this->modelManager));
It seems to have a proper Entity Object with all fields on NULL values...
FINALLY SOLVED IT!
So, the code of the tutorial contains many...mistakes
In spite of trying to create 'userHasExpectation' in the DataTransformer we just return the object userHasExpectation in the reverse DataTransformer then we create our records in the postPersist and postUpdate of our Admin Class that way :
/**
* {#inheritdoc}
*/
public function postUpdate($object)
{
$position = 0;
$uniqId = $this->getUniqId();
$request = $this->getRequest()->get($uniqId);
$qb = $this->modelManager->createQuery('MainCoreBundle:ArticleTag', 'at');
$TagsToRemove = $qb->where('at.article = :article')
->setParameter('article', $object)
->getQuery()
->getResult();
foreach ($TagsToRemove as $Tag) {
$this->modelManager->delete($Tag);
}
foreach($request["article_tags"] as $tag)
{
$Tag = $this->modelManager->find('MainCoreBundle:Tag', $tag);
$article_tags = new ArticleTag;
$article_tags->setTag($Tag);
$article_tags->setArticle($object);
$article_tags->setPosition($position++);
$this->modelManager->create($article_tags);
}
}
/**
* {#inheritdoc}
*/
public function postPersist($object)
{
$position = 0;
$uniqId = $this->getUniqId();
$request = $this->getRequest()->get($uniqId);
foreach($request["article_tags"] as $tag)
{
$Tag = $this->modelManager->find('MainCoreBundle:Tag', $tag);
$article_tags = new ArticleTag;
$article_tags->setTag($Tag);
$article_tags->setArticle($object);
$article_tags->setPosition($position++);
$this->modelManager->create($article_tags);
}
}
Hope this will help Somebody who has the same trouble.
#Sonata-admin-team : I hope you will read this and have time to update the tutorial in question.
Thanks,
Epixilog
For Sonata 3 adding the class attribute 'class'=> 'UserBundle\Entity\Expectation' resolved the problem for me.

Doctrine / Symfony: convert custom type to database value before using QueryBuilder

I have defined a custom Doctrine data type for Uuid. When I search for an object using find($uuid), it works correctly, i.e. the attribute is converted using convertToDatabaseValue() before executing the query, and converted back with convertToPhpValue() when value is retrieved.
The conversion doesn't work if I use the QueryBuilder. Example:
$qb = $this->createQueryBuilder('s');
$qb = $qb->where( //some conditions...
$qb->expr()->eq( 's.uuid', ':uuid' ))->setParameter( 'uuid', $uuid );
I found two similar unanswered questions:
Symfony Doctrine datatype only works in findBy not querybuilder
Doctrine 2 Custom Types
It looks like that the conversion is in fact ignored.
How can I force the conversion of the parameter before executing the query? Is there a way to access the convertToDatabaseValue() function of the custom data type from the repository?
Thanks
Yes setParameter() has third parameter, but the type of third param as string is worked for me not the object.
You can do it in following way.
$qb = $this->createQueryBuilder('s');
$qb = $qb->where( //some conditions...
$qb->expr()->eq( 's.uuid', ':uuid' ))->setParameter( 'uuid', $uuid, 'uuid' );
If you dont know what exactly key is for datatype 'uuid' is.
Then use print_r(Type::getTypesMap()); to get list of all dataypes added.
In my case it was
Array
(
[array] => Doctrine\DBAL\Types\ArrayType
[simple_array] => Doctrine\DBAL\Types\SimpleArrayType
[json_array] => Doctrine\DBAL\Types\JsonArrayType
[object] => Doctrine\DBAL\Types\ObjectType
[boolean] => Doctrine\DBAL\Types\BooleanType
[integer] => Doctrine\DBAL\Types\IntegerType
[smallint] => Doctrine\DBAL\Types\SmallIntType
[bigint] => Doctrine\DBAL\Types\BigIntType
[string] => Doctrine\DBAL\Types\StringType
[text] => Doctrine\DBAL\Types\TextType
[datetime] => Doctrine\DBAL\Types\DateTimeType
[datetimetz] => Doctrine\DBAL\Types\DateTimeTzType
[date] => Doctrine\DBAL\Types\DateType
[time] => Doctrine\DBAL\Types\TimeType
[decimal] => Doctrine\DBAL\Types\DecimalType
[float] => Doctrine\DBAL\Types\FloatType
[binary] => Doctrine\DBAL\Types\BinaryType
[blob] => Doctrine\DBAL\Types\BlobType
[guid] => Doctrine\DBAL\Types\GuidType
[geometry] => CrEOF\Spatial\DBAL\Types\GeometryType
[point] => CrEOF\Spatial\DBAL\Types\Geometry\PointType
[polygon] => CrEOF\Spatial\DBAL\Types\Geometry\PolygonType
[linestring] => CrEOF\Spatial\DBAL\Types\Geometry\LineStringType
)
And my doctrine code was something like this.
$queryBuilder = $this->createQueryBuilder('c');
$queryBuilder
->where('st_contains(:polygon, point(c.latitude, c.longitude) ) = 1')
->setParameter('polygon', $city->getPolygon(), 'polygon');
Here's the solution: the function setParameter() has a third argument $type which is used to declare the typology of the parameter. The custom declared type can be retrieved with the getType() function of the Doctrine Type class:
$qb = $this->createQueryBuilder('s');
$qb = $qb->where( //some conditions...
$qb->expr()->eq( 's.uuid', ':uuid' ))->setParameter( 'uuid', $uuid, Type::getType('uuid') );

Choice Multiple = true, create new Entries

My Entity
/**
* Set friend
*
* #param \Frontend\ChancesBundle\Entity\UserFriends $friend
* #return ChanceRequest
*/
public function setFriend(\Frontend\ChancesBundle\Entity\UserFriends $friend = null)
{
$this->friend = $friend;
return $this;
}
My Action
$task = new ChanceRequest();
$form = $this->createFormBuilder($task)
->add('friend', 'choice', array(
'required' => true,
'expanded' => true,
'choices' => $fb_friends,
'multiple' => true,
'mapped' => true
))
->getForm();
Because setFriend is expecting a scalar, I cannot validate this or save it to db. It is an array from how many friends the user want to send a message to somebody. How can I change it?
I have seen here a post:
Symfony2 Choice : Expected argument of type "scalar", "array" given
but this don't work that I put an array in front of \Frontend or $friend. I guess because of the related table.
What do I have to do in Entity to get it work?
If friends could be found in your database (for example it is a User entity), you should declare ManyToMany relationship for these two tables. If not, make friend property to be a doctrine array type. if friends is not a valid entity class, all the rest you have is to make a custom validator and datatransformer. Otherwise you have nothing left to do. All this information you can find in the official symfony and doctrine documentation.
How to create a Custom Validation Constraint
How to use Data Transformers
Association Mapping
Working with Associations

Resources