Doctrine2 Querying in entities - symfony

I'm using SF2.1 with Doctrine2
I have 2 entities : Category and Article, linked with a oneToMany relation.
I want to retrieve all articles of a specific category, but only the published ones ....
I show you what I do for the moment :
// in /Entity/category.php :
public function getAllArticlesPublished(){
$articles = array();
foreach($this->getArticles() as $article){
if($article->isPublished()) $articles[] = $article;
}
return $articles;
}
Is this the good way to do it ? It doesn't look good to parse the whole array of Articles ... but I don't want to do this in the repository becauseit concerns a specific Category.
Any hint for me ?

You might take a look at Filtering Collections. If it doesn't solve your problem, then a repository would be the best place for stuff like this.

Related

Bug in AssociationField with autocomplete() for Many to Many field in EasyAdmin

I have an entity called Question which has a Many to Many relationship with another entity User. So I have following tables:
question(id, field1, users)
user(id, name)
question_user(question_id, user_id)
I use EasyAdmin for creating QuestionCrud form where I use AssociationField for assigning multiple Users to a Question. If I use AssociationField without autocomplete() method it works like a charm and stores the data. But I have really big amount of data in User table and that's why need to use autocomplete in order to load only small amount of data.
Using autocomplete() with AssociationField giving following error and giving validation error on a form submit:
The choices 123, 2323 do not exist in the choice list.
123, 2323 are IDs of the selected users.
Has anybody faced such a problem?
A month ago another developer faced the same problem - https://github.com/EasyCorp/EasyAdminBundle/issues/5467. He proposed to edit vendor file src/Form/EventListener/CrudAutocompleteSubscriber.php and thanks to his investigation on what was wrong with autocomplete() method on many-to-many relationship we came out with another solution.
Instead of editing a vendor file we decided to override findBy method of the Entity repository.
public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
{
if (isset($criteria['id']) && is_array($criteria['id'])) {
$ids = [];
foreach ($criteria['id'] as $id) {
if (Uuid::isValid($id)) {
$ids[] = Uuid::fromString($id)->toBinary();
} else {
$ids[] = $id;
}
}
$criteria['id'] = $ids;
}
return parent::findBy($criteria, $orderBy, $limit, $offset);
}
This solution is good as far as you have only one Entity which is used as many-to-many relationship, but if there are several entities, then the findBy method should be overridden in all of them.
Hope that supporters of EasyAdmin will fix this bug soon and we will not need to use such 'ugly' solutions.

Symfony - Read-only entities hydrated from YAML

Is it possible to have simple read-only entities, that can have an association with an other doctrine entity, but their data is stored in a text ( YAML ) file ?
Let's say I have a product entity, and I want to set a category for each product. But for now, I only have very few categories ( and don't need to edit or add ), so I don't want/need to create a full doctrine entity with it's own table in the DB.
So I create a very simple entity:
class ProductCategory
{
private $id;
private $name;
public function getId()
{
return $this->id;
}
public function getName()
{
return $this->name;
}
}
Now I would like to create a simple YAML file where the data is stored, like so:
0: Cheese
1: Meat
2: Dairy Products
....
Then I would like to set a ManyToOne relation from the product entity to the ProductCategory entity.
Is that possible ?
And, how to "query" the categories ? ( let's say I want to list all categories that start with a certain letter )
'Why' you ask ?
Well for now, as I said, I only have very few categories, but maybe some day I want to add many more, and even have a CRUD editor for them and so on, then I could easily convert it to a full doctrine entity.
Or any other suggestions on how to approach this ?
There is already a library that provides what you are looking for that's called Alice:
https://github.com/nelmio/alice
https://github.com/hautelook/AliceBundle
https://github.com/fzaninotto/Faker
https://github.com/h4cc/AliceFixturesBundle
This way you can create random test data en masse and can still work with Doctrine as usual.
If you want to do this manually it will be a pain to solve the problem of connecting the entities. Your best bet is to keep all of them in arrays with id's being used as keys but even then you will probably end up writing lots of glue code to connect the entities.

link between QueryBuilder parameters

public function Bycategorie($categorie)
{
$qb = $this->createQueryBuilder('u')
->select('u')
->where('u.categorie = :categorie')
->orderBy('u.id')
->setParameter('categorie',$categorie);
return $qb->getQuery()->getResult();
}
I want to know what the link is between:
$categorie, u and the entity in which I'm working,
Your question is related to Doctrine. About association mapping you can read here
In your example relation can be One-to-One (in theory) or Many-to-One (many users can obtain the same category). Many-to-One relation is more preferable variant and has a logical explanation.
helo, i have found what i was searching for.
my question was : what is the link between querybuilder parameters.
in my example i find that in the where clause (where('u.categorie =:categorie'))
'categorie' of the left(in the parenthesis) must be a colum of a table in my database.
thanks for your helps.

Doctrine Translatable how to only fetch records with a translation

I'm using Symfony2 + Doctrine + Translatable from DoctrineExtensions.
I have an entity article which has a couple of translatable fields like Title and Content. What is happening now is that I've created a bunch of articles in Chinese language, but have not added a translation for English. This is giving me some problems when I try to display a top 8 most recent articles on my homepage... When I view my homepage in English, it will show a bunch of title-less articles there (the Chinese articles that dont have a translation in English).
I found a solution for this in the Translatable extension by using ORM query Hint:
"\Doctrine\ORM\Query::HINT_CUSTOM_OUTPUT_WALKER".
This lets you directly query the translated fields of your entity which are actually stored in ext_translations and not in the entity's table.
As a result the code I use to fetch the articles for the homepage looks like this:
public function getNewestArticles($limit = 1){
$dql =
"SELECT a FROM NewsBundle:Article a
WHERE a.published = 1
AND a.title != ''
ORDER BY a.created_at DESC";
$query = $this->_em->createQuery($dql);
$query->setMaxResults($limit);
$query->setHint(
\Doctrine\ORM\Query::HINT_CUSTOM_OUTPUT_WALKER,
'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker'
);
$result = $query->getResult();
return $result;
}
This actually works, but the generated query is so inefficient that it slows down the page a lot... I'm talking 1800 ms for that query. I've also tried to just put the fields I need in the select statement, which improves the performance, but still not enough.
Any ideas?
you can try to optimize the query manually. use locale as the parameter in your repository
public function getNewestArticles($locale, $limit = 1){
//your own superfast query
}
in the controller then set the locale with
$locale = $request->getLocale();
$em->getNewestArticles($locale, $limit);
additional question: have you set indexes on your tables?

Symfony2.1 Circular references

I'm wondering how to avoid having a circular reference in my symfony2.1 application.
I have an entity like
customer (
name
addresses -- OneToMany
currentAddress -- OneToOne )
and
address (
street
customer -- ManyToOne )
Now my fixtures won't load because it can't delete the customer because of the foreign key.
For performances' sake I would like to avoid having to add a getCurrentAddress() method on customer which would select in the addresses table.
Does anybody have a solution for that?
Adding a getCurrentAddress() isn't such a performance issue.
This way, I'll avoid the circular reference and all the issues that come along with it.
In my situation, using an order by date in the doctrine annotation was enough:
// on customer entity :
/** #ORM\OrderBy({"datemodified" = "DESC"}) */
private $addresses
public function getCurrentAddress()
{
return $this->addresses[0];
}

Resources