Inserting Data via Fixtures
…paste some code from the tutorial/ directory.
We now have three ship objects, but nothing has been saved - or persisted to the
database yet. But interesting, Doctrine passes us an ObjectManager.
This is the heart of Doctrine. We'll use it to save, fetch, update…
Fetching with DQL, the QueryBuilder & find()
…query, in this case,
our homepage() method.
One bummer is that DQL isn't that pretty!
Luckily, Doctrine has a "query builder". This thing is awesome: instead of writing
the DQL string manually, we build it with an object.
Back in our homepage() method, replace…
Cosmic Queries: the Repository Class
…Cool! We have an App\Repository\StarshipRepository
object. Go check out this class: src/Repository/StarshipRepository.php.
First, if you're curious how Doctrine knows this class is the repository for the
Starship entity, jump into src/Entity/Starship.php. Ah, the #[ORM\Entity]
attribute…
Ship Upgrades: Updating an Entity
…on our homepage only lists incomplete starships, so we need to find a
completed one. In your terminal, run:
symfony console doctrine:query:sql 'SELECT slug, status FROM starship'
lunar-marauder-1 is a completed ship. Copy the slug, and back in the app,
visit…
Setup & Ways to Extend API Platform
…validation, voters, and more.
That's all good stuff. But, so far, all of our #[ApiResource] classes have been
Doctrine entities. And that's fine! But as your API starts to look different from
your entities, making that work adds complexity: serialization groups, extending
normalizers…
Decorating the CollectionProvider
…the failed response. Hmm:
More than one result was found for query, although one row or none was expected.
If you view the page source, this is coming from Doctrine... and eventually the
core ItemProvider that we're calling. Back on the docs, the GetCollection…
Many To One: The King of Relationships
…null.
But that's not allowed, thanks to the nullable: false. Clear those 50 rows with:
symfony console doctrine:query:sql "DELETE FROM starship_part"
And run the migration again:
So, how do we go about linking a StarshipPart object with its Starship?
Buckle up…
State Processors: Hashing the User Password
…platform: we need some way to run
code after our data is deserialized onto the User object, but before it's saved.
In our tutorial about API platform 2, we used a Doctrine listener for this,
which would still work. Though, it does some negatives…
Partial Handler Failures & Advanced Routing
…there's a problem removing this ImagePost from
the database, Doctrine will throw an exception right here and the file will never
be deleted. That's perfect: the row in the database and file on the filesystem
will both remain.
But if deleting the row…
SELECTing into a New DTO Object
… I like to work with
objects whenever possible. Fortunately, Doctrine gives us a simple way to improve
this situation: we query for the data we want... but tell it to give us an object.
First, we need to create a new class that will hold…
The Failure Transport
…an expanded
format where you put the dsn on its own line and then add an options key with
whatever you need below that.
What options can you put here? Each transport type - like doctrine or amqp -
has its own set of options. Right now…
Translated Object Wrapper
…ObjectTranslator, we have
this todo waiting for us.
There's a couple ways we can approach this. One way is to directly modify
the properties on the object. But since this is a Doctrine entity, it'll
be marked as modified. If you unintentionally flush…
stateOptions + entityClass Magic
…darn it, let's
yolo this thing and try to!
Head over to UserApi, say provider, and point to CollectionProvider
(the one from Doctrine ORM).
Let's see what happens! At the browser, go to the endpoint directly -
/api/users.jsonld. And... we get an…
Raw SQL Queries
…s as boring as SQL queries can
get. I used fortune_cookie for the table name because I know that, by default,
Doctrine underscores my entities to make table names.
Now that we have the query string, we need to create a Statement with
$stmt…
JOINs
…a database perspective, in order to update our
WHERE clause to include WHERE fortune_cookie.fortune = :searchTerm, we first
need to JOIN to the fortune_cookie table.
And that is what we're going to do in Doctrine... except with a twist. Instead
of…
Performance Optimization 2: Caching
…ObjectTranslator service. Down here in the
translationsFor() method, this findBy() is what's making the queries.
This is what we want to cache!
Doctrine does offer some result caching, but it can get complex isn't
as flexible as the Symfony Cache component. So, let…
Translatable Mapping
…and slick approach is to use PHP
attributes.
I'm all for slick and modern, so let's go with attributes.
These will be similar to these Doctrine ORM mapping attributes. Ours will
map translatable entities and properties.
In our object-translation-bundle/src directory…
Bundle Configuration
…reference
With no arguments. This lists all the loaded bundle's, and their configuration
key (or extension alias). DoctrineBundle, alias doctrine, DoctrineMigrationsBundle,
alias doctrine_migrations. Here's our bundle: ObjectTranslationBundle, alias
object_translation.
Hmm, I'd like to prefix it with symfonycasts, like the Tailwind…
Setting Relations in Foundry
…our good
friend: Foundry. Remove the manual code, then anywhere, say:
StarshipPartFactory::createMany(100):
And try the fixtures:
symfony console doctrine:fixtures:load
Uh-oh!
starship_id cannot be null in starship_part.
This traces all the way back to StarshipPartFactory, down in
the defaults…
DTO -> Entity State Processor
…the item of type UserApi.
We already talked about what's happening: the JSON is deserialized into a UserApi
object. Good! Then the core Doctrine PersistProcessor is called because
that's the default processor when using stateOptions. But... because our
UserApi isn't an entity…
x
1000+