-
Notifications
You must be signed in to change notification settings - Fork 214
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
ae789ed
commit a0cc6bc
Showing
1 changed file
with
117 additions
and
98 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,166 +1,185 @@ | ||
# Doing Crazy things with Foundry & Fixtures | ||
|
||
Coming soon... | ||
|
||
We want to take. Well, we | ||
actually want is, are the published questions were down or created down here to be | ||
related to some random tags. We don't want to create more random questions up here. | ||
So I'm going to believe the return save and add that `QuestionTagFactory` line. So | ||
the way we were doing this before is we had this call back and we said, okay, set | ||
the tags property to a zero to five random tag objects. But our question entity does | ||
not have a `tags` property anymore. Our question into now is a `questionTags` | ||
property. Okay. So let's change this to how about `questionTags` And then is set | ||
to, and we could say a `QuestionTagFactory::randomRange()` here, but that would | ||
require us to create those question tags above here first, which I don't really want | ||
to do. So I'm gonna say `QuestionTagFactory::new()`. So we're going to set the | ||
`questionTags` property to a `QuestionTagFactory` that this isn't making sense yet. | ||
It's okay. Stick with me | ||
|
||
|
||
There is one small problem with this, but this is mostly correct. So what this is | ||
going to do is it's going to tell Foundry to use this `QuestionTagFactory` instance, | ||
to create a new `QuestionTag` object, but because we're doing this from inside the | ||
`QuestionFactory` creation, when it creates this `QuestionTagFactory`, instead of | ||
creating a new `Question`, the question attribute is actually going to be overridden by | ||
whatever question is currently being created. So in other words, this will not cause | ||
a new question to be created in the database. It will relate it to, to whatever | ||
question object is currently being created. Now I said, there is one small problem | ||
with this and we'll see it right here. | ||
We *are* able to create new `QuestionTag` objects with its factory... but when | ||
we do that, it creates brand *new* `Question` objects. That's... not what we | ||
want! I want what we had before... where we create our 20 published questions | ||
and relate *those* to a random set of tags. | ||
|
||
```terminal-silent | ||
symfony console doctrine:fixtures:load | ||
``` | ||
Delete the `return` statement and the `QuestionTagFactory` line. Right now, | ||
this says: | ||
|
||
> Create 20 questions. And, for each one, set the `tags` property to 5 random | ||
> `Tag` objects. | ||
## Setting the questionTags Property on Question | ||
|
||
The problem is that our `Question` entity doesn't *have* a `tags` property anymore: | ||
it now has a `questionTags` property. Okay. So let's change this to `questionTags`. | ||
We *could* set this to `QuestionTagFactory::randomRange()`. But that would require | ||
us to create those `QuestionTag` objects up here... which we *can't* do because | ||
we need the *question* objects to exist first. | ||
|
||
By the way, we're about to see some *really* cool, really advanced stuff in | ||
Foundry. But at the end, I'm also going to show a simpler solution to creating | ||
the objects we need. | ||
|
||
If we ate, yes, we get something that says | ||
they property question tags. Uh, Okay. Kind of a weird air from the property accessor | ||
about question tags can set attribute question tags. This is a little bit hard to | ||
read, but what's happening here is this is grading eight single question tag object, | ||
and then trying to set it onto the question, tags property. All we need is an array. | ||
So what I'm going to do here is say `->many()` what this basically says, we still have a | ||
`QuestionTagFactory` instance, more or less, but it's configured to return many items | ||
now onto this property. | ||
## Foundry Passes the Outer Object to the Inner Factory | ||
|
||
25 living the fixtures now. | ||
Anyways, set `questionTags` to `QuestionTagFactory::new()`. So, to an *instance* | ||
of this factory. | ||
|
||
There *is* a problem with this... but it's *mostly* correct. And... it's kind of | ||
crazy! This tells Foundry to use this `QuestionTagFactory` instance to create a new | ||
`QuestionTag` object. But because we're doing this from *inside* the `QuestionFactory` | ||
the `question` attribute that's passed to `QuestionTagFactory` will be overridden | ||
and set to whatever `Question` object is currently being created. | ||
|
||
In other words, this will *not* cause a new, extra `Question` to be created in the | ||
database. Instead, the new `QuestionTag` object will be related to whatever Question | ||
is currently being created. Foundry does this by *reading* the Doctrine relationship | ||
and smartly overriding the `question` attribute on `QuestionTagFactory`. | ||
|
||
But... I *did* say that there was a problem with this. And... we'll see it right | ||
now: | ||
|
||
```terminal-silent | ||
symfony console doctrine:fixtures:load | ||
``` | ||
|
||
Oh, and they'll tell us how many we want. Well, we can | ||
actually give it a random range here or, uh, create anywhere from one to five new | ||
question tag objects, somebody go over now and run the fixtures. | ||
This gives us a weird error from `PropertyAccessor` about how the `questionTags` | ||
attribute cannot be set on `Question`. The `PropertyAccessor` is what's used to | ||
*set* each attribute from Foundry onto the object. And, while it's true that | ||
we don't have a `setQuestionTags()` method, we *do* have `addQuestionTag()` and | ||
`removeQuestionTag()`, which the accessor is smart enough to use. | ||
|
||
So, the problem is simpler: `QuestionTagFactory::create()` sys that we want | ||
to create a *single* `QuestionTag` and set it onto `questionTags`. But we need | ||
an *array*. To fix this, add `->many()`. | ||
|
||
This "basically" returns a factory instance that's now configured to create | ||
*multiple* objects. Pass 1, 5 to create anywhere from 1 to 5 `QuestionTag` objects. | ||
|
||
Try the fixtures again: | ||
|
||
```terminal-silent | ||
symfony console doctrine:fixtures:load | ||
``` | ||
|
||
It works | ||
|
||
And he was a really cool thing. If we `SELECT * FROM question`, | ||
No errors! And if we `SELECT * FROM question`: | ||
|
||
```terminal-silent | ||
symfony console doctrine:query:sql 'SELECT * FROM question' | ||
``` | ||
|
||
we only have 25 | ||
entries in here. That's the correct amount. That's the 20 up here and then a five | ||
down here. So this question tag factory did not create new questions like you did a | ||
second ago. All the new question tags are related to these 20 questions. We can see | ||
that by queering. `SELECT * FROM question_tag`. | ||
We only have 25 rows: that's the correct amount! That's the 20 published... and | ||
the five unpublished. The point is: the `QuestionTagFactory` did *not* create new | ||
question objects like it did a second ago: all the new question tags are related | ||
to these 20 questions. We can see that by querying: `SELECT * FROM question_tag` | ||
|
||
|
||
```terminal-silent | ||
symfony console doctrine:query:sql 'SELECT * FROM question_tag' | ||
``` | ||
|
||
And you can say each question tag | ||
there. This is a related question. I'd be 57, 57, 57 57. The next one is 56, 56 and | ||
then 55. So a random number. Each question is random number. | ||
60 rows seems about right. This is related to question 57, 57, 57, 57... then 56, | ||
56 and then 55. So each question has a random number. | ||
|
||
## Overriding the tag Attribute | ||
|
||
Unfortunately this line here is somewhere on this line. It is still creating a new | ||
random tag. So if you say `SELECT * FROM tag` | ||
Unfortunately this line *is* still creating a new random `Tag` object each time. | ||
Check the `tag` table: | ||
|
||
```terminal-silent | ||
symfony console doctrine:query:sql 'SELECT * FROM tag' | ||
``` | ||
|
||
you would hope that we have a | ||
hundred, because what we really want to do is when these question tags are created | ||
and we want it to use one of these 100 up here, but instead of having just a hundred, | ||
we have 160, it creates these a hundred up here. And then each for each question tag | ||
factory, it's still creating a new tag behind the scenes. Okay? So no problem. It's | ||
kind of nuts. But what we can do here is we can just pass. We can override the `tag` | ||
for this instead of to `TagFactory::random()` to grab one existing random | ||
We *want* there to be 100 rows... from the 100 in our fixtures. We don't want | ||
*extra* tags to be created down here. But... we get 160: 100 plus 1 more for | ||
each `QuestionTag`. | ||
|
||
And... this make sense, thanks to the `getDefaults()` method. | ||
|
||
The fix... is both nuts and simple: pass an array to `new()` to override the | ||
`tag` attribute. Set it to `TagFactory::random()` to grab `one` existing random | ||
`Tag`. | ||
|
||
So for reload fixtures now, | ||
Reload fixtures now: | ||
|
||
```terminal-silent | ||
symfony console doctrine:fixtures:load | ||
``` | ||
|
||
and then query for tag table, | ||
And query the tag table: | ||
|
||
```terminal-silent | ||
symfony console doctrine:query:sql 'SELECT * FROM tag' | ||
``` | ||
|
||
as we're back to just 99 tags, | ||
but there's still one tiny problem. And maybe you saw it's a little bit subtle. If we | ||
select from question tag, | ||
We're back to 100 tags! But I made a mistake... and maybe you saw it. Check | ||
out the `question_tag` table: | ||
|
||
```terminal-silent | ||
symfony console doctrine:query:sql 'SELECT * FROM question_tag' | ||
``` | ||
|
||
you can see that down here. These last two tags are both | ||
related to the question ID, uh, with 82. And in fact, so is this one right here? | ||
That's great. Every question is going to have anywhere from one to five question | ||
tags, but all three of these tags are related to the same. Uh, the same tag one, each | ||
question is created. It calls this call back. So this callback is ultimately called | ||
20 times. Then when the question then when each question tag is creative, that | ||
question, it actually is going to find a random tag, but then use that for all the | ||
question tags for this question. So the tags are being reused in the same way. This | ||
is the same situation we've seen before. We knew as refactor to use A call back. Now, | ||
if we reload the fixtures | ||
These last two are both related to the question id 82... actually the last 3. | ||
And that's fine: each `Question` will be related to 1 to 5 question tags. The | ||
problem is that all of these are *also* related to the same `Tag`! | ||
|
||
In the fixtures, each time a `Question` is created, it executes this callback. | ||
So it's executed 20 times. But then, when the 1 to 5 `QuestionTag` object are | ||
created, `TagFactory::random()` is only called *once*... meaning that the *same* | ||
tag is used for each `QuestionTag`. In other words, this is the same problem | ||
we've seen multiple times before... I'm trying to make this mistake as *many* | ||
times in this tutorial, so that you *never* experience it. | ||
|
||
Refactor this to use a callback. Then, reload the fixtures: | ||
|
||
```terminal-silent | ||
symfony console doctrine:fixtures:load | ||
``` | ||
|
||
And then the square from question tag. | ||
And check the `question_tag` table: | ||
|
||
```terminal-silent | ||
symfony console doctrine:query:sql 'SELECT * FROM question_tag' | ||
``` | ||
|
||
Yes. So you can see that these last two have | ||
the same question ID and they also, but they have different tag IDs. This has | ||
accomplished our mission. Now this is the most insane thing that you can do with | ||
Foundry. This says, create 20 questions for each question. The question tags should | ||
be set to a new question tag, except I want that question tag to be assigned to this | ||
question. Cause since it's inside the, that call back to that question and I would | ||
override it's tag, it should be one of these random tags here. Pru regulations. Do | ||
you not have your PhD in using Foundry? Now you do not need to make it this | ||
complicated. I mostly did this just to prove and show like the deepest, darkest parts | ||
of Foundry, An easier way to do this would have been to create a hundred tags, 20 | ||
published questions. And then down here, Use the question tag factory to create, For | ||
example, a hundred question tags Were each one Is related to a random tag And also a | ||
random question. So if you did this, then you can actually simplify things a whole | ||
lot. | ||
|
||
So if we try this | ||
Yes! These last 2 have the same question id... but they have *different* tag ids. | ||
Mission accomplished! And... this is probably the most *insane* thing that you'll | ||
do with Foundry. This says: | ||
|
||
> Create 20 questions. For each question, the `questionTags` property should be | ||
> set to 1 to 5 new `QuestionTag` objects... except where its `question` attribute | ||
> is overridden to be set to the new `Question`. Then, for each `QuestionTag`, | ||
> select a random `Tag`. | ||
Congratulations, you now have a PhD in Foundry! | ||
|
||
## The Simpler Solutions | ||
|
||
But... you do *not* need to make it this complicated! I did this mostly for the | ||
pursuit of learning! To show off the most advanced stuff you can do with Foundry. | ||
|
||
An easier way to do this would be to create a 100 tags, 20 published questions | ||
and *then*, down, use the `QuestionTagFactory` to create, for example, 100 | ||
`QuestionTag` objects where each one is related to a random `Tag` also a random | ||
`Question`. | ||
|
||
If we try this: | ||
|
||
```terminal-silent | ||
symfony console doctrine:fixtures:load | ||
``` | ||
|
||
No errors, and if you look inside of the question tag table, | ||
No errors. And if you look inside the `question_tag` table: | ||
|
||
```terminal-silent | ||
symfony console doctrine:query:sql 'SELECT * FROM question_tag' | ||
``` | ||
|
||
we get | ||
basically the same result. We get a hundred question tags and each of these is | ||
related to a random question and a random tag. All right, next, let's fix the front | ||
end where we use this relationship. Now that we've changed it. | ||
We get 100 question tags, each related to a random `Question` and a random `Tag`. | ||
It's not *exactly* the same as we had before, but it's probably close enough, | ||
and much simpler. | ||
|
||
Next: let's fix the frontend to use the refactored `QuestionTag` relationship. |