> Symfony 6 >

Course Overview

Doctrine, Symfony 6 & the Database

Dive into Doctrine in Symfony 6, and learn how to create and update entities, generate migrations, and query for data with ease.

  • 3777 students
  • EN/ES Captions
  • EN/ES Script
  • Certificate of Completion

Your Guides

About this course

What PHP libraries does this tutorial use?

// composer.json
    "require": {
        "php": ">=8.1",
        "ext-ctype": "*",
        "ext-iconv": "*",
        "babdev/pagerfanta-bundle": "^3.7", // v3.7.0
        "doctrine/doctrine-bundle": "^2.7", // 2.7.0
        "doctrine/doctrine-migrations-bundle": "^3.2", // 3.2.2
        "doctrine/orm": "^2.12", // 2.12.3
        "knplabs/knp-time-bundle": "^1.18", // v1.19.0
        "pagerfanta/doctrine-orm-adapter": "^3.6", // v3.6.1
        "pagerfanta/twig": "^3.6", // v3.6.1
        "sensio/framework-extra-bundle": "^6.2", // v6.2.6
        "stof/doctrine-extensions-bundle": "^1.7", // v1.7.0
        "symfony/asset": "6.1.*", // v6.1.0
        "symfony/console": "6.1.*", // v6.1.2
        "symfony/dotenv": "6.1.*", // v6.1.0
        "symfony/flex": "^2", // v2.4.5
        "symfony/framework-bundle": "6.1.*", // v6.1.2
        "symfony/http-client": "6.1.*", // v6.1.2
        "symfony/monolog-bundle": "^3.0", // v3.8.0
        "symfony/proxy-manager-bridge": "6.1.*", // v6.1.0
        "symfony/runtime": "6.4.3", // v6.4.3
        "symfony/twig-bundle": "6.1.*", // v6.1.1
        "symfony/ux-turbo": "^2.0", // v2.3.0
        "symfony/webpack-encore-bundle": "^1.13", // v1.15.1
        "symfony/yaml": "6.1.*", // v6.1.2
        "twig/extra-bundle": "^2.12|^3.0", // v3.4.0
        "twig/twig": "^2.12|^3.0" // v3.4.1
    "require-dev": {
        "doctrine/doctrine-fixtures-bundle": "^3.4", // 3.4.2
        "symfony/debug-bundle": "6.1.*", // v6.1.0
        "symfony/maker-bundle": "^1.41", // v1.44.0
        "symfony/stopwatch": "6.1.*", // v6.1.0
        "symfony/web-profiler-bundle": "6.1.*", // v6.1.2
        "zenstruck/foundry": "^1.21" // v1.21.0

After the first two courses, we're going to turn the volume to 11! Yup, it's database time!

This tutorial is all about Doctrine: a powerful ORM that will allow us to talk to a database from inside our Symfony app. With the power of PHP 8 & tools inside Symfony, Doctrine is not only the most powerful ORM in PHP, it's also a joy to work with. You are going to love it!

  • Booting a database with Docker via the Flex recipe system
  • Database config
  • 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 Foundry
  • Relationships & Associations

SELECT * FROM doctrine_knowledge.

Next courses in the Symfony 6: The Fundamentals section of the Symfony 6 Track!


Sort By
Login or Register to join the conversation
Lionel-F avatar Lionel-F 1 year ago

Hi guys, I got a general question about doctrine, where you flush/persist an entity ? In repository ? controller ? on a service ?

1 | Reply |

Hey Lionel F.

That's a good question. I usually manage entities through a service class, but sometimes I call flush in a controller for convenience. I think the answer is "it depends" on how complex is your process of creating new entities. If it's a straightforward process (call persist, then flush) doing it in the controller is acceptable


1 | Reply |

On a service of relevant Enity like UserManager, always, unless you don't want to overcomplicate things for biginners like Symfonycats does.

| Reply |

Hi how to get certification on the courses?

| Reply |

Hello @dibase

You will get course pass certificate after finishing it, also you will be able to find all you certificates on a https://symfonycasts.com/certificates page


| Reply |
M-P avatar M-P 4 months ago edited

Last example in Doctrine documentation about fetching entities automatically is missing essential parameter to the MapEntity: FQCN of the Entity, it should be:

public function show(
    Product $product,
    #[MapEntity(expr: 'repository.findBy(["product_id" => id], null, request.query.get("limit", 10))', class: 'App\Entity\Comment')]
    iterable $comments
): Response {
| Reply |

Hey M-P,

Hm, sounds valid because $comments type is just iterable so the system does not know its entity type. Are you getting an error with that example? Would you like to open a PR to fix that code block?


| Reply |
Evan-W avatar Evan-W 7 months ago

Hi! If this is still active, I have a question about setting up multiple connections in Doctrine.

We have a system that we're trying to implement where we selectively use a read-only database. Currently, we have it set up like a replica database, but we can't use the replica everywhere in the app, only in certain places will it work without major refactors. I've attempted to update the doctrine.yaml file with multiple connections and entity managers, but I continue to experience issues. With the configuration I currently have, I'm seeing an unusual behavior where the secondary connection (not the default) is pulling data seemingly from the default database. I've verified that the entity managers in the controller are indeed pointing to databases with different names. The behavior I'm expecting is to have the secondary database connection return values from it's database only, which may or may not be in sync with the default. I have already referenced the documentation here, but that doesn't seem to work with what I have. For context, the mapping for each database is the same, as the schemas are identical (dir: '%kernel.project_dir%/src/Entity' for both).

Is this behavior I'm looking to achieve even possible? If so, are there ways to troubleshoot or examples I could look at? If not, is it possible to have a replica database that is only used in certain ways, or will it always be app wide?

Apologies for the long message. Any feedback would be greatly appreciated.

Thank you!

| Reply |

Yo @Evan-W!

Tricky :). You mentioned:

For context, the mapping for each database is the same, as the schemas are identical (dir: '%kernel.project_dir%/src/Entity' for both).

So, both entity managers are pointing at the same src/Entity/ directory, right? I think (?) that would confuse things. For example, if you asked for the ProductRepository, to instantiate that object, it hits this line - https://github.com/doctrine/DoctrineBundle/blob/2.10.x/Repository/ServiceEntityRepository.php#L47

If we have two entity managers that both map Product, it won't know which one to choose (I imagine it'll always choose the first or the last - not sure which).

Am I understanding the setup correctly? If so, yea, the current approach won't work. It sounds more like you effectively want to use the writable DATABASE_URL in some cases and a different DATABASE_URL that points to your replica in other situations. Depending on what you mean by "only in certain places will it work without major refactors", this could be tricky.

In the simplest situation (e.g. all URLs under /admin should use the replica), you could probably set up a really early RequestEvent listener to change the DATABASE_URL. But if you need to be able to use the writable connection to the product table from ServiceFoo and the readonly connection to the product table from ServiceBar... yikes... I'm not sure. In theory, you might be able to "activate" the readonly connection right before you make a query, then turn it back to writable after. Idk... you'll have to tell me how all of this sounds :).


