If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.
With a Subscription, click any sentence in the script to jump to that part of the video!
Login SubscribeWe just upgraded from DoctrineBundle version 1 to version 2 and... it broke our app. That's lame! Hmm:
Cannot autowire service
ApiTokenRepository
: argument$registry
references interfaceRegistryInterface
but no such service exists.
Hmm. Ya know, instead of trying to figure this out... and digging for any other breaking changes... let's just go look at the bundle's CHANGELOG. Go back to the DoctrineBundle GitHub homepage. And... ah! Even better: upgrade files! Open UPGRADE-2.0.md
.
There's a lot here: dropping old versions of PHP & Symfony and changes to commands. But if you look closely, you'll find that most of these are pretty minor. The most important changes are under "Services aliases". Previously, if you wanted to get the doctrine
service, you could use the RegistryInterface
type-hint for autowiring. Now you should use ManagerRegistry
.
Where do we use RegistryInterface
? Move over to your terminal and run:
git grep RegistryInterface
We use it in every single repository class. This is code that the make:entity
command generated for us. The newest version of that bundle uses ManagerRegistry
.
Fixing this is as simple as changing a type-hint... it's just tedious. Open up every repository class. And, one-by-one, I'll change RegistryInterface
to ManageRegistry
in the constructor:
... lines 1 - 14 | |
class UserRepository extends ServiceEntityRepository | |
{ | |
public function __construct(ManagerRegistry $registry) | |
{ | |
... line 19 | |
} | |
... lines 21 - 85 | |
} |
Use ManagerRegistry
from Doctrine\Persistence
. There is also one from Doctrine\Common\Persistence
:
... lines 1 - 6 | |
use Doctrine\Persistence\ManagerRegistry; | |
... lines 8 - 14 | |
class UserRepository extends ServiceEntityRepository | |
{ | |
public function __construct(ManagerRegistry $registry) | |
{ | |
... line 19 | |
} | |
... lines 21 - 85 | |
} |
That's another Doctrine change that's happening right now. Doctrine originally had a package called doctrine/common
, which contained a lot of... well... "common" classes that other Doctrine libraries needed. Doctrine is now splitting doctrine/common
into smaller, individual packages. Basically, the Persistence
directory of doctrine/common
is now its own package and you should use its classes: the old ones are deprecated.
What makes this a bit more confusing is that the UPGRADE log references the old class name. Like I said: there are a lot of moving pieces right now.
I'll also remove the old RegistryInterface
use statement. Repeat this a bunch more times: change to ManagerRegistry
, remove the use
statement and keep going:
... lines 1 - 6 | |
use Doctrine\Persistence\ManagerRegistry; | |
... lines 8 - 14 | |
class TagRepository extends ServiceEntityRepository | |
{ | |
public function __construct(ManagerRegistry $registry) | |
{ | |
... line 19 | |
} | |
... lines 21 - 49 | |
} |
... lines 1 - 8 | |
use Doctrine\Persistence\ManagerRegistry; | |
... lines 10 - 17 | |
class CommentRepository extends ServiceEntityRepository | |
{ | |
public function __construct(ManagerRegistry $registry) | |
{ | |
... line 22 | |
} | |
... lines 24 - 80 | |
} |
Do you want to see how fast I can type?
... lines 1 - 8 | |
use Doctrine\Persistence\ManagerRegistry; | |
... lines 10 - 16 | |
class ArticleRepository extends ServiceEntityRepository | |
{ | |
public function __construct(ManagerRegistry $registry) | |
{ | |
... line 21 | |
} | |
... lines 23 - 73 | |
} |
... lines 1 - 6 | |
use Doctrine\Persistence\ManagerRegistry; | |
... lines 8 - 14 | |
class ApiTokenRepository extends ServiceEntityRepository | |
{ | |
public function __construct(ManagerRegistry $registry) | |
{ | |
... line 19 | |
} | |
... lines 21 - 49 | |
} |
Suuuuuuper faaaaaaaast. Ah! I sprained a finger.
Let's see if we're good! Spin over and just run:
php bin/console
Before those changes, running this would have caused an explosion - the same one that we saw after running composer update
. So we are good: we're using a Symfony5-compatible version of DoctrineBundle.
But... because this library is so important... and because we just did a major version upgrade, I also want to upgrade its recipe. Run:
composer recipes
Ok, yea, DoctrineBundle is one of the few recipes that still have an update available. Run:
composer recipes doctrine/doctrine-bundle
to get more info and copy the update command. Run it!
composer recipes:install doctrine/doctrine-bundle --force -v
Ok, it looks like this updated several files. Let's step through the changes. Clear the screen and run:
git add -p
The first changes are inside .env
: it added a PostgreSQL example and, oh, this comment is important: it mentions that the serverVersion
setting is required in this file or in config/packages/doctrine.yaml
. That's actually not a new thing, but the new recipe now gives you a bit more info about this.
The setting tells Doctrine what version of your database you're using, like MySQL 5.7 or mariadb-10.2.12
. Doctrine uses that to know which features are supported by your database.
The point is: this is something Doctrine needs to know and you can add that config inside your DATABASE_URL
environment variable or in doctrine.yaml
, which is what I prefer. I like to set this to my production database version and commit it inside doctrine.yaml
so that the project works the same on any machine.
So... I guess I want these new comment changes, except that I want to keep my existing DATABASE_URL
. Copy it, hit "y" to accept the changes, then "q" to quit the patch mode.
Back in our editor... find .env
, look for DATABASE_URL
, and paste our original value:
... lines 1 - 22 | |
###> doctrine/doctrine-bundle ### | |
# Format described at https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url | |
# For an SQLite database, use: "sqlite:///%kernel.project_dir%/var/data.db" | |
# For a PostgreSQL database, use: "postgresql://db_user:db_password@127.0.0.1:5432/db_name?serverVersion=11&charset=utf8" | |
# IMPORTANT: You MUST configure your server version, either here or in config/packages/doctrine.yaml | |
DATABASE_URL=mysql://root:@127.0.0.1:3306/the_spacebar | |
### | |
... lines 30 - 62 |
Let's keep going!
git add -p
Accept the change we just made to .env
. The next update is in composer.json
, we definitely want this. Then... actually, hit "q". Let's add the files we know we want:
git add composer.json composer.lock symfony.lock src/Repository
Run:
git status
Much better! Back to:
git add -p
In bundles.php
, it removed DoctrineCacheBundle - that's a good change - and now we're inside of doctrine.yaml
.
There are a bunch of interesting updates here. First, there used to be a parameter called env(DATABASE_URL)
. This was a workaround to prevent Doctrine from exploding in some edge cases. It's no longer needed. Progress!
Next, the driver
setting isn't needed inside here because that part is always contained inside DATABASE_URL
. It's just extra, so we can remove it. Oh, and server_version
was just moved further down.
The recipe also removed these charset
options, and that is interesting. If you use MySQL, these settings are needed to make sure that you can store unicode characters. Starting in DoctrineBundle 2.0, these values are no longer needed because they are the default. That's a nice cleanup.
Below, the server_version
is now commented-out by default: you need to choose to put it in this file or inside your environment variable. I'll uncomment this in a minute.
Finally, this naming_strategy
is a minor change: it controls how table and column names are generated from class and property names. The new setting handles situations when there is a number in the name. It's a good change... and the old setting is deprecated. However it is possible that this could cause Doctrine to try to rename some columns. You can run:
php bin/console doctrine:schema:update --dump-sql
after making this change to be sure. Enter "y" to accept all these changes, then "q" to quit. Find this file - config/packages/doctrine.yaml
- uncomment server_version
and adjust it to whatever you need for your app:
doctrine: | |
dbal: | |
... lines 3 - 6 | |
server_version: '5.7' | |
... lines 8 - 19 |
Back to work!
git add -p
Enter "y" for our server_version
change. The last big update is in config/packages/prod/doctrine.yaml
. This file configures cache settings in the prod
environment: this is stuff you do want. When we originally installed the bundle, the old recipe created several cache services down here under the services
key... and then used them above for the different cache drivers.
Basically, in DoctrineBundle 2.0, these services are created for you. This means that the config can be drastically simplified. Say "y" to this change.
And... we're done! Phew! Commit this:
git commit -m "upgrading to DoctrineBundle 2.0"
And celebrate!
Let's go see how the deprecations look now. When I refresh the homepage... down to 11 deprecations! Check them out.
Huh: a lot of them are still from doctrine... they all mention a deprecation in doctrine/persistence
1.3. doctrine/persistence
is one of the libraries that was extracted from doctrine/common
.
Ok, but why are we getting all these deprecations? Where are they coming from?
I have 2 things to say about this. First, because this is a deprecation warning about a change in doctrine/persistence
2.0... and because we're focusing right now on upgrading to Symfony 5.0, this is not a deprecation we need to fix. We can save it for later.
Second, if you Google'd this deprecation, you'd find that it is not coming from our code: it's coming from Doctrine itself, specifically doctrine/orm
.
There's currently a pull request open on doctrine/orm
- number 7953 - that fixes these. Basically, doctrine/orm
is using some deprecated code from doctrine/persistence
, but the fix hasn't been merged yet. The fix is targeted for version 2.8 of doctrine/orm
. So hopefully when that's released in the future, you'll be able to update to it to remove this deprecation. But, as I said... it's not a problem right now: we can keep working through the Symfony-related deprecations and ignore these.
And... that list is getting pretty short! Time to finish them.
Hokey, I figured out that I could to this instead:
$analyses = $em->getRepository('App\Entity\Hazardlog\Analysis')->findAll();
Hey Matt,
Awesome, I'm happy you were able to figure it out yourself, well done!
Btw, you were very close in your 3rd try, i.e. the option with $analyses = $em->getRepository('Analysis::class')->findAll();
is almost correct, but it should be this way:
$analyses = $em->getRepository(\App\Entity\Hazardlog\Analysis::class)->findAll();
// or if you add the namespace as a use statement above your class - just:
$analyses = $em->getRepository(Analysis::class)->findAll();
I.e. It should not be in quotes ;)
Cheers!
Hi, apparently my mySql is a MariaDB, for server version phpMyAdmin says <b>10.3.35-MariaDB-log - FreeBSD ports</b> so should my doctrine.yaml then look like this?
doctrine:
dbal:
server_version: 10.3.35```
Or do I need anything more (or different) in there? (indentation seems lost in this comment field, indented for yaml obviously)
Hey Mattias,
Good question! Well, it should look like "server_version: 'mariadb-10.3.35'", i.e. you should add that "mariadb-" prefix for MariaDB SQL servers - that's a standard you should just follow :)
But keep in mind that it's better to write there the version you have on production. And ideally, you should have the same version locally and on production so that it works without problems. Otherwise, you can try to specify the lowest version from both and see if it will work well. Otherwise, you would need to specify that version different for different environment using .env files.
I hope this helps!
Cheers!
Thank you! Yes, that was from the production server. But oh, I just realized that I have MariaDB in production, but for my local server I'm running <b>"Server version: 5.7.32 - MySQL Community Server (GPL)"</b> so they are completely different then I suppose.
So one way would be to put the respective versions in the DB connection strings.
I suppose another way would be to put a doctrine.yaml file in each of the config/packages/prod and config/packages/dev directories, and put this in the config/packages/dev/doctrine.yaml
doctrine:
dbal:
server_version: 'mysql-5.7.32'```
is that correct?
Hey Mattias,
Hm, well, they are not that much different fairly speaking.. but yeah, it's better to separate them. The more specific version you specify there - less problems you will have, and queries that Doctrine generates in migrations will be more optimized for too. But I used to have MariaDB on prod and MySQL locally and it works OK with the MariaDB server_version for me. So, it depends.
> I suppose another way would be to put a doctrine.yaml file in each of the config/packages/prod and config/packages/dev directories, and put this in the config/packages/dev/doctrine.yaml
Well, it might be enough for you, but it's not quite correct IMO, because you may load your project in prod mode locally... and what then? The website will use MariaDB version locally? If you never do this - probably it will be OK, at least this strategy is simple. But keep in mind that if you will generate a migration in dev mode - it will use MySQL version instead of MariaDB, but the problem that you want to use MariaDB as you need to run that migration on prod.
A better would be to create an env var in .env files and set it to MySQL version locally and to MariaDB version on prod- this should be the correct way to solve this.
But ideally, install and start using MariaDB locally too :)
> server_version: 'mysql-5.7.32'
Haha, uh oh, almost like that :) With MySQL it's simplified to just "5.7.32", you can see more config options here in the docs: https://symfony.com/doc/cur... . As you can see, MariaDB complicates that value a bit, but it's simple with MySQL. Actually, it's difficult to remember, so I usually look at the docs when I need to configure it.
Cheers!
Hello, when i saw the naming strategy changed in the doctrine.yaml
file i got scared ! When i dump the sql for the schema:update cmd, i see
a lot of changes regarding some tables. Thing is i have a lot of
relations in there, so if i actually udpate my database schema, it
breaks because of foreign keys. What can i do about that ? I do not want
to loose my data, and my database has a lot of tables !
Hey @elbarto
You can choose whatever naming strategy is convenient for you, or you can create your own strategy in case you need to. Check line 298 https://symfony.com/doc/current/bundles/DoctrineBundle/configuration.html
I believe the CamelCaseNamingStrategy
is set by default, you can change it to use the UnderscoreNamingStrategy
I hope it helps. Cheers!
Hello Diego,
If i put back doctrine.orm.naming_strategy.underscore in my doctrine.yaml file, i then get a deprecation message : User Deprecated: Creating Doctrine\ORM\Mapping\UnderscoreNamingStrategy without making it number aware is deprecated and will be removed in Doctrine ORM 3.0.
The thing is, what solutions do we have if i want to pass from underscore to underscore_number_aware strategy and updating my database. Because as i said earlier, if i have few tables named table1_test , table2_test. They will become table_1_test and table_2_test.
On a schema:update it breaks because i have a bunch of relations (FK) inside of them, thus forbidding me to update my schema.
Thanks in advance !
Hmm, you can ignore that deprecation :D
or, another solution is to manually define the name of all the tables you have problems with
/**
* @ORM\Table(name="table2_test")
*/
class SomeEntity
The naming strategy is only used when Doctrine have to give it a name to your tables/fields
Cheers!
// composer.json
{
"require": {
"php": "^7.3.0",
"ext-iconv": "*",
"antishov/doctrine-extensions-bundle": "^1.4", // v1.4.2
"aws/aws-sdk-php": "^3.87", // 3.110.11
"composer/package-versions-deprecated": "^1.11", // 1.11.99
"doctrine/doctrine-bundle": "^2.0", // 2.0.6
"doctrine/doctrine-migrations-bundle": "^1.3|^2.0", // 2.1.2
"doctrine/orm": "^2.5.11", // v2.7.2
"doctrine/persistence": "^1.3.7", // 1.3.8
"easycorp/easy-log-handler": "^1.0", // v1.0.9
"http-interop/http-factory-guzzle": "^1.0", // 1.0.0
"knplabs/knp-markdown-bundle": "^1.7", // 1.8.1
"knplabs/knp-paginator-bundle": "^5.0", // v5.0.0
"knplabs/knp-snappy-bundle": "^1.6", // v1.7.0
"knplabs/knp-time-bundle": "^1.8", // v1.11.0
"league/flysystem-aws-s3-v3": "^1.0", // 1.0.23
"league/flysystem-cached-adapter": "^1.0", // 1.0.9
"league/html-to-markdown": "^4.8", // 4.8.2
"liip/imagine-bundle": "^2.1", // 2.3.0
"nexylan/slack-bundle": "^2.1", // v2.2.1
"oneup/flysystem-bundle": "^3.0", // 3.3.0
"php-http/guzzle6-adapter": "^2.0", // v2.0.1
"sensio/framework-extra-bundle": "^5.1", // v5.5.3
"symfony/asset": "5.0.*", // v5.0.2
"symfony/console": "5.0.*", // v5.0.2
"symfony/dotenv": "5.0.*", // v5.0.2
"symfony/flex": "^1.0", // v1.17.6
"symfony/form": "5.0.*", // v5.0.2
"symfony/framework-bundle": "5.0.*", // v5.0.2
"symfony/mailer": "5.0.*", // v5.0.2
"symfony/messenger": "5.0.*", // v5.0.2
"symfony/monolog-bundle": "^3.5", // v3.5.0
"symfony/security-bundle": "5.0.*", // v5.0.2
"symfony/sendgrid-mailer": "5.0.*", // v5.0.2
"symfony/serializer-pack": "^1.0", // v1.0.2
"symfony/twig-bundle": "5.0.*", // v5.0.2
"symfony/twig-pack": "^1.0", // v1.0.0
"symfony/validator": "5.0.*", // v5.0.2
"symfony/webpack-encore-bundle": "^1.4", // v1.7.2
"symfony/yaml": "5.0.*", // v5.0.2
"twig/cssinliner-extra": "^2.12", // v2.12.0
"twig/extensions": "^1.5", // v1.5.4
"twig/inky-extra": "^2.12" // v2.12.0
},
"require-dev": {
"doctrine/doctrine-fixtures-bundle": "^3.0", // 3.3.0
"fzaninotto/faker": "^1.7", // v1.8.0
"symfony/browser-kit": "5.0.*", // v5.0.2
"symfony/debug-bundle": "5.0.*", // v5.0.2
"symfony/maker-bundle": "^1.0", // v1.14.3
"symfony/phpunit-bridge": "5.0.*", // v5.0.2
"symfony/profiler-pack": "^1.0", // v1.0.4
"symfony/var-dumper": "5.0.*" // v5.0.2
}
}
Hi, I ran into some trouble with my entities after moving to symfony 5 (5.4). I while back (already in sym 4 possibly) we were instructed to reference our entities with a "::class" at the end in the getRepository() function. I had nested my Entities to keep them cleaner in the directory structure and therefore opted to keep my way of referencing them (as it still worked back then). My directory structure looks like this
I currently do this when I pick up an entity
$analyses = $em->getRepository('App:Hazardlog\Analysis')->findAll();
That no longer works. I've tried all three of these with no luck:
Is there no longer a way to keep my entities neatly organized into folders? Or is there a trick to referencing them?