Doctrine & the Database

1:56:34
Buy Access

Two episodes down! Booya! And we are super ready to put our new skills to the test! It's finally time to make up app come alive by using Doctrine to connect to a database.

Doctrine is an amazing ORM that works great with Symfony and is super powerful. It also has a reputation for being hard to learn and for making you write a lot of code. But that's changing! Thanks to some recent improvements and Symfony Flex, working with Doctrine has never been easier or more rewarding. So, let's get started!

  • Creating (and updating) Entities with make:entity
  • Generating & using migrations
  • Inserting new data
  • Fetching & Querying for data
  • Doctrine Repositories
  • Custom queries and the query builder
  • Fixtures (Dummy data) using Faker
  • Relationships & Associations

Your Guides

Ryan Weaver

Questions? Conversation?

  • 2018-10-30 Paweł Chry

    Damn good and exhausting answer. Thank You!

  • 2018-10-29 weaverryan

    Hey Paweł Chry!

    Fascinating question! Let me answer with various points:

    1) Does it make sense for you to map each table to a database class?

    Maybe. In some projects, it's quite common to be consistent working with the data for one table. Like, "Hey! Give me the data from the product" table. But, in other projects - especially if you have a complex or legacy database - you are more commonly grabbing data from many different tables and using them all at once. In that context, it's probably not that helpful.

    2) How to organize Symfony project without ORM (Doctrine) to keep controllers clean and slim?

    In general, the important thing is this: create "model" classes (by this I mean a class that holds data like a Doctrine entity, but is just a normal PHP class) that are meaningful to your "business logic". If this matches your database table structure (e.g. a "product" is a meaningful concept in my code and I also have a "product" table), great! If it does not match your table structure, no big deal. Here's a nice way to think about it: if you aren't modeling your database to PHP classes currently, then you are probably passing around a lot of associative arrays of data. For your application, those arrays are meaningful. And if you are commonly passing around an array with more or less the same data in it, this is probably an "important concept" in your app, and you could convert it into a class. For example, suppose you query 5 database tables at once to retrieve a bunch of "product shipping information". Cool! It might be helpful to create a ProductShippingInfo class and put the data onto that class instead. Then, instead of passing that array around, you are now passing a class around.

    So, my general advice is this:

    A) Find patterns of data that you fetch from the database. And, if it's helpful, start returning those things as objects. And, the same is true in the other direction: if accept 20 parameters from a form, consider creating a class and putting that data into a new instance of the class. And *then* passing it around to your system.

    B) And apart from creating "model" classes, create a rich service layer. Basically, each time you need to "do" something, put that code into a service class. I also (outside of Doctrine) still follow the Doctrine "repository" method where I have a class that holds all of the queries for each table (so 10 tables == 10 repository classes). This is easy to do even outside of Doctrine. Though, again, if your more commonly querying from 5 tables, then maybe you follow this idea, but it doesn't really match your database structure.

    So, here is a "pretend" before and after. Before:


    $name = $request->request->get('product_name');
    $price = $request->request->get('price');
    // 10 other fields

    $pdo->query('INSERT INTO ...'); // then you build the query to pass these 10 things

    After:


    $name = $request->request->get('product_name');
    $price = $request->request->get('price');
    // .. 10 other fields

    $product = new Product($name, $price, ...);

    // this service class has a nicely-named method and receives a Product class
    // it would take care of the ugly query inside
    $productManager->createNewProduct($product;

    It's not a science, and there are people that are much better at this than I am. But, generally, turn "data" into classes & objects. And put all of your "work" into service classes.

    I hope this helps!

    Cheers!

  • 2018-10-27 Paweł Chry

    Hi, have You maybe wrote something about: How to organize Symfony project without ORM (Doctrine)? My company use Symfony without orm (with plain sql) and as a Symfony developer I have problem how to keep controller slim and clean. I mean with Doctrine I have Entities that have relations etc. Should I still map sql tables as classes? How about controller who receive request with 20 parameters from form, and whose job is to persist it, and by persist I mean sql procedure including 5 tables. Should I map tables as classes and in controller full these objects with request params? That would be mess. And for what benefits, if my job is to pass parameters to procedure. My general question is: How to organize Symfony project without ORM (Doctrine) to keep controllers clean and slim?

  • 2018-10-22 weaverryan

    Yo bob!

    Wow! That's a new error for me! Oh boy, it looks like MySQL 8.0.4 my have changed the default way that you send your password to them :/. Here is some info on how people are fixing / working around this:

    * https://github.com/laradock...
    * https://stackoverflow.com/q...

    Also, this was apparently fixed in PHP 7.2.4 - you can read a bit about that here: http://php.net/manual/en/re...

    Hopefully one of these will give you an easy fix! It's too early in this tutorial to hit a big snag - you haven't had any fun yet!

    Cheers!

  • 2018-10-20 bob

    While trying to create the database using ./bin/console doctrine:database:create i get a couple of errors:
    The server requested a authentication method unknown to the client [caching_sha2_password

  • 2018-08-24 weaverryan

    Hey Jimmy Silva!

    Ah, so happy to hear it! If you have any questions, thoughts or suggestions, definitely let us know down in the comments (or shoot us an email).

    Cheers!

  • 2018-08-22 Jimmy Silva

    weaverryan I just signed up and loving your tutorials

  • 2018-06-04 weaverryan

    Hey Sławek Grochowski!

    GREAT question. I was having that same thought after writing it this way :). If I were to recreate this function to be more flexible, I would probably just force the user to do this step. So, it would look more like this:


    $this->createMany(10, function($i) {
    $article = new Article();
    // ...

    return $article;
    });

    Then, the createMany() function would look at the class of the object that was returned to know how to store it as a reference :). I think this is just as easy, but more flexible.

    Cheers!

  • 2018-06-02 Sławek Grochowski

    function createMany is pretty nice, but what about Entities which require arguments in constructor?

  • 2018-04-23 Victor Bocharsky

    Hey Prout,

    Yes, we have the one but in Symfony 3 track. This course was recorded in a Symfony 4 way using Flex and our new "The Spacebar" Symfony 4 project.

    Cheers!

  • 2018-04-22 Prout

    I thought there was already a "Doctrine & the Database Tutorial". Is it an update ?

  • 2018-04-20 Diego Aguiar

    Hey Hermen

    Haha, you "may" be lazy but it's our fault as well. For some reason it wasn't added to the track, but I just did it!
    Thanks for reporting it :)

    Have a nice day

  • 2018-04-20 Hermen

    Why is this course not listed in the Symfony 4 track? I have a hard time finding it (or I'm just lazy)...

  • 2018-03-28 Paweł Chry

    Thank You!

  • 2018-03-28 weaverryan

    Hey @pawechry!

    If you need to write raw SQL, I always say, just do it instead of using the Query Builder :). But yea, you have the special problem where the EntityType is *forcing* you to use the QueryBuilder. So, your best option is to

    instead of specifying the query_builder option, just query for the entities that you need with your custom query and pass them directly to the choices option: https://symfony.com/doc/cur.... You'll need to dependency inject the entity manager or your repository into your form class to make this query. Also, the tricky part is that, Symfony *does* need the entity objects in order for the EntityType to work. So, you'll need to write your custom query to only select the id field, then make another, normal query where you return all of the actual entity objects that match that array of ids.

    If you really want to completely avoid querying for entities, then don't use the EntityType, just use the ChoiceType. But then, you'll need to use a data transformer to ultimately transform the submitted value back into an entity - https://symfony.com/doc/cur.... So.... using EntityType is easier :).

    Cheers!

  • 2018-03-28 Paweł Chry

    Hi, I need to place a query (that is not possible to write with doctrine entities(?)) in the symfony form query_builder.

    SELECT `id` as `categoryId`,`name`,`parent_id` as `parentId`,
    ( SELECT LPAD(`intra_document_category`.id, 5, '0')
    FROM `intra_document_category` parent
    WHERE parent.id = `intra_document_category`.id
    AND parent.parent_id = 0
    UNION
    SELECT CONCAT(LPAD(parent.id, 5, '0'), '.', LPAD(child.id, 5, '0'))
    FROM `intra_document_category` parent
    INNER JOIN `intra_document_category` child
    ON (parent.id = child.parent_id)
    WHERE child.id = `intra_document_category`.id AND parent.parent_id = 0 ) AS level2
    FROM `intra_document_category` order by level2

    Is it possible to write raw SQL inside query_builder symfony form type? If not, then what is an alternative?

    NATIVE SQL http://docs.doctrine-projec... is the answer?

  • 2018-02-20 weaverryan

    Hey Mauro!

    Yea, these commands are still being updated to work with Symfony 4. The big issue is actually pretty simple: you don't have a bundle in Symfony 4 :). Here are some more details: https://github.com/doctrine....

    So, as you can see there, right now, there are some workarounds, like temporarily creating a bundle. But pretty soon, I hope it will be updated to work without a bundle.

    Cheers!

  • 2018-02-16 Mauro

    Hi guys,
    how can i import an existing database in Symfony 4?
    In Symfony3 you can do:

    php bin/console doctrine:mapping:import --force AppBundle xml
    php bin/console doctrine:generate:entities AppBundle
    php bin/console doctrine:mapping:convert annotation ./src

    but those commands don't work in Symfony4.

    Thanks.

  • 2018-02-13 weaverryan

    Hey ali nizar!

    You can read about all of that here: https://symfony.com/doc/cur.... The configuration in that article will need to be a bit different to support environment variables, but hopefully it will get you started. For autowiring all the entity managers, I would use a bind rule (https://knpuniversity.com/s... to bind to argument names - like $adminEntityManager if you had an em called "admin".

    Cheers!

  • 2018-02-13 weaverryan

    Hey Peter Kosak!

    This is next in the Symfony series - and I want to get it out soon. But, it will be at least several weeks, for two reasons. First, we'll release the Webpack Encore & React tutorials first. And second, there's a pull request on MakerBundle that we really *need* for this tutorial. So, it needs to be merged and released still. But I'll try to get it all done as quickly as possible :).

    Cheers!

  • 2018-02-13 ali nizar

    hi,
    how can i use Multiple Entity Managers and mutiple databases

  • 2018-02-13 Peter Kosak

    When will be this course available? Cant wait

  • 2017-11-16 Diego Aguiar

    You may need to create a model class that maps all the fields you need for this form, then create a FormType based on that class, it can contain embedded forms of your entities so you don't repeat yourself.
    You can watch an example of creating an embedded form here: https://knpuniversity.com/s...
    or in the symfony docs: https://symfony.com/doc/cur...

  • 2017-11-15 Peter

    Thank you for response.

    Let me explain, I would like first - to prepare my spider of manufacturers, then add categories to them, and then - types, or models to categories.

    I'm (mostly) not shure how to handle doctrine to write those three entities in the same time. - I have already made the may-to-one relations from last category entity to manufacturer, gave fields passing right Object to 'set' methods in entities

    I sow in this tutorial on #3 or #4 episode smth that can help me:

    $em->persist($ob1),
    $em->persist($ob2)

    but how handle the form if I want set only manufacturer? - is it possible?, or better way is just make special form for manufacturer?.

    Ajax in symfony is a little bizzare for me...

  • 2017-11-15 Diego Aguiar

    Great!
    For that case I would do it with JS, because you need to generate your forms dynamically. You gonna need an extra endpoint (backend) where you can pass the options selected by user, and then return a rendered form as the response of the AJAX call (I'm assuming you are familiar making AJAX calls, if not, you can watch our JS tutorials, they are awesome!)

    Cheers!

  • 2017-11-15 Peter

    Hi, Yes Diego that is correct.

  • 2017-11-14 Diego Aguiar

    Hey Peter!

    Let me see if I understood you well. What you need is like a three steps form, where you have to choose an option first, so next form (step) gets filled up based on the chosen option (because they are related), and for step three is the same formula. Am I correct?

    Cheers!

  • 2017-11-14 Peter

    BMD = BMW ; -)

  • 2017-11-14 Peter

    I already know that I can use EntityType, I'm confused how pass to next part of form variable.
    For example 1st is id of BMD category, so next part of form need to have only BMW matches and so on

  • 2017-11-14 Peter

    Hi Ryan and Leanna, Victor,
    thank you for your courses and great effort and work.

    It woud be great to hear some advices from You.

    I gave 3 entities.

    1) Manufacturer, 2) manufacturerModel, 3) ManufacturerModelTyp

    they connected many-to-one from 3->2->1
    so for example product will looks like

    1) BMW,
    2) seriie 5
    3) E12

    and product table (entity) have separate fields for id1, id2, id3

    how to handle with that kind of relation in form?

    some advices, links to examples?

    best regards,
    Peter

  • 2017-11-07 weaverryan

    Hey Xal!

    Sorry for the late reply - for some reason Disqus put your comment in Spam :(. The latest version of Alice indeed contains a lot of changes. See our note about it near the top of the script - https://knpuniversity.com/s.... Basically, we recommend using the older version for following the tutorial :).

    Cheers!

  • 2017-11-06 Diego Aguiar

    Yes, you should be able to keep your relationships in the base class only. Try configuring your base class with these annotations


    /**
    * @Entity
    * @InheritanceType("SINGLE_TABLE")
    * @DiscriminatorColumn(name="discr", type="string")
    * @DiscriminatorMap({"person" = "Person", "employee" = "Employee"})
    */

    You can follow the steps here: http://docs.doctrine-projec...

    Cheers!

  • 2017-11-06 Ferdinand Geerman

    Hey Diego,

    I tried that already, the Single Table approach, but without any success

    I have a abstract BasePerson class (/*@MappedSuperClass*/) and a abstract BaseAddress (/*@MappedSuperClass*/)
    In the BasePerson I have an $address property. I tried to set the relation as follow:

    /**
    * @ORM\OneToOne(targetEntity="BaseAddress")
    * @ORM\JoinColumn(name="address_id", referencedColumnName="id")
    */

    For my project I have the subclasses Person and Address (/**@ORM\Table(name="person") @ORMEntity() */
    /**@ORM\Table(name="address") @ORMEntity() */)

    When I do doctrine:migrations:diff i get the error:

    [Doctrine\ORM\ORMException]
    Column name `id` referenced for relation from Entity\Person towards Entity\BaseAddress does not exist.

    I guess the Person entity tries to access the BaseAddress entity, which is not an entity. That's is the reason I defined the relation in the subclass Person to the subclass Address.

    Is there a way to define that relation solely in the abstract classes, so that the subclasses person and address inherit the relation?

  • 2017-11-06 Diego Aguiar

    Hey @ferdinandgeerman

    You are correct, the Base class should be the only one holding the relationship, but, you will need to configure your entities in a special way (I believe it's not covered in this course)
    Doctrine give us a way to manage subclass entities, there are two ways, via single table or multiple tables (each for subclass). Of course this depends on your use case, but if you are not going to add extra fields specific to every subclass (only different behaviour), you should consider using "Single Table" approach.

    You can read more detailed information for how to implement it here: http://docs.doctrine-projec...

    Cheers!

  • 2017-11-06 Ferdinand Geerman

    Hi Ryan,

    A very nice tutorial!
    Just one question, could you give me some more insights about the relation between abstract entities?
    Consider the following situation:
    BaseClassA has a relation to BaseClassB, in which all the subclasses will inherit that relation. However when I run the doctrine:migrations:diff or doctrine:schema:update I get an error about:
    Column name `id` referenced for relation from SubClassA towards BaseClassB does not exist. Both base entities has the protected $id property. Right now I defined the relation in the subclasses to make it work, but I suppose the relation should be in the abstract entities, right?

  • 2017-10-29 Xal

    I couldn't get the dummy data fixtures work with the latest version of alice. I've changed the code to use NativeLoader instead of Fixtures, but when trying to run doctrine:fixtures:load from the console I get a [Symfony\Component\Debug\Exception\ContextErrorException] Notice: Undefined offset: -5 error. Any ideas?

  • 2017-09-01 Diego Aguiar

    Oh, a permissions problem, of course!
    Things like that happens all the time. I'm glad to hear you could fix your problem :)

    Have a nice day!

  • 2017-09-01 Weli Orlu

    I have dicovered the problem. It was caused by improper permissions on the cache directory. Reinstalled everything using composer

  • 2017-08-28 Diego Aguiar

    Hey @weliorlu

    When running in dev mode, you shouldn't be worry about clearing cache (except for a few cases), can you double check that you are hitting the correct route? and can you tell me more about those changes?

    Cheers!

  • 2017-08-27 Weli Orlu

    Hi Ryan and Leanna. I have been following through the course but now changes in my controller doesn't give a corresponding response. I have deleted emptied the cache directory. then ran bin/console cache:warmup --env=dev followed by bin/console cache:warmup --env=dev. With no change in response

  • 2017-06-26 weaverryan

    Awww, cheers! Thanks for the very nice comment - I'm very happy the tutorial is useful!

  • 2017-06-26 Yan Yong

    Hi Ryan and Leanna, Just want to say thank you for creating this tutorial. I have finished it without any trouble. I learned a lot by doing it, please keep working on it, this is very helpful.

  • 2017-04-11 Diego Aguiar

    Hey Claire!

    In this course we don't go through deleting a Genus, but there is other tutorial where we cover a lot more about working with entities "Doctrine Collections", it is a bit more advance topic but you can find it very helpful and fun!
    Check this chapter, it shows how to remove an item from an entity collection:
    https://knpuniversity.com/s...

    Have a nice day!

  • 2017-04-11 claire

    Hi,

    Fantastic tutorials, it been a great way of learning Symfony ! I was wondering (you probably already have it covered and I am being blind) if you cover 'deleting a genus'?

    Cheers
    Claire

  • 2017-02-21 Victor Bocharsky

    Yes, exactly what I mean! The query builder allows us easily do it. Thanks for sharing it ;)

    Cheers!

  • 2017-02-20 Sergey

    I already found =)
    https://knpuniversity.com/s...

  • 2017-02-20 Victor Bocharsky

    You're welcome! Btw, in some course we already do similar refactoring in a repository class (which I explained above) to get rid of code duplication, but to be honest, I don't remember what course and what chapter it was. :)

    Cheers!

  • 2017-02-20 Sergey

    Thank you for quick feedback!!

  • 2017-02-20 Victor Bocharsky

    You're absolutely right ;)

    Cheers!

  • 2017-02-20 maxii123

    Ignore. You have to open a specific video first and there it is. Thank you.

  • 2017-02-20 maxii123

    Where is the downloadable course script pdf for this tutorial?

  • 2017-02-20 Victor Bocharsky

    Hey Sergey,

    Yes, the findAllPublishedUpdatedMoreThan() method sounds great! What about duplicated logic - well, you can move duplicated code into the private method inside your repository method if you use query builder. So this way you'll get rid of code duplication - your public methods will contain only unique conditions and reuse private method which shares common logic.

    Cheers!

  • 2017-02-19 Sergey

    Hi. Thanks a lot for great course. But i have a question.

    In last lesson "Custom Queries" we created findAllPublishedOrderedBySize method which return all published Genuses.

    What is the best way to have a method for getting all published Genuses that were update more than 3 months ago?

    Should i write another one findAllPublishedUpdatedMoreThan($date) {} ?

    It's so looking so strange... Because in this way i need to duplicate published logic and do it every time when i need to get Genuses filtered by another property (for example update more than and less then date)

    I'm confused now...

  • 2017-01-13 Victor Bocharsky

    Hey Cristian,

    Great! Let me know if you still have troubles with it.

    Cheers!

  • 2017-01-12 Cristian Merli

    Hi Victor, no I couldn't connect but i found a way to reset my root password, and now i feel confident I can give it another try! thanks!

  • 2017-01-12 Victor Bocharsky

    Hi Cristian,

    Please, double-check your database credentials in `app/config/parameters.yml`. Are they valid for your database? Can you connect with these credentials using a MySQL client, like MySQL WorkBench or PhpMyAdmin?..

    Cheers!

  • 2017-01-11 Cristian Merli

    Hi, unfortunately I am stuck at Lecture 2. Whenever I try to create the database from the console I get the "Access denied for user 'root'@'localhost'" errors.
    I am using Ubuntu, any clue?

  • 2016-10-15 Benson Twumasi

    Thanks Man

  • 2016-10-15 weaverryan

    Hey Beson!

    Awesome! To your questions:

    1) It's possible (I have never done it, but others certainly have) to reverse engineer your existing database in order to create entities that match it. Exactly how successful this will be depends on how clean or messy your current database is. Here are the details: http://symfony.com/doc/curr...

    2) If your empBirthday field is a Doctrine datetime or date type (e.g. @ORM\Column(type="date"), which it should be, then what you should set on this property is a DateTime *object* - not just a date string. The reason you're getting this error is that Doctrine is expecting a DateTime object, so it's trying to call format() on your string when inserting it into the database. So, your code should look something like this:


    $employee->setEmpBirthday(new \DateTime('1984-11-12'));

    Even though this will store as a string in the database, you'll always deal with DateTime objects with Doctrine, which is actually pretty nice. Later, if you wanted to print the birthday, it would be something like:


    echo $employee->getEmpBirthday()->format('Y-m-d');

    Cheers!

  • 2016-10-15 Benson Twumasi

    Ryan,
    it worked. You re Genus. lol. Thanks.

    However l have a new challenges.

    1.how do i use exiting database in my projects instead of recreating using doctrine.
    2. i have update my database with birthday. l get this date format error
    "Call to a member function format() on a non-object" when inserting to the tables using this

    $employee->setEmpBirthday('1984-11-12');

  • 2016-10-15 weaverryan

    Hi Benson!

    Welcome to Symfony! I can definitely help you with this - it's just one *small* thing :). In your route, you have `/employee/{employeeName}`. This means that you are allowed to have a `$employeeName` argument to your controller. But, you have `$employeeId`. Symfony is basically saying:

    > Hey! I see `$employeeId` as an argument to showAction(), but I don't see a {employeeId} in your route, so I don't know what value to pass here!

    The fix is to make these match - probably in your case by changing the route to `/employee/{employeeId}`. Also, when you do this, if you have any links to this route (the employee_show route), you'll need to update those as well to now pass employeeId instead of employeeName (http://knpuniversity.com/sc....

    Let me know if this helps!

    Cheers!

  • 2016-10-15 Benson Twumasi

    <tr>
    <td>
    {{ employee.empId }}
    </td>
    <td>{{ employee.empFirstname }}</td>
    <td>{{ employee.empLastname }}</td>

  • 2016-10-15 Benson Twumasi

    hi Ryan

    Am trying my hands on my first symfony project and having this difficulties.

    Controller "AppBundle\Controller\EmployeeController::showAction()"
    requires that you provide a value for the "$employeeId" argument. Either
    the argument is nullable and no null value has been provided, no
    default value has been provided or because there is a non optional
    argument after this one.

    this the code

    viewEmployeeList.html.twig',


    <tr>
    <td>
    {{ employee.empId }}
    </td>
    <td>{{ employee.empFirstname }}</td>

    EmployeeController.php


    /**
    * @Route("/employee/{employeeName}", name="employee_show")
    */
    public function showAction($employeeId)
    {

    $employee = $this->getDoctrine()->getManager();
    $employeeId =$employee->getRepository('AppBundle:Employee')
    ->findOneBy(['employeeId' =>$employeeId]);

    if (!$employee) {
    throw $this->createNotFoundException('employee not found');
    }
    $this->get('logger')
    ->info('Showing Employee: '.$employeeId);

    return $this->render('employee/viewEmployeeDetails.html.twig', array(
    'name' =>$employeeId,
    ));
    }
    }
  • 2016-08-31 Victor Bocharsky

    Hey Marcelo,

    Could you debug it by running bin/console doctrine:schema:validate command? And let me know its result. It shows whether you have any invalid mapping.

    BTW, you probably use `user` column name instead of `user_id` in some of your indexes or uniqueConstraints. Please, recheck that all your entities (not only Course entity) have `user_id` column name instead of `user` inside @ORM\Table() annotation. Actually, you have to check all the entities which have relation to the User entity.

    Cheers!

  • 2016-08-30 Marcelo

    Hi there!
    I'm having the same problem:
    My class:


    /**
    * Course
    *
    * @ORM\Table(
    * name="course",
    * uniqueConstraints={
    * @ORM\UniqueConstraint(name="unique_course", columns={"name", "institution_id", "user_id"})
    * },
    * indexes={
    * @ORM\Index(name="IDX_169E6FB9A76ED395", columns={"user_id"})
    * }
    * )
    * @ORM\Entity(repositoryClass="MainBundle\Entity\CourseRepository")
    * @UniqueEntity(
    * fields={"name", "institution", "user"},
    * errorPath="name",
    * message="unique.course.name"
    * )
    * @ORM\HasLifecycleCallbacks
    */
    class Course extends AbstractEntity
    /**
    * @var \MainBundle\Entity\User
    *
    * @ORM\Column(name="user_id")
    * @ORM\ManyToOne(targetEntity="MainBundle\Entity\User", inversedBy="series")
    * @ORM\JoinColumn(name="user_id", referencedColumnName="id")
    */
    private $user;


    Then when I run:


    console doctrine:migrations:diff
    [Doctrine\DBAL\Schema\SchemaException]
    There is no column with name 'user' on table 'course'.
  • 2016-08-15 Henri Tompodung

    Thank you Ryan!

  • 2016-08-11 weaverryan

    Hi Henri!

    It depends :). I'm not really sure how the database looks - as it's really custom to your application. The first step would be to setup a Menu entity with the proper relationships. Once you have that, it should be pretty easy to figure out how you would do all of this.

    BUT, there is always another option. If you have a really custom query, there's nothing wrong with writing and using a raw SQL query, instead of doing things through Doctrine. In fact, in some cases, this might be the best idea. We talk about how to do that here: http://knpuniversity.com/sc...

    Cheers!

  • 2016-08-09 Henri Tompodung

    How to make recursive function in symfony 3 with doctrine?
    I have script PHP native like below:

    mysql_connect("localhost","root","blablabla");
    mysql_select_db("demo");

    function html_menu(&$strmenu="", $parent=0) {
    $query = "SELECT * FROM menu
    WHERE code_parent='$parent'
    ORDER BY code_menu";
    $sql = mysql_query($query);

    if (mysql_num_rows($sql) > 0) {
    $strmenu .= '<ul>'.PHP_EOL;
    }

    // show children
    while ($row = mysql_fetch_array($sql)) {
    $strmenu .= "<li>".PHP_EOL;
    $strmenu .= sprintf(" % s ", $row['link'], $row['nm_menu'], $row['nm_menu']).PHP_EOL;

    html_menu($strmenu, $row['code_menu']);
    $strmenu .= "</li>".PHP_EOL;
    }

    if (mysql_num_rows($sql) > 0) {
    $strmenu .= '</ul>'.PHP_EOL;
    }

    }

    $strmenu = "";
    html_menu($strmenu, 0);
    echo $strmenu;

  • 2016-07-20 JLChafardet

    @weaverryan yeah! suddenly i became swamped in work, a company in the netherlands hired some hours (i work as a freelance contractor some hours a week aside from my business, you know, extra coins wont hurt ever, as long as they dont take up sleep time nor weekends [I myself used to work even weekends for the past 18 years, lost a lot of time on that, so now im properly taking care of not just my mental health but also my body's health and my spiritual peace haha]) so got 2 projects going on my 8h/day mon-fri work routine, 3 extra hours a day contracted in the NL for this laravel project, havent had much time to browse or comment! but I take to heart everything I learnt here! I'm still much inexperienced, but im growing with each line of code i write, getting to know symfony better bit by bit.

    regarding laravel, well its indeed nice, it has a lot of out of the box features that are really cool, yet it feels way too much microframeworkish, thats just overgrown, it doesnt feel by any means a fully featured framework in and on itself, but as stated a "overgrown" microframework. I may be wrong tho.

  • 2016-07-20 weaverryan

    Hey! No worries :) Laravel is not my preference, but it's nice too - you can probably bring back some nice tools/lessons from it back to Symfony.

    I look forward to having you back! - I noticed you hadn't commented in awhile ;)

  • 2016-07-20 JLChafardet

    @weaverryan my subscription expired, but ill renew it next month, this month im tied down horribly with a laravel project that i gota take care of. (:S didnt want to write in laravel, but the customer's mind is dead set on it, wanted to try to get them to use symfony)

  • 2016-07-20 weaverryan

    Awesome :) - glad you got it figured out. It's configurable, but out-of-the box with Doctrine in Symfony, property names are "snaked-cased" like this, which I kinda like (but it can surprise at first!)

    Cheers @JLChafardet!

  • 2016-07-19 JLChafardet

    ok my bad, found the issue, was on the indexes, as im using isRead variable, but the table name is in fact "is_read"

  • 2016-07-19 JLChafardet

    hey guys, I'm having an issue with the migrations here.


    /**
    * @ORM\Column(type="boolean")
    */
    private $isRead;

    when I run console doctrine:migrations:diff i get the following error

    jl@josefo-d: /var/www/vhosts/project-s3 on master [!?]
    $ console doctrine:migrations:diff


    [Doctrine\DBAL\Schema\SchemaException]
    There is no column with name 'isRead' on table 'contact'.

    what could be the issue here?

  • 2016-06-28 JLChafardet

    Consider this tho: this works flawlessly in propel! (just for argument sake, if it works in propel, out of the box, no extra bundle required, i think it would be great for doctrine to have it too).
    back on topic:
    yeah i think ill get rid of loggable/versionable behavior. as the translatable one is more important for the customer, offering "versions" was an idea of mine and i actually never really offered it, i just "wanted" to give it as an extra

    i was pointed at https://github.com/DATA-DOG... seems its a more robust audit tool, which could serve, ill consider it for later implementation to see if it works in my favor

  • 2016-06-28 weaverryan

    Those two behaviors specifically will be very difficult to get working together. And it kind of makes sense - versioning is already hard in a relational database (you need to duplicate each row before it's changed). Add onto that the fact that each row now has many translations, and you quickly (and correctly) get a big, ugly matrix. I use some of the more magic behaviors sparingly - learning from Doctrine version 1 that the magic has costs. For example, on our apps, we don't use Loggable/versionable or soft deletable.

    So, my best advice is to consider doing *less* - these behaviors try to make a relational database do things that it doesn't naturally do well. If you layer on too many, I don't think you'll be happy.

    Cheers!

  • 2016-06-28 JLChafardet

    seems is not possible to use them together. i hate this, i really dont want to implement my own behaviors.

  • 2016-06-27 JLChafardet

    ok, getting on my way to properly have Versioned and Translatable working together! what a freaking long day.

    the issue seems to be related to the fact that to add a new language you have to actually "edit" and when you "edit" it generates a new version.

    its pissing me off badly.

  • 2016-06-27 JLChafardet

    translatable and versionable (loggable) dont seem to be friendly. adding a new translation is interpreted by loggable as a new version of the row.

  • 2016-06-27 JLChafardet

    i seem to be advancing on the translations, ill keep you posted lol

  • 2016-06-27 weaverryan

    Yep, I am aware of this - it's tricky because if you *do* include the unfolded code blocks, then some of them are HUGE (in some tutorials, we show a cached file that is a few thousand lines long) and you also lose perspective of the 5 lines that we want you to focus on. But, if they're folded, then sometimes you can't see enough :). I don't think there's a perfect way - except to check out the code on the site ;)

    Cheers!

  • 2016-06-27 weaverryan

    Nice work @JLChafardet

    I think what happens in a lot of cases with Doctrine is that:

    A) it requires more typing to set something up and
    B) The documentation often isn't clear (so that it's difficult to know what to type!)

    Anyways - nice job, and thanks for sharing your thoughts - I definitely have this on the "idea" list :)

    Cheers!

  • 2016-06-27 JLChafardet

    I think it would do great to have a full blown tutorial/track coverage.

    I've been playing with the Versioned and Translatable behaviors, and at least in 5 hours of work, i CANNOT get them to work properly.

    heres the basic main reason why now that I see how Dogtrine works why some people prefer to use Propel.

    I'm going to keep at it, as i just cant accept defeat, but this is just ridiculously complex for something that should be ridiculously simple.

    getting "Versioned" fields doesnt seem to work on the fly as it should, what i mean is this:
    Entity:


    namespace AppBundle\Entity;

    use Doctrine\ORM\Mapping as ORM;
    use Gedmo\Mapping\Annotation as Gedmo;
    use Gedmo\Translatable\Translatable;

    /**
    * @ORM\Entity
    * @Gedmo\Loggable()
    * @Gedmo\SoftDeleteable(fieldName="deletedAt", timeAware=false)
    * @ORM\Table(name="blog", indexes={@ORM\Index(name="title_idx", columns={"title"}),@ORM\Index(name="slug_idx", columns={"slug"})})
    */
    class Blog implements Translatable
    {
    /**
    * @ORM\Id
    * @ORM\GeneratedValue(strategy="AUTO")
    * @ORM\Column(type="integer", unique=true)
    */
    private $id;

    /**
    * @Gedmo\Translatable()
    * @Gedmo\Versioned()
    * @ORM\Column(type="string")
    */
    private $title;

    /**
    * @Gedmo\Timestampable(on="create")
    * @ORM\Column(type="datetime")
    */
    private $createdAt;

    /**
    * @Gedmo\Timestampable(on="update")
    * @ORM\Column(type="datetime", nullable=true)
    */
    private $updatedAt;

    /**
    * @ORM\Column(type="datetime", nullable=true)
    */
    private $deletedAt;

    public function getId()
    {
    return $this->id;
    }

    public function getTitle()
    {
    return $this->title;
    }

    public function setTitle($title)
    {
    $this->title = $title;
    return $this;
    }

    }
    ?>

    Controller:


    namespace AppBundle\Controller;

    use AppBundle\Entity\Blog;
    use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
    use Symfony\Bundle\FrameworkBundle\Controller\Controller;

    class BlogController extends Controller
    {
    /**
    * @Route("/test")
    */
    public function newAction()
    {
    //we insert
    $blog = new Blog();
    $blog->setTitle('Titulo 1 ');
    $blog->setDescription('Lorem ipsum dolor sit amet, consectetur adipiscing elit.');
    $blog->setMainImage('image');
    $blog->setContent("

    Praesent eleifend facilisis sapien a lobortis. Aliquam semper feugiat lectus. Cras non ligula nec odio gravida maximus sed eu sem. Quisque in ornare sem odio

    ");
    $blog->setTranslatableLocale('es_ES');
    $em = $this->getDoctrine()->getManager();
    $em->persist($blog);
    $em->flush();

    //we retrieve (comment the above code and run the code below this line)
    $em = $this->getDoctrine()->getManager();
    $blogEm = $this->getDoctrine()
    ->getRepository('AppBundle:Blog');
    $articles = $blogEm->findAll();

    dump($articles);
    //IT DOESNT get any of the Versioned fields.

    the answer from the dump is:

    BlogController.php on line 36:
    array:1 [▼
    0 => Blog {#565 ▼
    -id: 1
    -title: ""
    -slug: "article-one-1"
    -mainImage: "image"
    -description: ""
    -content: ""
    -isVisible: false
    -locale: null
    -createdAt: DateTime {#561 ▼
    +"date": "2016-06-27 15:45:36.000000"
    +"timezone_type": 3
    +"timezone": "America/Caracas"
    }
    -updatedAt: DateTime {#562 ▼
    +"date": "2016-06-27 15:45:36.000000"
    +"timezone_type": 3
    +"timezone": "America/Caracas"
    }
    -deletedAt: null
    }
    ]
  • 2016-06-27 JLChafardet

    BTW! @weaverryan are you aware that when you download the transcript for the courses, the code is folded when the pdf is created?

    you should look into that, so the pdf is generated with the code entirely expanded.

  • 2016-06-27 JLChafardet

    Heya @weaverryan !

    Tried alone first, pure doctrine extensions, installation was a bit rough, but went ok! tho couldnt get translatable to work, then went with StofDE and got it working, believe it or not, was touger to get StofDE working tho.

    just find really irritating it seems translatable uses a single table to translate everything, will have to see that a little bit ahead! i will port some apps from silex to s3, but on my free time, for now gota keep up working on what gota be done hehe

  • 2016-06-26 weaverryan

    Yo @JLChafardet!

    You beat me to it - but I was going to recommend gedmo - so very happy you found it. It's a great library, though sometimes its documentation isn't AS great as it could be :). Are you using it with StofDoctrineExtensionBundle? It doesn't do much, but if helps alleviate some of the setup work (but it's docs aren't great). I'm not sure about Translatable - that's one I haven't used yet.

    But yea, the extensions are super fun - it might be good for a mini-tutorial :)

    Cheers!

  • 2016-06-26 JLChafardet

    ok I've been playing with the gedmo/doctrine-extensions, seems i've gotten most of it to work, except translatable, or at least im not seeing it create any tables for the translations, loggable, softdeletable, timestampable, sluggable tho seems to work just fine.

    gota keep playing with it it seems.

    dogtrine's learning curve is really step! oh well, who doesnt love a good challenge eh!

  • 2016-06-26 JLChafardet

    yo yo @weaverryan

    hows all going? I have a question, lol highly important to me atm (maybe its covered in a different tutorial yet i havent had much time lately to browse around, if so would you please point me in the right direction?).

    I'm interested in knowing about doctrine behaviors, for example, I use a lot in propel timestampable, softdelete and well of course, i18n
    I'm not sure how to even begin to work that out on doctrine the annotations. i checked you have a knp bundle called doctrine-behaviors but they seem to be overly complicated to use, is there nothing of the sort native out of doctrine as they are entirelly and totally native in propel?

    I'm attempting to port a project i wrote in silex1+propel1 into S3+dogtrine, to practice and well if possible actually really migrating it, and those behaviors are a requirement.

  • 2016-06-01 David Thorne

    Great introduction Ryan! Thanks. Keep up the good work.

  • 2016-04-26 weaverryan

    Hi Andrés!

    Hmm, that usually means that you are trying to persist and entity (e.g. Genus) - but Doctrine does not think it's an entity. For example, if you mistakenly put `Genus` in a directory called `Model` instead of `Entity`, then Doctrine wouldn't know to read its annotation metadata, and it would look like a normal class, not an entity. This would cause this error. It's a very uncommon error, exception in edge-cases when you're working with third-party libraries that give you entities. In those cases, sometimes you have to add configuration so Doctrine is aware of the extra entity classes :).

    I hope that helps!

  • 2016-04-24 Andrés Vr

    Hello Ryan

    when I create an entity I have this error:
    The class 'xxx' was not found in the chain configured namespaces

    Do you have any idea to resolve them??

  • 2016-04-21 Shairyar Baig

    Hi,

    All i had to do was move '$currentProfileImage = $college->getLogo();' at the beginning of the action and it worked :)

    Thanks for your comments and looking into it anyways.

    Baig

  • 2016-04-21 weaverryan

    Hey Shairyar!

    Hmm, I'm not sure. But! To find out, here's what I would do. Suppose that the persisted property on College for the image is called imagePath. First, I'd see if anything in College modifies the imagePath property other than setImagePath(). If anything else *does* modify imagePath, then temporarily comment that out and edit the College - see if the image is lost. Also, throw a new \Exception() in setImagePath() to see if something is calling it on College edit.

    My guess is that you might be setting $this->imagePath = null; inside setLogo() or something similar, but I'm not sure :).

    Cheers!

  • 2016-04-21 Shairyar Baig

    Hi Ryan,

    I am stuck in a situation and hoping that your expertise will push me in right direction.

    It is a really simple task, in admin panel i need to give admin an option to add image and add the description, this is working fine but as soon the admin edit's the description and saves it the image name becomes null in database. so it works the first time and then later on, on edit the image name goes missing.

    This is the action, in this i am using `currentProfileImage ` and saving the existing image in case user does not provide the new one while editing so i dont lose the only that is already there, but this does not work.



    public function editAction(Request $request, College $college)

    {

    $em = $this->getDoctrine()->getManager();
    $editForm = $this->createForm('AppBundle\Form\CollegeType', $college);
    $editForm->handleRequest($request);
    $currentProfileImage = $college->getLogo();

    if ($editForm->isSubmitted() && $editForm->isValid()) {

    if ($editForm->get('logo')->getData() == null) {

    // if an image has not been provided
    $college->setLogo($college->getLogo());

    $em->persist($college);

    } else {

    $profileImageDir = $this->container->getParameter('kernel.root_dir') . '/../web/uploads';

    $file = $college->getLogo();

    // Generate a unique name for the file before saving it
    $fileName = md5(uniqid() . $file) . '.' . $file->guessExtension();

    // Move the file to the directory where profile images are stored
    $file->move($profileImageDir, $fileName);
    $college->setLogo($fileName);

    $em->persist($college);
    }

    $em->flush();

    //display successful message
    $this->get('session')->getFlashBag()->add(
    'success',
    $this->get('translator')->trans('general_success_message')
    );

    return $this->render('AppBundle:admin/college:edit.html.twig', array(
    'college' => $college,
    'edit_form' => $editForm->createView(),
    ));

    }

    return $this->render('AppBundle:admin/college:edit.html.twig', array(
    'college' => $college,
    'edit_form' => $editForm->createView(),
    ));

    }

    What am i doing wrong here?

  • 2016-01-27 weaverryan

    Hey there!

    Welcome! Yes, it's not exactly a beginner problem, but maybe I can help:

    1) The only thing that will live in your repository are queries. From flat PHP, think of it this way: any time that you *used* to literally write a query - e.g. $sql = 'SELECT * FROM ...', followed by $conn->execute($sql) or something similar - put that logic as a new method in a repository. That's the only purpose of a repository: to try to prevent query logic from being all around your project. If you're selecting from multiple tables, just put the new method in the repository that you feel most appropriately fits.

    2) Depending on your user flow, your form might be quite complicated for this. If the user is creating an event, then adding a drop-down of all of the themes in the system is simple - just use the EntityType. But, if you need to do some crazy AJAX logic once the user selects the theme (e.g. in order to load a list of products in that theme, or something) - that can get more complicated. My advice on the form system is always this: use it when it works for you. But if you get in a real complex situation, it's ok to revert back and use some normal HTML forms and process the input manually in your controller (a bit more like flat PHP)

    3) If you need to do some validation after a form is submitted to see if the required products are available, then you can do that in your controller (and just render the template with an error message if there is a problem). If you want to get a bit more advanced, you can create a custom validation constraint. I talk about some of the possibilities on this post: https://knpuniversity.com/s...

    Overall, don't worry too much. Symfony gives you a lot of tools, but optional tools. If you feel overwhelmed, it's ok to choose to use less of Symfony's tools, while you get going :).

    Good luck!

  • 2016-01-27 Bettinz

    Hello, this is a beginner question :D I've an entity called product, one called event, and one called theme. To make an event, you must select a theme; based on theme, the event will require some products and I need to check if that products are available. I need to write custom queries (like select quantity from product_in_theme and verify if is available in product) but..where I write that code? In repository? If yes, the full code, will be in repository? (For example: check the theme passed with form, select the product from the form, etc). I know it's not the beginner situation, and maybe years writing plain php is giving me the wrong idea, so please, help me :)

  • 2016-01-20 weaverryan

    Hey Sudhir! I'm still aiming for the next few weeks :)

  • 2016-01-20 Sudhir Gupta

    hi , when it will released??
    I are awaiting like hungry

  • 2016-01-06 weaverryan

    Hey Igor!

    This is the 2nd episode in the Symfony 3 series after knpuniversity.com/screencas..., which we're just finishing now. My hope is to get this episode this month. In the mean time, Doctrine hasn't changed that much, so here are some links that might be useful:

    * https://knpuniversity.com/s... (and the chapter after)
    * https://knpuniversity.com/s...
    * and most of https://knpuniversity.com/s...

    I hope that helps!

  • 2016-01-05 Igor Lula

    Hello there, when this screencast will be released?