1 | Reply |

Hey @weaverryan!

Thanks for the reply! You did understand my situation correctly, despite my vague descriptions haha. I had a hunch that entity manager mapping line would cause that issue, and what you described as it defaulting to the first one is exactly what I'm seeing.

We're trying to support a replica database setup in our app. By "only in certain places will it work without major refactors", I meant we noticed issues with the doctrine replica setup since we have situations where we read and write to the database in quick succession. Too quick for the databases to sync, and we were looking for a solution for this issue without refactoring a lot of our logic.

Thanks for the suggestion, I don't think that would work for us though. We might end up resorting back to the standard replica configuration and go through a refactor. Alternatively, is it possible that we can use the wrapper_class option in the configuration to selectively determine when to read from the replica? If that's possible, I think that would be our best bet.

Thanks again for the reply! Really enjoy the tutorials!

| Reply |

Hey @Evan-W!

Ah yes, so you have the "more complex" problem that I feared šŸ¤£.

Alternatively, is it possible that we can use the wrapper_class option in the configuration to selectively determine when to read from the replica? If that's possible, I think that would be our best bet.

I don't have direct experience with replicas or this option. But if the idea is to create a custom class that then "toggles" between the correct connection... maybe? I can't think of why this wouldn't work. But again, you'd need to somehow signal to the system which to use... perhaps having some central service you call to "activate write connection" then "deactivate write connection", which sets a flag that your connection class users? I'm doing a lot of guessing as to whether this would work or not, but I don't see any giant red flags. It's worth a shot.


1 | Reply |

Hi @weaverryan,

Ah I see haha. I'll certainly take a "not sure why it wouldn't work" over "no way" any day. I really appreciate the advice on this, I'll give that a shot.

Thank you!

1 | Reply |
David_S avatar David_S 1 year ago


I watched every video that is available at the moment. 7 videos are still at -comming soon-. Do you have any idea when this videos will be available?

Thank you and best regards

| Reply |

Hey David,

We're sorry for the delay, we're trying to release 1 new video a day, so I think the course will be completely released at the end of the next week. In short, our normal schedule is 1 video per day, stick to this pace.


2 | Reply |

Delete comment?

Share this comment

astronaut with balloons in space

"Houston: no signs of life"
Start the conversation!