WEBVTT

NOTE Created by CaptionSync from Automatic Sync Technologies www.automaticsync.com

00:00:01.016 --> 00:00:04.646 align:middle
So our content browser was
working beautifully...

00:00:04.986 --> 00:00:07.026 align:middle
until we selected an item.

00:00:07.566 --> 00:00:13.166 align:middle
At that time, it chose to
do an odd thing: explode!

00:00:13.746 --> 00:00:20.596 align:middle
The Ajax call that failed says: Value loader
for doctrine_recipe value type does not exist.

00:00:21.406 --> 00:00:27.196 align:middle
To review: we have a custom value
type called doctrine_recipe,

00:00:27.516 --> 00:00:33.016 align:middle
which we created so that we could add
grids and lists of Recipe entities.

00:00:33.706 --> 00:00:40.206 align:middle
For this to work, we have (1): a value
converter to convert Recipe objects

00:00:40.206 --> 00:00:42.506 align:middle
into a format understood by layouts.

00:00:43.016 --> 00:00:47.476 align:middle
(2) a query type to allow us
to use dynamic collections.

00:00:47.946 --> 00:00:52.576 align:middle
(3) a browser backend class to
allow us to select manual items.

00:00:53.076 --> 00:00:59.306 align:middle
And now (4), we need a value loader
that is able to take the "id"

00:00:59.306 --> 00:01:04.806 align:middle
of these manually-selected items
and turn them into Recipe objects.

00:01:05.306 --> 00:01:10.036 align:middle
This will be the last "thing" we
need for our value type, I promise!

00:01:10.986 --> 00:01:15.556 align:middle
Inside the src/Layouts/ directory, create
a new class called RecipeValueLoader,

00:01:16.636 --> 00:01:22.376 align:middle
make it implement ValueLoaderInterface
and generate the two methods it needs.

00:01:23.076 --> 00:01:24.256 align:middle
These are pretty simple.

00:01:24.686 --> 00:01:31.026 align:middle
But, before we fill them in, go back to
the Ajax endpoint, and refresh to see...

00:01:31.406 --> 00:01:33.496 align:middle
the exact same error.

00:01:34.076 --> 00:01:41.316 align:middle
Why? Like we've seen with other things, we
need to "associate" this RecipeValueLoader

00:01:41.536 --> 00:01:44.606 align:middle
with our doctrine_recipe value type.

00:01:45.376 --> 00:01:47.166 align:middle
How? No surprise!

00:01:47.436 --> 00:01:48.846 align:middle
With a tag.

00:01:49.716 --> 00:01:55.826 align:middle
Say #[AutoconfigureTag()] and this time
it's called netgen_layouts.cms_value_loader.

00:01:56.496 --> 00:02:00.896 align:middle
For the second argument, pass
value_type set to doctrine_recipe.

00:02:01.646 --> 00:02:04.296 align:middle
Perfecto! If we reload now...

00:02:05.256 --> 00:02:10.236 align:middle
better! That error is because we haven't
actually filled in the logic yet.

00:02:11.006 --> 00:02:15.766 align:middle
Very simply, we need to take the
ID and return the Recipe object.

00:02:16.316 --> 00:02:22.836 align:middle
To do that, create a constructor that accepts
a RecipeRepository $recipeRepository argument.

00:02:23.546 --> 00:02:25.206 align:middle
And... let me clean things up.

00:02:25.946 --> 00:02:32.636 align:middle
Now, down here, return
$this-&gt;recipeRepository-&gt;find() and pass $id.

00:02:33.306 --> 00:02:40.076 align:middle
For loadByRemoteId(), which we only need if
we're using the import feature to move content

00:02:40.076 --> 00:02:44.396 align:middle
across databases, just return $this-&gt;load($id).

00:02:45.246 --> 00:02:46.226 align:middle
And now...

00:02:48.006 --> 00:02:49.926 align:middle
the Ajax call works!

00:02:50.376 --> 00:02:54.856 align:middle
More importantly, if we refresh
the entire layouts admin...

00:02:55.326 --> 00:02:57.036 align:middle
yes! Look at our grid!

00:02:57.246 --> 00:02:59.456 align:middle
We have four manual items!

00:02:59.776 --> 00:03:01.316 align:middle
That is awesome!

00:03:01.946 --> 00:03:07.596 align:middle
We can reorder these if we want,
add more, remove them, whatever.

00:03:08.246 --> 00:03:15.036 align:middle
Try publishing this page and
then reloading the homepage.

00:03:16.676 --> 00:03:17.576 align:middle
There they are!

00:03:18.126 --> 00:03:21.446 align:middle
Though our "latest recipes" are missing.

00:03:22.076 --> 00:03:26.976 align:middle
Whoops! I think I accidentally changed
this to a manual collection also.

00:03:27.676 --> 00:03:38.756 align:middle
Change that back to a dynamic
collection, looks good, publish and....

00:03:38.756 --> 00:03:42.306 align:middle
now... cool: everything is back.

00:03:43.076 --> 00:03:47.586 align:middle
So we now have the power to select
manual items via the content browser...

00:03:48.006 --> 00:03:54.696 align:middle
though when we originally add the config for
all of this, we set a preview template...

