Buy

Time to put that lazy isPublished field to work. I only want to show published genuses on the list page. Up until now, we've been the lazy ones - by using findAll() to return every Genus object. We've avoided writing queries.

There are a few other methods besides findAll() that you can use to customize things a bit, but look: someday we're going to need to grow up and write a custom query. It's time to grow up.

What is the Repository?

To query, we always use this repository object. But, uh, what is that object anyways? Be curious and dump $em->getRepository('AppBundle:Genus) to find out:

101 lines src/AppBundle/Controller/GenusController.php
... lines 1 - 11
class GenusController extends Controller
{
... lines 14 - 33
public function listAction()
{
$em = $this->getDoctrine()->getManager();
dump($em->getRepository('AppBundle:Genus'));
... lines 39 - 44
}
... lines 46 - 99
}

Refresh! I didn't add a die statement - so the dump is playing hide-and-seek down in the web debug toolbar. Ah, it turns out this is an EntityRepository object - something from the core of Doctrine. And this class has the helpful methods on it - like findAll() and findOneBy().

Ok, wouldn't it be sweet if we could add more methods to this class - like findAllPublished()? Well, I think it would be cool. So let's do it!

Creating your own Repository

No no, not by hacking Doctrine's core files: we're going to create our own repository class. Create a new directory called Repository. Inside, add a new class - GenusRepository. None of these names are important. Keep the class empty, but make it extend that EntityRepository class so that we still have the original helpful methods:

11 lines src/AppBundle/Repository/GenusRepository.php
... lines 1 - 2
namespace AppBundle\Repository;
use Doctrine\ORM\EntityRepository;
class GenusRepository extends EntityRepository
{
}

Next, we need to tell Doctrine to use this class instead when we call getRepository(). To do that, open Genus. At the top, @ORM\Entity is empty. Add parentheses, repositoryClass=, then the full class name to the new GenusRepository:

95 lines src/AppBundle/Entity/Genus.php
... lines 1 - 6
/**
* @ORM\Entity(repositoryClass="AppBundle\Repository\GenusRepository")
* @ORM\Table(name="genus")
*/
class Genus
... lines 12 - 95

That's it! Refresh! Now the dump shows a GenusRepository object. And now we can start adding custom functions that make custom queries. So, each entity that needs a custom query will have its own repository class. And every custom query you write will live inside of these repository classes. That's going to keep your queries super organized.

Adding a Custom Query

Add a new public function called findAllPublishedOrderedBySize():

23 lines src/AppBundle/Repository/GenusRepository.php
... lines 1 - 7
class GenusRepository extends EntityRepository
{
... lines 10 - 12
public function findAllPublishedOrderedBySize()
{
... lines 15 - 20
}
}

I'm following Doctrine's naming convention of findAllSOMETHING for an array – or findSOMETHING for a single result.

Fortunately, custom queries always look the same: start with, return $this->createQueryBuilder('genus'):

23 lines src/AppBundle/Repository/GenusRepository.php
... lines 1 - 7
class GenusRepository extends EntityRepository
{
... lines 10 - 12
public function findAllPublishedOrderedBySize()
{
return $this->createQueryBuilder('genus')
... lines 16 - 20
}
}

This returns a QueryBuilder. His favorite things are pizza and helping you easily write queries. Because we're in the GenusRepository, the query already knows to select from that table. The genus part is the table alias - it's like in MySQL when you say SELECT * FROM genus g - in that case g is an alias you can use in the rest of the query. I like to make my aliases a little more descriptive.

WHERE

To add a WHERE clause, chain ->andWhere() with genus.isPublished = :isPublished:

23 lines src/AppBundle/Repository/GenusRepository.php
... lines 1 - 14
return $this->createQueryBuilder('genus')
->andWhere('genus.isPublished = :isPublished')
... lines 17 - 23

I know: the :isPublished looks weird - it's a parameter, like a placeholder. To fill it in, add ->setParameter('isPublished', true):

23 lines src/AppBundle/Repository/GenusRepository.php
... lines 1 - 14
return $this->createQueryBuilder('genus')
->andWhere('genus.isPublished = :isPublished')
->setParameter('isPublished', true)
... lines 18 - 23

We always set variables like this using parameters to avoid SQL injection attacks. Never concatenate strings in a query.

ORDER BY

To order... well you can kind of guess. Add ->orderBy() with genus.speciesCount and DESC:

23 lines src/AppBundle/Repository/GenusRepository.php
... lines 1 - 14
return $this->createQueryBuilder('genus')
->andWhere('genus.isPublished = :isPublished')
->setParameter('isPublished', true)
->orderBy('genus.speciesCount', 'DESC')
... lines 19 - 23

Query, done!

Finishing the Query

To execute the query, add ->getQuery() and then ->execute():

23 lines src/AppBundle/Repository/GenusRepository.php
... lines 1 - 14
return $this->createQueryBuilder('genus')
->andWhere('genus.isPublished = :isPublished')
->setParameter('isPublished', true)
->orderBy('genus.speciesCount', 'DESC')
->getQuery()
->execute();
... lines 21 - 23

That's it! Your query will always end with either execute() - if you want an array of results - or getOneOrNullResult() - if you want just one result... or obviously null if nothing is matched.

Let's really show off by adding some PHP doc above the method. Oh, we can do better than @return mixed! We know this will return an array of Genus objects - so use Genus[]:

23 lines src/AppBundle/Repository/GenusRepository.php
... lines 1 - 4
use AppBundle\Entity\Genus;
... lines 6 - 7
class GenusRepository extends EntityRepository
{
/**
* @return Genus[]
*/
public function findAllPublishedOrderedBySize()
{
... lines 15 - 20
}
}

Using the Custom Query

Our hard work is done - using the new method is simple. Replace findAll() with findAllPublishedOrderedBySize():

100 lines src/AppBundle/Controller/GenusController.php
... lines 1 - 11
class GenusController extends Controller
{
... lines 14 - 33
public function listAction()
{
... lines 36 - 37
$genuses = $em->getRepository('AppBundle:Genus')
->findAllPublishedOrderedBySize();
... lines 40 - 43
}
... lines 45 - 98
}

Go back, refresh... and there it is! A few disappeared because they're unpublished. And the genus with the most species is first. Congrats!

We have an entire tutorial on doing crazy custom queries in Doctrine. So if you want to start selecting only a few columns, using raw SQL or doing really complex joins, check out the Go Pro with Doctrine Queries.

Woh guys - we just crushed all the Doctrine basics - go build something cool and tell me about it. There's just one big topic we didn't cover - relationships. These are beautiful in Doctrine, but there's a lot of confusing and over-complicated information about there. So let's master that in the next tutorial. Seeya guys next time!

Leave a comment!

  • 2017-07-26 Mateusz Sobczak

    Thanks much for your explanation! It helps me get a better grasp of the bigger picture. And I'll definitely use getRepository helper :-)

  • 2017-07-26 weaverryan

    Yo Mateusz Sobczak !

    Yes, very good question! Eloquent and Doctrine use the 2 different major "types" of ORM. Eloquent is called an "Active Record"... which basically means that when you query, you actually use the class (e.g. Genus). Doctrine is known as a data mapper, where your class (Genus) is just a simple, non-magic class that holds data (and then you do your queries through a different object). Which is better is a major area of debate: data mappers are "cleaner OO code", but take more work. Using static calls that an active record requires is usually not a great idea... but in practice, it usually works well enough.

    So that's the explanation about why there are two objects floating around :). In reality, I usually *do* shortcut things a bit - you can't get as short as Eloquent due to the difference above, but you can get closer. For example, if you create your own base controller (that extends Symfony's normal Controller) and add a protected function getEm(), then you could have this:


    $genuses = $this->getEm()->getRepository(Genus::class)->findAll();

    Or you could even add a protected function getRepository($class) and shorten to:


    $genuses = $this->getRepository(Genus::class)->findAll();

    That's probably about as short as you'll get it - not as short, but a lot closer :). I personally like the data mapper way of doing things because it makes sense to have one object that simply holds data, and another object that's really good at querying (separation of concerns).

    Cheers and welcome to Symfony :)

  • 2017-07-26 Mateusz Sobczak

    Thank you for the video series. It's fun to watch and very informative.

    This is my second day with Symfony. I've used Laravel for a while. I was just wondering if all this code for entity manager is necessary:

    $em = $this->getDoctrine()->getManager();
    $genuses = $em->getRepository('AppBundle:Genus')->findAll();

    I'm used to Laravel where you just type:

    $genuses = Genus::all();

    Is there a shortcut to get rid of the boilerplate code?

  • 2017-07-20 Diego Aguiar

    Hey Dennis!

    Can you show me the error message ?

    I believe you just need to change your "setParameter", instead of passing the categoryId, just pass the whole object, if your relationship is correctly setup, Doctrine already knows what to do.

    Have a nice day :)

  • 2017-07-20 Dennis

    Hi Ryan,

    How can I make a custom query for a pair of entities with manyToMany relation?

    I've got this now:

    return $this->createQueryBuilder('product')
    ->andWhere('product.category = :categoryID')
    ->setParameter('categoryID', $category->getId())
    ->getQuery()
    ->execute();

    But I get an semantical error.

  • 2017-06-27 Diego Aguiar

    Greeeeeeeeeeat!! Keep it going ;)

  • 2017-06-26 Yeison J. Espinoza

    Yes! finally! thanks! now i can continue :p

  • 2017-06-26 Diego Aguiar

    Hey Yeison J. Espinoza

    Finally I could find your problem, you are mixing your entities configuration, you have a YML file that defines your Player entity, but also, you have annotations on it, you have to decide which one you want to use, look's like symfony by default detects yml first, and you are not defining which is it's repository class, so you just have to add this into Players.orm.yml:


    AppBundle\Entity\Players:
    repositoryClass: AppBundle\Repository\PlayersRepository

    Cheers!

  • 2017-06-26 Yeison J. Espinoza

    I'm not getting a way to fix that problem, here is the whole code if some one can check and help
    ---> https://mega.nz/#!hUkijIQb!...

  • 2017-06-20 Diego Aguiar

    Hey Yeison,

    Let's figure it out why this is happening.
    First, try creating a new Entity and a new Repository, but name it in singular i.e. Player, then dump it and let's see if it works.
    If it does not work, I believe it's caused by Doctrine's cache, so run this, and try it again
    $ bin/console doctrine:cache:clear-metadata

    I hope this will do the trick

    Cheers!

  • 2017-06-20 Yeison J. Espinoza

    I did clear cache, and no, not using any cache engine

  • 2017-06-20 Victor Bocharsky

    Hey Yeison,

    Are you trying to do so in dev environment? Because for the prod one you probably need to clear the cache. Actually, I advise you to clear the cache for both dev and prod environments, or better manually remove everything in the cache folder with the next command:

    rm -rf var/cache/*

    Btw, do you use any bytecode cache engines for doctrine annotations, like OPCache or APCu? If so, you need manually clear that cache as well.

    Cheers!

  • 2017-06-20 Yeison J. Espinoza

    The same result, entitymanager :S

  • 2017-06-19 Diego Aguiar

    Hmmm, it looks good

    Could you try my response above ? https://knpuniversity.com/s...

  • 2017-06-19 Yeison J. Espinoza

    I'm in dev environment, next is the config.yml
    https://pastebin.com/Fd4C6km6

  • 2017-06-19 Diego Aguiar

    Hey Yeison,

    Try fetching the EntityManager from the Container instead of injecting it via the ParamConverter, something like this:


    // PlayerController
    public function playersAction() {
    $em = $this->getDoctrine()->getManager();
    $repository = $em->getRepository(Players::class);
    $players = $repository->findAllOrderedByName();
    }

    Cheers!

  • 2017-06-19 Diego Aguiar

    It shouldn't be the case, you are using all the standards, but let me check your config.yml file.
    Are you running in dev or prod environment ?

  • 2017-06-19 Yeison J. Espinoza

    I'm still waiting to get some help :S
    I remake the whole project and follow all steps and still getting EntityRepository instead of my custom Repository

    https://gyazo.com/942c78279...

  • 2017-06-17 Yeison J. Espinoza

    "i dont know why is not recognizing my PlayersRepository, i checked everything, maybe some config?"

  • 2017-06-16 Diego Aguiar

    Alright, so what you mean with "Not recognizing" I see in your dump that your Players entity class is been mapped, what happens when you execute

    $this->em->getRepository('AppBundle:Players')->findAllOrderedByName() 

    Also you don't have to inject the EntityManager into a Controller Method, you can gather it directly from the container


    $this->getDoctrine()->getManager();
  • 2017-06-16 Yeison J. Espinoza

    Symfony 3.3.* current
    Yes is the only dump in the code
    Yes already tried clearing cache

  • 2017-06-16 Diego Aguiar

    Hey Yeison J. Espinoza

    Your repository configuration looks good to me.

    Which version of Symfony are you using ?

    The dump that you printed is for this line ?

    $this->em->getRepository('AppBundle:Players');


    if so, it looks like you are getting the right repository and your code should just work, so I'm guessing that for any reason you are having troubles with the cache (I suppose you are running in "dev" environment), try executing $ bin/console cache:clear

    I hope it helps you, cheers!

  • 2017-06-16 Yeison J. Espinoza

    Hi, i'm doing my own project following you guide, i did try many ways but i'm still getting this:

    Dump: https://gyazo.com/9bf0e8594...
    PlayersController.php on line 28:
    EntityRepository {#347 ▼
    #_entityName: "AppBundle\Entity\Players"
    #_em: EntityManager {#457 …11}
    #_class: ClassMetadata {#369 ▶}
    }

    i dont know why is not recognizing my PlayersRepository, i checked everything, maybe some config?

    PlayersEntity: https://gyazo.com/c9f5917ac...
    PlayersRepository: https://gyazo.com/12e46654f...
    PlayersController: https://gyazo.com/26b36675a...

  • 2017-05-15 Victor Bocharsky

    Hey Cesar,

    The main advantage of ORM is that you operate objects and ORM lib like Doctrine do a lot of work for you. But yeah, it depends on your aims.

    Cheers!

  • 2017-05-13 Cesar Delgado

    Thanks Victor. I am using DBAL now and it's great. Maybe it's because I am not an expert but I couldn't find the advantages of the ORM.

  • 2017-05-03 Victor Bocharsky

    Hey Cesar,

    With Doctrine you get both ORM and DBAL. We explain ORM in this course, it's higher level and more fun. However, ORM is based on the more lower level like DBAL. Actually, you can think of Doctrine DBAL as about PDO, it's just a fancier wrapper for PDO objects. And we have a screencast about using it in your project: https://knpuniversity.com/s... . So if you don't want to use ORM yet, take a look at Doctrine DBAL instead of PDO or other plane PHP for connecting to your database. I think here's the most interesting article in docs for you: http://docs.doctrine-projec... .

    So what about your questions: yes, you can! But you even don't need to configure anything if you want to try Doctrine DBAL since it configured out-of-the-box. But if you still want to write your custom service for it - it's up to you, you can do it as well.

    Cheers!

  • 2017-05-02 Cesar

    Hi. I want to tell you that this track explains Symphony in a really friendly way.

    However, after this Doctrine course, I prefer to use plane PHP for connecting to my database (keep things simpler). But I wonder if I can take advantage of some Symfony features for this. For example, use the parameters.yml file or use a special service?

    Do you have any tutorials about this or any recommendations? I will appreciate it.

  • 2017-03-02 weaverryan

    Nice job Thomas! That is a gotcha of reverse engineering! As soon as Doctrine finds *one* metadata format, it just stops looking for the other formats. Good debugging!

  • 2017-03-02 Thomas

    Hi Ryan, thanks a lot for making this clear.

    Additional I found out why symfony/doctrine was checking the XML Files instead of my Entites ... the XML-Files was created caused by Reverse Engineering of existent database. Thats why doctrine is checking these files instead of using the annotations within entities.

    Now I ran into equal issues while using relationships. Just deleted the XML-Files and now all is fine ;-)

  • 2017-03-01 weaverryan

    Hey Thomas!

    Good find on your solution! You're getting "bit" by a bit of a bad error message. In this chapter (https://knpuniversity.com/s..., we talk about how, out-of-the-box, when you call $em->getRepository('AppBundle\Entity\Genus'), Doctrine returns a generic EntityRepository class. This has a few methods on it, like find(), findOneBy(), findAll(), etc. But as soon as you want to add your own custom methods to this, then you'll create your own repository class (AcmeRepository in your case). But, how does Doctrine know to use *your* class instead of its generic EntityRepository class? The answer: by adding (if you're using XML mapping) the repository-class option to your XML file. If you're using annotations (like we are), then we have that same config above the class (repositoryClass=".."). With this config, Doctrine now knows to use *your* class when you ask for the repository.

    So when you get the The method name must start with either findBy or findOneBy! error, it was because you were calling your custom method on the internal, EntityRepository class. Really, you should have seen a message more like Undefined method findAcmeStuff() on class EntityRepository. With this error, it would have been a bit more obvious that Doctrine was not using your class. But, the EntityRepository has a magic __call method, which allows you to make "magic" calls to it - e.g. you can say "findOneBySlug('foo')" - that method doesn't exist, but the __call method translates it into a findOneBy(['slug' => 'foo']). I never take advantage of this, but it's the reason for the error. You can see it right in the EntityRepository class: https://github.com/doctrine...

    tl;dr; You make the right change! And before this change, Doctrine wasn't using your custom class (so you got this error from the core of Doctrine).

    Let me know if this helps! And Cheers!

  • 2017-03-01 Thomas

    After some research I found the solution. Don't know why but I had to add

    repository-class="AcmeBundle\Repository\AcmeRepository"

    within the <entity>-Key to the Resources\doctrine xml-File. Why?

  • 2017-03-01 Thomas

    Hi Ryan, first of all thanks for the great tutorials. Its fun to learn with. Really great.

    In this one I am stuck. I am using symfony 3.2.4 and went trough this tutorial for creating customer queries. I've added Repository Class and ORM Notation but ... Symfony is telling me:

    The method name must start with either findBy or findOneBy!

    I am out, I have no clue anymore.

  • 2017-01-19 Pierre G.

    Dear Victor,

    I totally understand. Thank you very much for your detailed explanation!

    Cheers

    Peter

  • 2017-01-19 Victor Bocharsky

    Hey Peter,

    Doctrine model, i.e. Genus entity in our case, or any other entity - can't query the database, it's an architectural pattern of Doctrine. To query the database - you need to use entity repository, so you can some default methods in default repository like findAll(), findBy(), etc. *or* extend this default repository with your own, where you can define more custom methods like findAllPublishedOrderedBySize(), etc. Sometimes, for some simple queries, the default repository methods are enough, but if you want write complex queries, use JOIN, GROUP BY, etc. - you will need custom queries.

    Actually, you can write custom queries in controllers, but it's a bad practice, because you mix layers and also you can't reuse your custom queries in this case. So better write it in custom repositories, where you can easily reuse and make them more readable. Actually, that was the advantages of custom repositories.

    I think it's clearer for you now. If you have more questions - let us know.

    Cheers!

  • 2017-01-19 Pierre G.

    Dear Ryan, first of all thank you for your awesome tutorials, they help perfectly to get a grip on Symfony!

    I have more like architectural question regarding the custom GenusRepository you create:

    What, in your words, is the advantage of overwriting the default Repository over just defining findAllPublishedOrderedBySize() as a method of the Genus model?

    Thank you in advance and have a great day

    Peter

  • 2016-10-24 weaverryan

    Hey Terry!

    You got it then :). @ORM\Entity(..) ties the repository to the entity, and then @ORM\Table ties the entity to the table (and so, both put together effectively tie the repository to the table).

    And I *love* the way you said:

    > the query already knows to select from the GENUS Entity's table

    The "weird" (by design) thing about Doctrine sometimes is that it wants you to think in terms of entities and not worry about the database. So, your way of thinking about it here is perfect.

    Cheers!

  • 2016-10-24 Terry Caliendo

    Got it. I was focused on the table name. I knew the @ORM\Entity(...) line tied the two together (but forgot to explicitly state it in my question), and was ultimately verifying that the @ORM\Table(...) statement ultimately tied both the Entity and Repository to a particular table name.

    But at the Repository level, I hear from your answer that I don't need to worry about the table name, just that the Repository is tied to the Entity by the @ORM\Entity(...) statement and the Entity is in turn tied to the table by the @ORM\Table(...) statement.

    Thus, when you said "the query already knows to select from that table", I shouldn't have been thinking about a particular table but interpreted it as "the query already knows to select from the GENUS Entity's table (whatever name it may have).

    Thanks for the clarification.

  • 2016-10-24 weaverryan

    Hey Terry!

    You are thinking about the problem *perfectly* and are *so* close to being correct :). It knows because of the @ORM\Entity annotation on Genus (not the \Table annotation):

    /**
    * @ORM\Entity(repositoryClass="AppBundle\Repository\GenusRepository")
    * ...
    */
    class Genus

    We add this right after creating the repository class (https://knpuniversity.com/s.... So, the GenusRepository class can live anywhere, and we connect that repository class to our Genus entity with that annotation. If you take away that annotation, Doctrine will fallback and use the generic, core EntityRepository class (which is what it's been using up until this point).

    Let me know if that makes sense! I like that you're questioning it :).

    Cheers!

  • 2016-10-22 Terry Caliendo

    When you create the Repository and Subsequent GenusRepository folders, you say the names are not important. Then when you are in the findAllPublishedOrderedBySize method within GenusRepository and call the createQueryBuilder('genus') you say that because "we are in the GenusRepository, the query already knows to select from that table". How does it know? It can't be because of the repository name, because you said the name was arbitrary. There's nothing else in that file that would indicate the 'genus' table. Thus, I assume it knows because of the @ORM statement at the top of the Genus Entity @ORM\Table(name="genus"). Am I correct? If so (or even if not) I could use a bit more clarification.

  • 2016-07-08 Sergio Medina

    You're a legend mate!
    That worked just great!

    Never mind the other question just find that it was my bad, haven't defined the relationship on the entity =( It works all good now!

  • 2016-07-07 weaverryan

    Hi Sergio

    Is this a custom "formatter"? So you have something like this in your YAML: <account()>?

    My guess is that Alice actually "flushes" all of the data at once. What I mean is, even though Alice may have parsed your YAML file for the CoreBundle:Account entity, these have not actually be flushed to the database yet. So, there's nothing in the database to query.

    Typically, you relate entities by using the '@' symbol in YAML - http://knpuniversity.com/sc...

    Any reason why you can't do it that way?

    Cheers!

  • 2016-07-07 Sergio Medina

    Hi again Ryan!
    I've got an annoying problem =( I'm trying to use Fixtures + Alice and while doing simple things it works perfect, when I try to query an entity to populate other tables I get and empty array.

    I have followed the documentation and added:

    use Symfony\Component\DependencyInjection\ContainerAwareInterface;
    use Symfony\Component\DependencyInjection\ContainerInterface;

    I'm doing this:

    public function account()
    {
    $em = $this->container->get('doctrine')->getManager();

    /** @var \App\Bundle\CoreBundle\Entity\Repository\AccountRepository $account */
    $account = $em->getRepository('CoreBundle:Account')->find(1);

    return $account->getId();
    }

    But all I get is an empty array:
    array(0) {
    }

    Any ideas what may I be doing wrong? Thanks in advance for your help.

  • 2016-06-22 Victor Bocharsky

    You're welcome! Keep learning :)

  • 2016-06-22 Dominik

    thank you, Victor :)

  • 2016-06-21 Victor Bocharsky

    Hey, Dominik!

    Ah, it was a bad cache. I fixed it!

    Thank you for reporting it!

  • 2016-06-21 Dominik

    Hello Ryan!
    I got a problem - can't see any script on this page. Can you fix this, please?

  • 2016-06-01 Raphael Schubert

    Thank you Ryan! I`m not a good guy when talking about Database... maybe there is how to do what i`m doing in a best way.... But thanks... I`ll have a look in that tutorial... i need learn more also about Symfony Services... Create objects that will be shared across all the application... i`ll take a look in that tutos also... thanks

  • 2016-06-01 weaverryan

    Yo Raphael!

    For tough queries like this, where you don't expect to get back an object (but instead, an array), it's *ok* if you need to make straight SQL queries. So, I honestly wouldn't worry too much about this, as long as you're not doing too much of this stuff. Btw, even if you are writing SQL queries, I highly recommend putting this inside repository methods - like http://knpuniversity.com/sc....

    However, I will say that I don't fully understand your schema setup, but this query *does* look pretty complicated, even in SQL - it's a bit confusing to look at :). It's possible that your database schema could be setup better to make this query easier. But again, I only have a small part of the whole picture :).

    Oh, and you *could* probably write a query like this with DQL or with the query builder. I was going to try to translate it for you, but it's such an odd query (because the FROM is actually selecting a sub-query), that it's actually a bit hard for me too :).

    Cheers!

  • 2016-06-01 Raphael Schubert

    Hello Ryan! One more time i`m here...

    I`m in love with symfony... but i still have some doubts... i learned how to do some querys... But now i need perform some advanced querys...

    For sample... I did implemented this query:


    $em = $this->getDoctrine()->getManager();
    $query = "SELECT *, COUNT(1) AS count
    FROM ( SELECT * FROM visualizacoes WHERE idperfil = $idperfil ) a
    GROUP BY idusuario, idperfil, data";

    $stmt = $em->getConnection()->prepare($query);
    $stmt->execute();
    $stmt->fetchAll();

    How can i implement it with doctrine? because the result of this will be an list of how much times a people viewed an profile... but a profile can have lots of views from lots of users....

    i really wanna implement it in SF3

    Thanks!

  • 2016-05-18 weaverryan

    Hi Kosta!

    My pleasure - I'm so happy you this stuff is useful for you!

    Ok, about your situation: Do you have a ManyToOne relationship from Memo to User? It *sounds* like you a just storying the id of the user, and not using an actual Doctrine relationship. In the database, both options result in the same structure: your memo table will have a user_id column. But if you map this as a true ManyToOne relationship, then you *should* be able to say (in php( $memor->getCreatedBy()->getUsername(). Or, equivalently in Twig, memo.createdBy.username.

    If I'm right that you're not using a ManyToOne relationship, then check out: http://knpuniversity.com/sc.... But if you *do* have this relationship mapped correctly, you should be able to simply say {{ memo.createdBy.username }} to print out the username of the user who created this memo.

    Let me know if this helps!

  • 2016-05-14 Kosta Andonovski

    hey again ryan, I am so thankful for all our help and tutorials brother they are awesome! I have come to a little problem and I know the answer is simple. I have two databse tables memo and users. when a memo is made it saves the id of the user who made it. eg.1, now if I'm viewing the memo list on the html page. I can see the message and under the html colum "created by" - it will show currently the number 1. not the name of the user because the memo db table only has stored the number 1. My question is what is the best way to get all the details of that user (from the users table) so that I can display his name. Should I create a public function getAuthor() and place it inside the entity class memo.php or do I get it inside the controller for that page. Also if there is already a tutorial that covers this similar thing as it would happen all the time, can you point me to the tutorial, thank you so much for everything!

  • 2016-05-05 weaverryan

    Hi Kosta!

    Yes, really good question! There is only *one* reason I do this: PHPStorm auto-completion. Doing this doesn't change any behavior in my application. But now, when I call the findAllPublishedOrderedBySize() method, PhpStorm knows that it returns an *array* of Genus objects - the [] tells it that it's an array. If I iterate over that array, PhpStorm will auto-complete the methods on the Genus object :). So basically, I *love* autocompletion, so I do these types of things.

    Cheers!

  • 2016-05-05 Kosta Andonovski

    Hello again! Towards the end of the tutorial you replace @return mixed with @return Genus[], in the GenusRepository.php - I dont fully understand why this has been done. I understand where it automatically adds use AppBundle\Entity\Genus; Is there any other reason you did that? Thank you so much for all your help sir!

  • 2016-04-15 Neandher Carlos

    Thank you for the answer '')

  • 2016-04-15 weaverryan

    Hi there!

    You're absolutely right! The first way is taught more commonly because it's easier to be returned objects (it's nice when you're working with the same object 99% of the time, instead of an array with certain fields) *and* performance often doesn't matter. I'd recommend doing the first way *until* you find that you need to increase performance. And once you know that you need more performance, I'd also recommend using Blackfire.io to identify what's slow: you might find that the queries are not the problem anyways :).

    Cheers!

  • 2016-04-15 Neandher Carlos

    This return all object, but maybe unnecessary fields.

    $qb = $this->createQueryBuilder('cat')
    ->leftJoin('cat.fortuneCookies', 'fc')
    ->addSelect('fc');

    This return array, but only with the fields i want.

    $qb = $this->createQueryBuilder('cat')
    ->select('cat.id')
    ->addSelect('cat.name')
    ->leftJoin('cat.fortuneCookies', 'fc')
    ->addSelect('fc.id')
    ->addSelect('fc.fortune');

    I believe, about perfomance, second option is better. But many courses teach only the first option.