00:03:55.046 --> 00:03:56.906 align:middle
but never created it!

00:03:57.646 --> 00:03:59.486 align:middle
Let's open the content browser again.

00:03:59.946 --> 00:04:03.056 align:middle
So on the manual grid, hit "Add Items".

00:04:03.836 --> 00:04:07.346 align:middle
The preview template powers
the preview mode up here.

00:04:08.286 --> 00:04:11.146 align:middle
If we click an item, it shows us a preview.

00:04:11.716 --> 00:04:13.136 align:middle
Well, it would...

00:04:13.276 --> 00:04:16.836 align:middle
except that we haven't actually
added that template.

00:04:17.696 --> 00:04:20.846 align:middle
To get this working, we need
to do two small things.

00:04:21.166 --> 00:04:23.796 align:middle
First, open RecipeBrowserBackend.

00:04:24.486 --> 00:04:26.196 align:middle
We skipped a few methods in here.

00:04:26.706 --> 00:04:31.726 align:middle
For example, we skipped getSubLocations()
and getSubLocationsCount()

00:04:32.076 --> 00:04:36.476 align:middle
because those are only need if
you have a hierarchy of locations.

00:04:37.416 --> 00:04:39.126 align:middle
We also skipped loadItem().

00:04:39.716 --> 00:04:41.676 align:middle
This is used for the preview.

00:04:41.676 --> 00:04:48.696 align:middle
It will pass us the ID of the thing that's
loaded and we need to return an ItemInterface.

00:04:49.516 --> 00:04:55.946 align:middle
So very simply, we can return a new
RecipeBrowserItem() - that's the little class

00:04:55.946 --> 00:05:02.276 align:middle
that wraps around the Recipe - passing
$this-&gt;recipeRepository-&gt;find($value).

00:05:03.216 --> 00:05:07.256 align:middle
Cool! The only other thing we need to do is...

00:05:07.256 --> 00:05:09.566 align:middle
actually create the preview template!

00:05:10.446 --> 00:05:16.366 align:middle
In templates/nglayouts/, add a new directory
called content_browser/, and inside,

00:05:16.646 --> 00:05:20.126 align:middle
a new file called recipe_preview.html.twig.

00:05:20.846 --> 00:05:23.266 align:middle
To start, just print the dump() function.

00:05:24.076 --> 00:05:27.126 align:middle
The cool thing is, we don't
even need to refresh.

00:05:27.706 --> 00:05:32.026 align:middle
As long as we click on an item that
we haven't already clicked on...

00:05:32.576 --> 00:05:39.396 align:middle
it works! And look at this item variable:
it's an instance of RecipeBrowserItem...

00:05:39.786 --> 00:05:43.496 align:middle
so an instance of this class right here.

00:05:44.306 --> 00:05:45.406 align:middle
That's great...

00:05:45.906 --> 00:05:53.496 align:middle
except that RecipeBrowserItem doesn't have a
way for us to get the actual Recipe object.

00:05:54.106 --> 00:05:56.826 align:middle
Fortunately, we can fix that ourselves.

00:05:57.246 --> 00:05:59.936 align:middle
After all, this is our class!

00:06:00.776 --> 00:06:04.636 align:middle
I'll go to Code -&gt; Generate to
generate a getRecipe() method.

00:06:05.506 --> 00:06:11.096 align:middle
Now, in the template, we
can say item.recipe.name.

00:06:11.846 --> 00:06:18.646 align:middle
And to make this fancier, add an &lt;img
whose src is set to item.recipe.imageUrl...

00:06:19.256 --> 00:06:21.366 align:middle
also with an alt attribute.

00:06:22.236 --> 00:06:24.696 align:middle
Once again, we don't need to refresh.

00:06:25.406 --> 00:06:30.686 align:middle
If you click on an item that you've already
previewed, it'll load it from memory.

00:06:31.416 --> 00:06:32.746 align:middle
But if you click a new one...

00:06:33.346 --> 00:06:35.616 align:middle
yeah! There's our preview!

00:06:35.886 --> 00:06:37.026 align:middle
Pretty cool.

00:06:38.076 --> 00:06:44.106 align:middle
Ok, we are done with manual items,
the content browser and all of this.

00:06:44.736 --> 00:06:51.816 align:middle
By the way, there is a way to add more columns
to this table, like filename, file size,

00:06:51.816 --> 00:06:57.286 align:middle
created date, etc. We're not going to talk
about that, but it's totally possible.

00:06:58.196 --> 00:07:05.526 align:middle
Status check: at this point, we have the ability
to add a layout to any page, reorder the content

00:07:05.526 --> 00:07:13.476 align:middle
on the page, add title, text, HTML blocks,
or even lists and grids of dynamic recipes.

00:07:13.876 --> 00:07:16.036 align:middle
That is a lot of power.

00:07:16.776 --> 00:07:19.236 align:middle
Now I want more power!

00:07:19.806 --> 00:07:25.756 align:middle
I want to make it possible to use the grid and
list blocks to add other items to our page...

00:07:26.256 --> 00:07:29.226 align:middle
items that do not live in our database at all.

00:07:29.676 --> 00:07:30.646 align:middle
That's next.

