Brightspot back-end training webinar

image of computer screen for Brightspot back-end training webinar
Requires Login
0:00 / 0:00
Video Companion
Brightspot back-end training webinar

Looking to learn more about data modeling and back-end development using Brightspot? Start with this training, led by our world-class team of experts.

Click here to download a copy of the back-end training deck.


Speaker 1: just a couple of housekeeping items real quick. Um We will be recording this um So you'll be able to come back later and reviews sections that you want to, I'm going to move kind of fast because we do have a lot of material to cover, but you will be able to go back and review and you know, practice things at your own pace and we will make that recording available as well as the slides afterwards. You can again review those um at your leisure and if you have any questions, um please put them in the chat and then I will either answer them right away or maybe defer them until later if it would fit better with the uh the flow. So with that let's get started. So today we're gonna be covering a couple of things. First, going to do a demo of the CMS with a focus on developers, how the developer would see the CMS. Um Then we're gonna talk a bit about the distinction between Bright spot and Daren just to understand some terminology, we'll review some roots style guide concepts. Um Those are also covered in the front entrance, which you may have seen yesterday. Uh And if not is also available with recording slides if you want to receive that. Uh And then we're going to spend the rest of the time going through an extended exercise. We're going to cover a lot of different back end topics and not including the roots style guide data modeling, view models, the save livestock, which is, you know, advanced data modeling effectively as well as modifications. And then finally we're going to look at the graphic, you L A P I. S, which is a newer feature that bright spot authors. Okay, so first CMS demo, we're going to focus on a couple of areas um and let's start back here. So right here I'm running um Bright spot um locally on on a doctor. This is provided um with the training materials, there's a docker environment which has some data already um populated in it. So you can actually see a full site um like you would, if you know, you actually had content published and people have been working in CMS to create stuff. Um So that's what I'm running here. What we're looking at right now is the dashboard, which is sort of the main homepage of the CMS effectively. That's what you see when you first log in. Um and it sort of just presents a bunch of different widgets that for the editors to help them, you know, get things quickly and see overview of the of the CMS. So uh this is customizable, but this is the sort of default when it comes with bright spot. Um so you've got some areas you can use to create your content and to see recent activity um and continents being worked on and work streams and whatnot. So from a developer's perspective, um you probably won't have much to do with the dashboard unless you end up needing a custom dashboard widget in which case you would be able to do some classes you can use to code that up and then that would be able to configure that to show up on on the dashboard. Um We're not actually going to cover that in this train, but just be aware that that is available to you, Should there be a requirement for that? Uh So the next thing is the search dropdown. This is a the main way of finding content. You can also create content from here with the create dropdown at the bottom here. This allows editors to find content uh by type as well as um filtered down by various um things depending on the content text. So maybe it could be part of the sections, you can filter on sections um or published date or status of whether it's still in, you know, in draft or workflow or if it's actually already been published live um filtered by date. So there's not, there are some customization that you continue as a developer but they're not that common. But the main thing is just this is how you find stuff. So when you're, when you're working with CMS debugging things, creating things, this is sort of the main like um epicenter for all of that. Um So then the next thing, let's take a look at an article. Um So this is what we call the content. Edit page. Each content type has its own version of this page has the fields that the editors can fill in things to populate the content type with whatever values make sense. There there are also widgets on the side here for configuring various things um and they're also fields can be organized on tabs, so we can have some more fields here on the SEo tab for the styles tab. And then um we've also got a widget down here at the bottom called conversation. So from a developer's perspective, this is a lot of your time should be spent with data modeling is setting this setting this page up effectively for the editors. Um So you can see here there's different field types of rich text or plain text, you can have things like placeholders. Um we can select references to other content types in bright spot. Um We can sort of create additional like subtypes inside this is called an embedded content type. So the lead here rather than me selecting, you know, some reference to some other piece of content database, I can actually just create something in line right here in this case was the lead um moderate Ataxia with more options. The toolbar here has provided more things like uh images and enlists, um People will pop up whatnot. That's so that's all configurable and various, you know, various different types of fields and how they can be arranged. So although that we're going to get into a little bit here when we get into data modeling, you'll note that different fields render in different ways. So um for instance on on the lead here, the image is sort of a special uh content type so rather than just looking like, you know, I selected an author here, it just has the name of it right here. An image actually got a preview um of what it looks like and then if you actually go into the image there are special ending options for, you know, changing the brightness or rotating the image and whatnot. Um so that's different, different field types might have different presentations dates. Another one um where you actually don't have an example of it in the field but you'll see it in the I'm up here for choosing to publish date that you sort of get a special date format as opposed to having to type in the date manually. Um And then for the widgets there are actually three different areas that you can place the widget the right, which is the most common location. And then you can also place widgets at the top, so they would just appear above the headline here and below the um sort of article labeled and you can also place them at the bottom uh this this conversation widget and finally you can actually place widgets as tabs. So you can have a I think there's actually, I don't think stiles is uses a tablet, There are some um some wages that actually do short as a tab. And so from that perspective it's no different than into the other tabs but from the developers presented it's very different because it's coming from a totally different source. Another important thing to note is the preview. So a lot of um editors will actually work with the preview open all the time so they might have a wider screen like this and they would actually be able to see as they type sort of um changes made into the preview as they type and change things so I can change the offer here. You can't really see it's not zoomed in but we gotta switch this down to more global tablet options will be sealed better. Um So as editors are working, you know basically you're the contact is going to be rendered um for them so they can see what is going on. And that's gonna be something to keep in mind when we get the data model as far as like how to make sure that's a smooth um experience for them. Okay, that's it for the content edit page. So the final thing we're going to look at is um sites and settings. So up here in the top left of the CMS, there's a triple bar menu or hamburger menu and this has some several areas inside of it. We're going to focus on the admin area here and into sites and settings but this is just bothering me because I made some changes. I didn't say to this content type so it doesn't um want me to lose those. But in this case off here um Society and settings um Content and bright spot is grouped into what we call sites which is basically from a developer's protective. It's basically just um all the content on that site is available under a certain well so in this case the U. R. L. Is just local host. So every cop this piece of content that's inside this site would be um some U. RL underneath your clothes like Yoko slash Stage one or whatever. Um Consider is actually gonna allow multiple urals that's mainly used for testing. Um The first one is always the default so that's what everything will be used as far as you like when you create your else or that's what expectation would be the first one is the one that's used. Um But so each site has its own settings. Um Those are configurable here. This kind of looks like the content, edit pages a little bit different. Um But it's a similar kind of thing with your fields that you can um And figure here we'll go into the more more advanced data modeling, how you mentioned how you can actually add fields here if you need to. Um And finally there is global which would basically be sites that are, let's say there are shared among all sites. Um So it's a different, very, very similar ui here, but a different class that you would use to add fields here if you needed settings that were available to every site. There's also something called site settings which is a java interface and that allows you to have settings that appear both on the site and in Global and there's a fallback. So if you haven't set a setting on the site, it will fall back to the one on Global. Um so that's available if that's um better pattern for you rather than just putting it directly on site. Okay, that's it for the CMS tour for now. So you'll note here that by going to the global things have actually gotten into the what we call a global site, which is really the absence of any site. So I mean I'm not an excitement now. So that's signified by global. Um most of time we recommend that you be in a specific state, especially when you're creating content as an editor. So we'll go back to the inspire confidence. Okay, so the next thing we're gonna talk about is bright spot and Dari and what to what the distinction between these two are. So bright spot. Obviously it's the company and its the CMS itself um Dari is so the bright spot provides, you know what we just looked at the CMS editorial user interface user experience. It also provides request handling interview system which will go over more later in the training. Um it also provides a bunch of things to manage content and editors managing the contents of permissions when editors and access workflows, which is the process that piece of company has to go through before it can be published. So there might be a certain reviews that have to happen or people have to approve it. Um there's notifications. So editors can, you know, when something happens, something implies that they need to act on something that they can send, we can send notifications to them, lots of other things there. Um Then Dari is the framework that provides powers bright spots. So it sort of sits underneath the bright spot and provides things like database abstractions, the data modeling using standard java types of temptations and then a bunch of different ap eyes for querying the database for storing, retrieving files, managing tasks, um surveillance, all kinds of things like that. Um So you'll see those terms used sometimes. Bright spot and Dari and that's sort of what do you think of um when when you hear those terms and you also will see the distinction in package names. So sorry, um Come PST Debbie Harry is the package for all the dirty things calm PSD that CMS and then bright spot dot whatever or both packages that are more aligned with bright spot. Mhm Okay. Roots style gun um sort of the glue between the back and the front end um and this was also covered in the front end training from the front of perspective, so now we're gonna look at it from the back end perspective. Um so we call it the roots dog because it originally lived in the project Root, but now it's located in the front end directory. Um so depending on if your project is starting a brand new or is it something that's been around for a while, it might be in one of those two different locations, but it's the principles are the same. Um and it's not to be confused with themes or bundles which have their own style guide directories and should not be confused with the project route um Style guide. Um there will be a lot of similar files in both those style guide directories but they serve different purposes. So the roof dog I specifies views which are basically just collections of fields that each have a specific type. Um Each of you in the roof dog requires Jason and HBs file. HBs for handlebars um and the handlebars file should always be empty because the reason I got is just about the data and not about the actual presentation, so there's no point in typing anything in the handlebars file because it will never be used. Um Whereas if you're working in a bundle, you actually would type in your handlebar, Your markup handlebars content in the handlebars file because that's actually what's gonna get rendered. Another thing. We use our groups which are traditionally located in the underscore groups directory, which allow fields to support multiple types, so maybe we have a media field and we wanna be able to put an image or video there so we can make a group called media and we would specify in the group that can support image or video and then we would use that reference that group from the media field and I'll show you what that looks like a little bit when we get to the root stock in section of the, of the exercise later on and so each view that is specified in the west are good results in a java interface for the back end to implement. So that's sort of how we glue things together. There's a java interface that is um generated from the Jason so it lines up exactly with what was specified in the Jason file, as long as tobacco and implements that, then your build will succeed and you know that everything the fund is expecting is being supplied by the back end and if you were to change things in the J stein file, added fields, remove fields or change the type of the field that would all be reflected in the job interface, changing which means that your build would break and you would know that you needed to address to change. So you would never be able to go um, you know, push something live to production and have it break because you know, you missed the change at the front of needed because you build and you never really get that bill built to deploy the production. So that's how we how we keep things in mind. Um So things to keep in mind roots dog, I was designed for use with handlebars um so it predates graphical and other A. P. I. S. And it's really designed for that purpose. So if you're starting a new project and you're going to use graphical, you probably are not going to use the roots dog, if you have an existing project or you or you have a project that um already has a bunch of handlebars views, it may be appropriate to reuse those in graphic detail and it may not, it just really depends on how they're structured and whether the format that they have makes sense for use in it because maybe i is much different design considerations than handlebars view basically. So you may end up using the star guy with an api chances are you probably would not. Mhm. Okay, so I don't see any questions, so I think we're good to go keep going with the rest of the exercise. This is gonna be basically our our main focus for the rest of the of the training. Um so we've got some high level requirements here. Um editors need to be able to create, search in search of recipes, they want to build the future recipes in an article, they won't be able to tag recipes. Um and so we need to translate these requirements into bright spot terminology. So um basically a recipe is going to be content type and we're going to need a kind of article that would reference a reference at a recipe. Um There's a lot of leeway as far as how you would actually end up doing that in practice with this sort of for this exercise is how we've designed things. We're also going to have a recipe module um so we can place recipes on other on other locations that aren't the specific recipe article. Um And then we're gonna make a new content type for tagging recipes specific um as opposed to using like a generic tag. Okay, so part one is the root stock guy. We're going to create two views. Um and then um well you see what those look like, as far as the interfaces, so thank you, we'll show you here, I'm in the training report right now. Um you can clone this yourself as a public repo um And uh this would be where all the code lives for this exercise, so you can work on this either if you can follow along while we're going into training or um you know, on your own time, come back and review the changes and commit some files that were working with anyway, so I'm on the develop branch right now and I'm going to um check out the first commit on uh this exercise recipe branch. So there's a bunch of commits series or all the different things we're gonna cover in the in the exercise and so I'm just going to sort of go through each commit and so I talked about the changes, so I just made a quick um upper for that so that I can just move through each one. So that's the first commit. Um let's just see what it made, what changes it made quick. So we've got a couple of files here in the root stock, so the front end stock directory, domestic p article page and rest api module. So let me go to my intelligent, we'll take a look at those. Cool, so you can see here, we've got recipe article page dot Jason and the handlebars file. So this is the best on file. Um every view in the black guy's gonna look similar to this um under keys that started underscore our special, so we've got four special keys here. And then we've got uh these are sort of three b three different fields in the views. We've got a lead field, article body field and the recipe field, honestly rapper false. Um It's kind of complicated but basically uh there's a concept in the root stock and whether this is a page for a module effectively. So if it's rappers false, that means it's a page um the rapper is not set or it's true, then it's a module. And so that's really gonna fit figure into how preview works in the same s um so for now we kind of ignore that. It's just rapper falls. It isn't true. I don't think that really does something anything in the woods dog anymore. Um That mattered more with the style guide application which you'll see in the front and training whether it would show up in that or not. Um So included were actually sort of, this is an inheritance mechanism. So we're the viewer creating here is going to extend the creative work page view. Um and then this is telling you that the template it's gonna use is this uh handlebars file again, this file we've already created. Um Mhm. Take a look at it here real quick. It's just an empty file. Um but it has to exist for the build to work. Again, that's kind of a legacy from uh when we used to do things slightly different than we do now. So you just need to have the empty file there and that's really what's gonna name your view. So the view is going to be called rest of the article page view. That's gonna be the name of the job interface that gets generated and then we've got our three fields here. Uh and you can see here these are all um either including or having a direct template, so in the root stock car you're gonna use include for um if it's gonna be a group basically. So what this is saying is um, include this file here. And this is actually gonna have an array inside a bunch of different views that can be considered leads and then um, he just tells it to pick the first one. I don't get out of that really matters in the Woodstock guy. That would matter in the if you're working in a bundle because then that tells the system like which thing to actually display um for the example, install that application. Um so the lead is going to use the leads group and then the article body is going to use the which text elements large group, which basically is all the different things that can go in an article rich text. Vice. Maybe we support images. Maybe we support quotes. Maybe we support a bunch of different things. Those are all specified in that group. And then finally, recipe, if we're just having a similar support, a single field, um, or single type, we can just reference the template directly. So we can just say this is going to be the recipe module template which in java will be the recipe module view interface. So now let's take a look at the other um, do you live with generators. So this is a recipe module? You know, there's not a rapper because this is a module. So it's not a page. Um, it has a separate template recipe module. So that's going to result in a recipe module. View interface. And then we've got a bunch of different fields here and these are simpler types. So um, we've got some groups as well here. We've got an image, but then we've also just got strings. Um, you can also have numbers in here. So maybe we'll actually want these difficulties to be american so we can just specify a number or um, we can also have napoleon's. So basically this is Jason, Kenney, Jason value can put here and that will show up in the tape whether it's in java, it becomes a string or a bully and for a number in your face. So this example, these are all strings. Um, and you could type in things here if you wanted to have an example of like what the spring would look like. Um, that's not necessary. All that matters for the java system is that it has the type. So an empty string. Would any string would be a string? So empty string is fine. We've also got um, title ingredients and directions are all rich text fields. So respect is a little bit different. Um, with bright spots of technically under the hood, these are just strings but we want to be able to strongly typed them to say, you know, the title can only support, you know, we don't want to have images in the title for instance. So we're only going to support certain um types of rich text elements entitled versus like the directions maybe we want to be able to support anything so we can use the large one and then ingredients maybe use the small one. And so under the hood these are going to get rendered out to html but we want to be able to strongly typed. So that's why we we look we have them look this way and um this is sort of a more recent change in Bright little we've made sort of every textual field that the editors can work with is typically expected to be rich text because editors, you know, there's no reason why we they wouldn't shouldn't be able to make like italics in the title for instance, even if we don't want to support anything else. So that's why we have this this timing option. So any field that the others can work with that it's exposed on the front of the week, it should typically be some kind of some type of rich text. Um Okay, so that's it for that. And then let's actually show you. Okay, now that I've got those new interfaces. Okay, uh test, I can tell um get price, build that front end grader project and that will actually rebuild those interfaces that we can see what took those files to generate. So here I'm just running the great old command skipping tests, although there aren't any tests in this specific one, but I'll skip tests for all of our bills just to save time. And then I'm telling you to build a front end project. Um uh actually that's not a good look at it. The pride your project is going to be broken into a bunch of great old projects. So don't confuse the terminology. So we've got core front end and when and then with any fun we've also got, each bundle would have its own project as well. So the front end builds the roots dog died. And then the bundles each have their own projects. So all of your backend code would be in the core project and then the web project is what builds the war for artists that you actually would deploy. Um so depending on what you're working on, you can tell a great deal to just build that one project and that might save a little bit of time. Um so well Young, okay, no report and depending on How many views you have this build might the front end build might take 20 seconds or a minute. Kind of depends on how complex you make things in there, which is why we typically try to keep things as simple as possible because style guide is just specifying the types. We don't have any need to put handlebars markup in there or to use some of the more fancy features that are intended more for use with bundles. Um, It's really just the type that's all we care about so we can make that as quick as possible. So yeah, 30, seconds. It's not too bad. Um so now we've got that built, I can actually go in here now and um okay, look at these new interfaces that we've been hearing. So we've got recipe article page view with that recipe model view. We've also got some additional information that we talked about. Um so here's our recipe article page interface. Remember we had that we included the creative work page. Um and so that's actually going to generate this extending creative work page view. Any fields that are on that view are also going to be present in the rest of the article. We've got a couple of annotations that were added here. Um, do you interface is what tells the right spot review system that um, all of the public methods on your view model, which we're going to talk about that a little bit should be exposed um as you know, into the whoever is using the handlebars or graph QL or whatever. Um, so that's very important interface to have annotation to have on anything that's gonna be interacting with the system and then the view template handlebars temperatures tells the system where the handlebar style lives. Um, so those are just added because it's kind of mars we need those and then if we look at the methods here. Um, you've got article Body lead recipe. Um Yeah, so Article Body is an honorable recipe. Article page review Article Body field. So it actually generated interface to uh to specify um what um Come on, go back to this, remembering article body was the rich text elements. Large groups. So basically whatever was specified in that will then be um generated. Um Whatever views generate from that will also extend this article by the field. Um interface. This is just a mark on her face. It doesn't have any methods but it serves to keep things strongly typed so that um we know exactly what can go in an article Body field and everything else would then um You know, cause a builder, if you want to try to put something in there we didn't want to support. And you can see here, it does list down on the job dot all the different things that satisfy this. Um So these are basically all the different um rich text elements that go with a large rich text toolbar. All right. As well as plain text so that you can do whatever you have those types of words. Those can also show up here. Uh And then similarly for different fields in here, we've got our commodity, the lead would have the lead field interface, whatever things can be leads. And then the recipe field. Ah And this is sort of the new thing that's going to be, we're talking about a second, but basically anything that we've we've only specified the one file for that. Go back to this, we just had a recipe module that HBs so um go to this, you know, always lists rescue module as the as what satisfied his interface. And then you can see here that we've got um rescue model to you extending this. So this is what was generated from the recipe module dot Jason. That's listed here um as a file that references this. This view. And again, we've got the annotations um uh set on on the on the class and we've got our different fields, so we've got to cook time. There's a chart sequence which, you know, basically string difficulty directions we said was a risk text elements large. Again, that's going to be another mark, another marker interface with all the different rich text elements. Um and so on. So all these fields show up was the 1-1 correspondence between fields. We specified Jason and the fields that we see in this interface, you can see here. Yeah, here we all are. Um So now when we want to do our view model a little bit, we'll be able to just, you know, fill in the blanks basically and we know exactly that we are satisfying what defined it needs. Um So onto the next thing, I think there's actually a better commit here. Yeah, so the next commit um is adding the recipe module to the modules group. I think this is a pretty small one, but this just shows that if we want recipes to count as modules, sort of module is just sort of a generic concert advice, but of something that can be placed on a larger page. Um actually show what that groups file looks like. Okay, thank you. So this is the one in the other school group directory, the models that Jason you can see here, it's a Jason array, whereas the other views of what that were objects. Um and inside it's the way we have a bunch of objects referencing different templates. So basically any template that shows up in here counts as a module. So down here, I've added recipe module into this file. So now when we build again, we'll see that the rescue module. View interface also extends um a bunch of different other fields which are basically all the fields that support modules, We'll see what it looks like now it was built it. Um So we've got recipe models you now and you can see it's got a huge list of a bunch of different fields. So columns are kind of module that supports modules inside of it and grouped into columns. So we can put recipes into any of those columns. You can put it into the above the side, below the main field which are sort of generic areas on a page. Um and taps So tags again with the models grouped into tax, we cannot put the rescue module into these contexts. It's a common mistake to forget to add it the add to the modules group or other groups as necessary. So maybe I should list out. Mhm. Show you what those, what the groups are available. Um Yeah, a bunch of different things here. It would depend on your, how your site is set up, you know, whether all of these are actually being used or whether you can make additional groups. Um it would depend on on your context, like maybe we want to have a different thing supported in the aside and so we would actually make like a module society group for instance. Um So a bunch of rich text elements, videos, modules leads, um article police articles have a specific concept of what should be a lead. And so we've got a specific group for that um and some specific things. So yeah, bottles is sort of the main group but there are lots of others. Okay. Um so next we're going to um so the front end bundle um we're not gonna cover the actual um details of this in this session because we have have a separate funding training but we're gonna apply to commit just to um add the changes to the bundle so we actually can see the front end of our as we're working um make it a little easier on us but depending on how your team functions you might have to be working on the back and before the funding is done, in which case you wouldn't have the bundle work that you would just have the your data models and your view models and the view system. So um we'll go a little bit more into detail about how you how you would work that later on. So now um data modeling, um every content type that is saved to database um needs to extend the record record is the class that data provides and it tells Darryl how to um serialize the data and put it into the database. So if you want something to be saved it needs to extend record and depending on what you're doing, you might actually extend context instead of content as a class. We had a bright spot extends record and as full text search ability, um some additional widgets and it kind of changes the ui a little bit in the in the same masks. Um pretty much. Um so basically anything that the editors should be able to find in the CMS search should probably extend content. Anything which editors should be able to create like I just want to go create the recipe. Um then recipes should extend content. Um Some things are reasons why you might extend record rather than content would be things that maybe are more for settings or more for like internal use, like maybe you've got some tasks sweating or some sort of internal processes that um you need to be able to save things, but editors wouldn't wouldn't really you know, interact with these expected and more for like automated systems. Um you would use a record for that. It is also um somewhat common where you want things to be um full text search. Um but you don't really want the editors to interact with it. So basically when you, when you add the content searchable annotation which is applied on content um content class, it allows the content to be indexed in the solar, anything that is in solar will show up in the CMS search. Um So if you want the full text search ability but you don't want the editors to see it in search, then we also have the excluded from global search and tensions so you can put that onto your record. Um and then also that's searchable and then you'll get full text search without it showing up in the city. So the editors wouldn't be able to just create these whenever they want to find them whenever they want. Their only for specific use cases. Um so some things to keep in mind when you're doing data modeling um is the editorial experience is paramount. Um you know, bright spot. We pride ourselves on being a very uh easy to use CMS, very convenient. And so anything that you uh create custom should also fit into that same mindset of like, make sure that it's easy for editors to work with your content types. So the common actions should be uh, you know, simple as possible as few steps organized the fields, um, you know, into an appropriate arrangements that they kind of flows. And the editors can easily see, you know, things that they might want to look at the same time will be close together in the CMS. Um you want to guide the editors and help them understand what they're doing. So having placeholders and notes, um, can help them understand what's going on or, you know, oh, I don't need to fill this in because it's already, you know, there's an automated um, you know, like fall back or something, you want to be able to um just how that was spelled out for the editors and then hide extraneous fields and widgets. Um so there's lots of things that show up in bright spots. Sometimes they're not really necessary for a specific use case. And so you can just hide it. And then the editors don't have to see that. It doesn't clutter up there there, the CMS for mr working. And then, you know, there's already talked about, there's like a label at the top of the content type that's also what shows up in the, in the surface. So if I go here, each of these lines here is the label. Um and then that also shows up when I click into the page that shows up on the top here. So you want that to be useful. Um So if you have it comes that has an internal name field. Um That should be a label. Um It doesn't have an internal name field. And there's there's probably going to be some kind of name or title like field. And you can make that label. You can also make the label. Um You know, custom, you can build it from various skills and whatever would be appropriate to your constant type. Um And then some of the things to keep in mind is, you know, what should be embedded versus what should be shared. We talked about this a little bit already. So um like this is a list module that's embedded. So um it's only going to live here. Whatever changes I make to this are not gonna affect anything else in the CMS. Um and I won't be able to reuse anything that I put here anywhere else, but I could also add a shared module. Um How do I do that? Yeah, that shared list. And then I can go find some other list in the CMS and I could use that in multiple places. Um So depending on what you're working on, it might make sense for it to be embedded. Might make sense for it to be shared or it might make sense to give the, enters the option for both. And that's what we see here. We've got to do an embedded list or I can do a shared list um and then think about what should be searchable. Um which as I said before means it's sort of the solar and you can use it. Um Full text search. Either the CMS search here is full text search and we also have um. Mhm. Front and side search. So your users on your site can no don't worry about that. Um So I can search for, it's a communal, I'm not in the same session as the CMS there. Um So this is doing a full text search for inspiration. You can see all the things that match that. So um any kind of content that you want your users to search for on the front end should also be full text search. And then finally if you're making a sort of a maybe a larger feature or set of features you might have a need for settings global settings, site settings. Um rice balls offers singleton's in july to have settings um sort of separately from the side of global settings. So depending on what you're working on those might all be appropriate. Um And then finally I've got some links here for just documenting all the different plantations that are available. Um We'll go into those markers as we look at the next couple of commits here. Um So let's actually look at some data modeling. So we're gonna add the basic model for a recipe. So it's going to be in here now. Okay, so this is a sort of the stubbed out class for a recipe constant type you can see here. It extends the content class which we talked about and content. The main thing that content provides is these two annotations here. So the surgical and publishable that swiss as the full text search and this is what changes or what widgets will show up and some other pieces of the ui in this comment edit form. Because we've got a bunch of different kinds of types of when in doubt you're probably going to extend content. Um So we've got recipe here, we've got a bunch of different fields. Um some of these deals and annotations. Um so let's just go through each one until we talk about real quick about what these do. So um title is a string field and it's specifically a rich text string field. So my adam is rich text annotation. It doesn't change the type in java but it changes how bright spot displays um the field and the CMS. And also changes what data is going to be stored in here. So what's actually going to be stored in this spot and this field is um sort of like an xml ish um which you know which text format. Um So you wouldn't be able to just use that raw um in an api or on the front you want to process it, whereas like plain text, you know, it's just plain text, it's ready to go wherever. Um Rich text has a couple of options on on the annotation, including toolbar and that tells the system which toolbar to use and the toolbar controls what buttons are available. So the tiny rich text toolbar provides basic formatting, like bold italic, underlying superscripts. Um and then the keyboard problems if you want to take them dia critics or special characters, there's a pop up for that. Um there's no other options, so they don't get to put any kind of, you can't put links in here, they have images in here. Um they're pretty limited and since this is the title, we don't really want them to be able to put like a bunch of stuff in here that would look bad on the front end. So we've we've locked down what they can do with that. Um We provided an internal name um depending on the content type, it might make sense to have an internal name or not. Um in this case for the recipe, you might want to have some have some specific format that they want the name, the different recipes, depending on the ingredients or whatever. And so um we've got an internal name for that, but we are going to say that if they don't type in until name will just use the title for the for the label, so they don't have to type an internal name if they don't want to. We've got a difficulty here. A difficulty is another class it's actually in um So um in bright spot venoms show up in the CMS is just a simple dropdown options. Um So we've got easy intermediate expert options for the difficulty levels and um job provided allows you to have additional data tied to um constant. So in this case we've got a code and that will allow us to do sorting later on by difficulty. Um Then we got ingredients and directions are both rich text um with different toolbars and they also have this in line false. Um So I went to texas by default is in line which means that we don't we don't expect any block level elements inside there so there wouldn't be images or like quotes or things that would that would be block level of html elements. Um And then in line also controls when the editor types in a new line whether that counts as a paragraph or whether that counts as a break tag. Um So um ingredients and directions. These are bigger fields. We want to have more data and so these are in line falls so that the editors can have more options here. We've got an image field. So this is going to reference a different type in the database. So web image is um standalone content type extends content. Um And so this will allow the editors to search for an image and and reference it from here. So um that's one of the nice things that price but provides is you don't have to do any special like um joining or anything to get reference to other content types. You just create a field with the type and that's what helps the rest. Recipe tag is another new continent. We just made that also extends content. So that would be some um you know, things straight to the database and so we can reference that as well and we actually can reference multiple. So they're having a list of wrestling tag allows the editors select multiple recipe tags and those will all be referenced from the recipe and we've got some time fields. So integers. Um managers are a little special in bright spot. They just look like um Stringfield to the editor but they are valid only allowed numeric inputs. Uh And we've also got this total time override so that if they want to just have the sum up, that could be the total time or they can override it. Um They want to make the total time next round number or whatever. Um So we've got a total override for that and we've added this display in the meditation so that um the name is shorter basically and we've got to some plain vanilla getters and setters in here and we've also added some methods to do the override total time logic. So we do use the override or we got to fall back And the fallback is just the sum of the three times. Um No, here I'm filtering out the no values so in bright spot um you should sort of expect any field generally could be normal. Um Even if we've got like in this case we've got the required annotation on this so the editors shouldn't be able to save a recipe without providing a title. Um but even in that case you should still expect title could be null the main use case for that as the editors are working and I talked about the preview earlier, so the preview is going to render this page and if I've got logic in my rendering that expects a title but they haven't typed in the title yet, then the preview is going to break. So um even though I have required here actually still expect title could be known and no check where appropriate. And so down here these aren't even required, so prep time and actually prep time cooked on. Maybe they have a type of value in there so I need to handle the whole case. Um So I don't get no pointer exception. So we're just getting to three values. Getting all the ones that aren't at all and then just summon them all together, not just the fallback. Um I don't think there's anything to go over and recipe tag, it's just a quick look, this is very similar recipe extends content. We've got only two fields here because all we really care about is the name we got indexed on that and we made it requires rich text because we like displayed on the front end and then the internal name um you know, if they want to start that they can or otherwise it should fall back to the name for living purposes. So let's build this. So I'm gonna do a full bill so that um probably use this with your that something. Um So I'm going to do a full build here so that I can actually take a look at this in the CMS. Obviously the exchange we made there was in the corps great old project. But if I want to see that in the same as I have to still build the web project. Um which is what does the war file and it's also got to build, since I just applied the theme changes. Um it's gotta build those as well. So this will take a little bit longer. Um So one thing I want to look at while that's going is the doctor. Um so the project comes with a docker compose file. It's in the project group. Um So uh this has a bunch of different services that build up bright spots. We've got tomcat, we've got Solar, we've got Apache And we've got my sequel and it's also green mail for 200 female tested locally that served as well. But the main thing to look at here is the war file. So um tomcat maps in the war file through I think it's called a bind mount. So we actually mount the root directory of the project into the doctor, continue under the code at the code directly, that's where it's mounted. So anything your project you can get to from and within the doctor. And so we've actually just mount by amount and mapping the war file that we built. And then as we change that we build that Tomcat sees that it changed and will redeploy the war file into the context. So once this builds in another minute or so we'll actually see um watching my logs here. We'll see the start spitting out messages about reloading things. Uh huh. So I started this doctor earlier today um just using these commands are documented, Read me dr compose up and then I'm actually watching the logs and this will display all logs for all the containers. So we've got five continues here. Um but I only like to hear about contract logs. So I'm just filtering out, it's not um Okay here we go. So now we're seeing that it's redeploying um the war fat. So if you're I recommend always having your logs open as you're working so you can see different areas that come up with some of the status of your partner. Oh your contact basically. Once you see this war file is finished, then that means you're going with us. No, he's still a little bit um for two bring up the system. Um so with that we should be able to see our new content types and we'll show you the sort of direct correspondence between the java class fields and CMS edit form fields. Okay, so here we've got um you must have encountered. So let's just go back to the recipe here real quick and refresh our memory. So we got title and generally and difficulty ingredients, directions, let's be tags and other times. So here we've got title, it's rich text. This is the tiny toolbar. Um so we only have just some basic formatting options and we've got the internal name. The difficulty remember, difficulty was in. Um so here's our three constants. Easy going to be an expert. And they also have the option to, I have no selection, which would be just north. Um you've got the ingredients and the directions in these arts progressively larger um rich text toolbars. So here we've got lists which would be useful for typing up ingredients and then in directions we actually get to have um images and you can put galleries and here one to the gallery of the, you know, you wanted to do the letters will be able to do that. We've got a reference to an image But you see all the images in the system to choose one and then I can also select recipe tags, creativity. Um and I just supports multiple sweat, there's money in my Youtube and then I've got the time field. So prep time and active prep cook time until um you can also see that we've got this new else legit um and the sites of watchers with us as well as the um I guess I got to save it. I say this um I think the conversation was, it wouldn't show up so that editors could have a discussion about the um and then all the recipe title quick. I think that's very just the name and the interim name. Um and we've also got to go into euros, which and whatnot. So we've got some clean up here to do now because as you can see like if I type in. Okay, Okay. Yeah, you can see here that it's using the first um field by default for the label, but we really want to use the internal name for the label is provided. And we also would like to see tag a show up here as a placeholder if I don't put in the internal name so that editors can see that, you know, they don't have to provide that if they don't need they don't want to I don't need to. Um So the next commit. Um this branch is going to improve the UI let's actually take a look at that here, so you can see because it changes, that may be um So recipe without it, there's no you or else widget interface, um see what that looks like. So there's there's an interface in bright spot called content edit widget display that allows you to um decide whether each widget should display or not. So you um when bright spot is rendering the content edit form, it will call this method for each widget and it's going to display and you get to decide display or not display it Um 99% of the time. All we're trying to do is hide. Um thank you, Charles widget. Um and so we've actually just made an interface that does that for you. So you don't have to type this out every time. So basically if the widget is being displayed is not the Euro is legit and display it. Otherwise, we hide it and you can see there's a bunch of different things that implement this. So just get that functionality for free. So by adding that we're hiding the Euro's widget but you could hide other widgets using a similar pattern contributed to. We've also broken um fields up into clusters with this cluster annotation. So we've got the time and clusters all the different time fields will show up from that and you can see I'm also added, this is third class that will actually allow the fields to line up on the same line. So by default bryce would only displays one field per per lying. Um But with that CSS class we can tell bryce about that. This field should only be one third wide. And so the next field could could display on the same line so by having all these fields next to each other and having them all be marked with his third eye will allow three of them to display on the same line. We've also added this dynamic placeholder method to a couple of fields. Um and so this um you put the name of the method here and method inside this class and then um I think it has to be directly on this classic, I don't know if it's if it's getting it from like an interface or extended class whether it will still work or not but it certainly should be working if it's a method directly on this class, it could be a private method. Um And so what bryce what we'll do is we'll call that method and if it returns a string that will display that string I used to play so that it returns, it can also return um uh part of dari provides like a an api for generating html issue actually can return um node class from that, not allow you to return um html if you wanted to have like colors or more, you know, in depth formatting, you can use html there as well. So we've got the placeholder method on these two different fields and then we've also you know filled in some of the methods we need that. So we've got the fallback logic for the internal name and we've got the label now um so the label will be here the internal name if it's not blank otherwise at least the fallback. The reason why we did the null and not blank check versus just null is it's it's possible that an editor in my next type in the space in this field. And so it's technically not null anymore but no one's going to notice it and you see the label would be messed up for no good reason. So usually whenever you're doing an old check against the string, you really do um a non blanche. So there's a stream of kills in Apache commons um has a method for doing that. And we've also got this more stringent kills class which provides more of a sort of decoration on top of that. Make it work. So in this case you can pass in a bunch of different method references into this and it will just pick the first one that is non blank. And now here in the fall back that we're actually doing this conversion to plaintext because the title is rich text but the label is plain text. And so we've got a method for doing that conversion and this is very common as well if you have fields like um you know a meta titles, meta tags or maybe external share fields that need to be plain text, you might be supplying them from a rich text value. So you need to pass that through this rich text to play a text method. The rest of the customer. We've added another year olds widget, we've added some placeholders for the label. So if we build this, this could be a faster building up. We built that theme already. Um So great old greater cash is heavily um your build artifacts. So um since we haven't made any theme changes, it should just reuse the theme as is and only have to rebuild the core and. Mhm. Web projects. So if you're not spilling the war, I'm sorry. And then I wake up Yeah, people in 45. And then once that finishes we should be able to see our updated um continent of forms. So I mentioned earlier the the outdoor experience is paramount. Was really thinking about that. Um as we're creating contact doing data modeling, um sort of the changes that we just made, I think we should always keep in the back of my these important decisions that should be like do I need to fix the label? Do I need to add some placeholders or um you can make things more from your notes. Um You might also get requirements for specifically for ordering the fields. Um and I'll show you to do that in a second um political season. And so now we've got the tag and whole name showing up as the label even though the entire name. I believe that now I've got a placeholder with the tag and that updates the label. And you can see we've got the now and then similar would be on the recipe. Ah Get that. Now we've got the timing cluster and we've got those three fields on one row and then the total time. And if I type in values here, Okay. 15 now and if I type in something that's invalid when I got to publish that actually on that field and tell me to fix that. So that's sort of right built in validation around his number of fields. Um Okay. I think that was it for cleanup. So the next commit. Um Domestically article, here's what I was talking about. The field display. This is one way you can control the field order. Um Let's just list out the fields. Um I don't know where they should be. And so then I think by default it will use the order just to declare them in the class. That gets complicated when you have super classes and modifications. Um So usually you end up needing to use the actual field display order and the values here are the internal names which may or may not be the same java field names and we'll get into more about when they wouldn't be um When we get to the modifications, the rest of the article is extending this abstract rich text article which is just some class that we already have in our, in our ecosystem here. This here's a couple different implementations and so the rest of the article, we're just adding a recipe field, that's all we're doing. Um and the reason for this is um you know, it was very common to have like a recipe blog. You need to have the recipes, but you also have like longer form content describing the process of coming up with the recipe or a story behind it. And so we want to have a content type for that, but we also want the recipes to be stand alone so you can search for them um in an api which we'll get into later with the graphic example. Um so I think that was yeah, this is pretty simple. Um so the next commit now we're going to talk about rescue module. So modules are a little bit more complicated, has actually been redone recently and by spots. So if you're on an older project, you'll see modules look a little bit different basically what we've got here is this sort of the root class in this case is an interface for all the modules. It's called module placement and that is an embedded class and that is basically what triggers um go back to the home page three billion. So Bryce flat, we'll watch you're if you make changes into the job classes, it'll actually rebuild things. So you don't have to do a full build every time. Um depending on what you're changing, you might still have to do a full build. So I usually are on the side of just doing a full build all the time, but certain changes will get picked up automatically. That's why it caused a little bit there. Um Oh yeah, we're gonna look at the homepage. Um So the homepage, uh she has a bunch of modules on it and so that's what this um news dropped on. This is actually a model policeman. And so is it? And that's how we get the embedded versus shares. The model placement is always embedded, but it may have the module itself inside it, in this case of the embedded risk module or it may just have a reference to some other external ist modules and that's how we support, both embedded and not embedded in the same field. So my replacement is sort of the root class for all your modules. And then there's also interface for shared module. So all of your shared models are going to implement this and all of your in line models and you're gonna implement module placement. Okay, so we've got a recipe module and we've actually sort of, the pattern here is if you want to have the full slate of embedded and shared modules, you need four classes basically. So you need this abstract recipe module, which is where all the actual fields would live. So we've got a recipe here, we've got an image overrides if you wanted to change the image. Um that comes from their recipe by default. And we've got to some methods in here to do the fallback logic and generate a placeholder for the editors. And then we're using the label. Um It's done delegating to the recipe at the label from that. Uh huh. So this is this is stuff you would not want to forget because um if you if I didn't have this set, all I've got here is referenced Fields, recipe and web image of both references to other objects in the database. Um So the label would just be like untitled or something by the fall. So I need to make sure I always have that risk label and there's not a text field in the class. So, the hashtag recipe module is one of the four classes. And then we're gonna have to extensions of that recipe module, which is the shared case and rest of the module placement in line, which is the inland case or embedded case. Um We're both just really simple. They should just extend that. We don't have any fields at all. Recipe module adds the internal made so that the editors can find the shared modules more easily. You know, people have to know your else widget because recipe modules don't have anywhere else and we're forcing the internal name to be first and then we'll let the whatever order the remaining fields dispute the default. So all we care about is internally entity first. Um, and then we're using the internal name as a label here instead of the default label. And then the 4th class um find it come up here. It's an amount of a recipe. There's the shared placement. So this also extends module placement and has a reference to the shared recipe module. And so by extending and implementing responsibility, this is also going to be embedded. And so this allows us to have a reference even though the field would normally be embedded, you gotta be delegating to the label of the of the shared module. Um, so that's a common pattern. You might not need to have all of that depending on whether you need to support shared and in line modules, but that's the 4000 you would need if you're doing the full sleep. Um, one other thing I wanted to mention, this is gonna, this is gonna sort of lead us into our next um mm hmm. This one here, Not from my place. Let me get to that later. Um Okay. I think this is a good time for a break. Um, So we'll take about a five minute break before we move on to few models. So I'll see you all in about 2 52 Eastern U. S. Eastern time, have the webinar set up properly. And so I missed all the questions from the first session. So let me just go through those real quick. Um I think some of them were answered by things we talked about later on and some of them were just um about the webinar itself and not the not the material. Um so a question about walking through and integrating a bride's veil as an external image repository. Um So by default, bright spot is going to use S3 if you're using um we got is hosting or um I forget what the name of it is for google but google cloud would have its own repository for images. Um and so if you want to use an additional um like maybe have another necessary repository, want to also use that's pretty easy to set up um sort of an operational configuration. If you want to have some external repository that is not AS three or google cloud or whatever other things we support out of the box would have to do some more work to uh support pulling images from maybe you have some other, I'm not sure what other things would be available but um it would be sort of a different work you don't have to do. So that's outside the scope of this training unfortunately, but you will be able to get help on that through the support portal, which I'll talk about at the very end. Um and there was a question here about what version of bright spot I'm working with right now I'm working on the latest um Released stable version which is 4.2.25 I think we can actually take a look at that real quick. Go to the CMS here and I open up and the root of the project is to build a cradle and this is what tells you how to build everything. And in here we've defined a variable of the Vice five version. That's 4 : 25. We've also got some other versions that are also fixed here Um here. So 1425 is the latest stable, which I think was released a week ago. About a week ago. Okay, so I apologize for missing this question but yeah, keep putting them in here and all now that I got from working. Oh, probably not not anymore. Okay so um yeah we talked about his links for all the different annotations that are available to you. Ah So I'm not gonna go over each one individually but there's dozens of them. So what you need to do is probably covered by. Okay, so next we're going to move on to View model. So first of all um so Bright spot uses what's called MG. DM Which stands for model View View model. It's sort of just a different design pattern from you might be conflicted more familiar with, which would be like ma how was your controller? Um We felt that M. D. D. M. Was a better fit or um the sort of web server um structure versus like a local application which NBC was more designed for. Um basically what the M. D. D. M. Gives us is a separation of, you know, logic. So we can, you know, put all of the business logic. Backend logic in the view model and then we don't have to put that in the view. So the view can be more simple or be more focused on graphical logic. So I think you can find an example that tom showed the other day. Um He does have logic in the temple but it's more about like how to break things up across you know, lines like we've got a bunch of different cards we want to display and you know they're going to display you know three per line or something. So how how do we do that and you might be able to do it with CSS thing. Right. Maybe you need to have some logic in your template to actually you know, put on the correct classes or arrangements in certain ways. So that's kind of how we separate the logic. Um So basically a view model is a value converter. Um So basically it's going to take your model and convert that into a form that is um ah usable in the view. Um And so most of the display but not this is friday this type. It's probably more the business logic rather than display logic would handle will be handled by the and you could just think of it as a function is a function that takes models in and gives that rentable views. Uh So in bright spot the model can be any class but it's usually recordable and recordable is just an interface that uh sorry, provides that is basically can consider the same as the record class. It's just an interface that um marks that. It's a view model is a class which extends the view model class provided by bright spot and the view model is generically parameter. Rised. Um So m is the model. So any any view model has a specific model that has a specific type and then within a view model, the model is never know. So you don't have to do an old check on your model because if it wasn't all the view model would have just been, you know, not even created in the first place, you would never been into the context where you would have a view model without no model in the model is final. So you would be able to set no later. Um I think it's final. Um and then finally the view to the back end is just interface. We already talked about the the interfaces um and it's bound to a specific method of rendering which like Jason and so in the initial case that would be handlebars, Jason case um you could have just like a Jason A P. I that doesn't render out. Just renders out Jason directly from the view model. And then often with graff kill, we don't even bother with the view interfaces, we just have a few models directly. Um but we'll get into that more later when we talk about the ah Graph two Lapis. Oh okay. So um we need some kind of empty point into the view system. Uh and so bright spot provides that by using page interviews. So any any page level content type. It's view model should implement the page interview as well as whatever view interface that you know goes whatever it's article page view or recipe, article view or whatever. Um, page interview is just a marker interface. It doesn't have any methods but it signifies that this is an entry point. So if someone requested you are out we should look for a page entry view for that model. Um to render out the request, we've also got the preview page view which is um specifically for use in the CMS and that sort of ties in with the rapper underscore wrapper equals false and true. Um that I talked about the rich dogan that keys into the preview page. So basically a module would not have, it would not be a patient of a continent but we still want to go to preview it as if it was a standalone content type. And so preview page view allows us to do that and I'll show you uh what that looks like right here. Yeah, so let's take a look at some code now, so we're going to apply the next commit and this is the recipe, new model, let's take a look at that. Mhm. Okay. Um We got recipe view model extends new model, recipes, this is the model, there's a recipe and they were implementing the recipe model view which we already generated with the wind started. Um So we've got here a bunch of different methods, they're all overriding methods from that recipe module view. Um And so that's how we get our I got a strongly typed relationship to whatever the front end is requiring. We we know that if we satisfy interfaces that were satisfying fronted. Um And so each year we just got a bunch of different a lot of sort of business logic for these. Um I feel so the cook time, it is going to be extremely one of just like a human readable time based on the number that the editors configured. Uh the difficulty we're going to just print a string value of that. Um the directions is rich text, remember, so we have to render that specially so there's this build. Html um utility class so we get to um It's sort of special handling here. So this this takes three Parameters. The first one is the sort of record that holds your rich text and then the next is going to be your the getter for that rich texas field. And the reason for this is that bright but needs to connect um you're rich text elements to the database and this is how it does that safely and properly. So you could you think you would be able to just pass in the string directly here except for the rich tax elements might have their own fields inside of them with their own references to other things but Davis And so we need to keep that all kind of tied together. And then the final thing is a method for how to render out additional views. So basically this is how we keep things stomach types. So we know that everything that's going to be coming out of this is going to extend this recipe model. View directions field and so we're telling the system um if you need to render any more views, here's how you do it basically. So taking this would be the rich text element, it would get past and just created do you call, which is sort of similar to this creative use called down here and that tells it to try to create a view model um with a certain for a certain view. So I'll talk about more how that works right here. So for the image um remember if we go to the the roots style guide, Jason for this? Well, you know, here this is the theme of the bundle. So this would be the the actual version that we're running on the front and this is the rich dog guy which has the type specification. So we want to look at that one. Remember here that the image was referencing another templates with another template means another view. And so how we do that in the view model. Thanks for giving is by delegating to another view model. So creative use tells the system. Here's the model, here's the view and go find a female for that and you know, render that out basically. So in this case this is just the marker for that, that field and there's any number of views that could satisfy this. So in this case we've only got image of you. What else could be other things potentially module. And so that tells the system which we model to find. Um So very like a lot of your methods in your view. Models are just going to create views. Here's the model here is the view That's like probably 50%. Um and then the rich text is also a special form of that create view. And creative uses the creative use creates an interval to plural. So we can have zero or more creative you creates a single. So then finally let's look at this just we got some business logic down here. Um So we want to format the duration, this is just some Apache utility class, just print operations in human readable text. Um And so we're just delegating all these different times to this method. So um basically, you know the new model is just, it's just a better job class. So you can do any kind of java coding normally would, so you can put private methods in here. Um you could put some fields in here if you needed to. We're going to go into that more a little bit. There actually is a field in here um and this is how you would get values off of the requests. So uh annotations, a bunch of different medications available to provide like html parameters, um http parameters rather um or cookies or various things you need access from the request. And so there's a bunch of different annotations you can use to have those populated into your view model. You can also just create fields in here um that you just want to use for like storing something for, you know, cashing, you don't have to like generate still in place. Um So again there's another example we'll get into later that shows a bit more of that. So just remember the models are just gotta classes, so you can do normal job coding in them. Um I think that just had the one game model in it, so I'm gonna go on to the next oh sorry, I didn't want to show that. Okay. Um So if you were if you needed to add dependencies um to for additional, you know, java jars access um you would do that in the core building that cradle. So here is the core project and the build dot great added. Um What was it? Oh there's 3 10. Okay, so this was added this I guess it wasn't Apache until the amount formats was from this 3 10. Um So I had to add a dependency to access that. This is how you can do that. Yeah. Okay so the next commit. So um with that, with that view model um let's go back to that, correct? But the previous command. Thanks. Um There's a question about what video record, I'm not sure what you mean by that one, but if you can elaborate point in the right direction um Let's just build, we're going to take a look at um why we need the preview every month. So that's it. So remember that recipe is stand alone class. So it lives on its own in the database. We're going to soon you have to wait for Just to finish before I got to finish one um and start to lower the top down. Hello this year. That's from. Mhm. So yeah, recipes are standalone content type in the database. Um but it's not a page level of contact because we have the recipe article instead to access them. Ah So recipes themselves don't have anywhere else, they're not standalone pages and so I need to do something special for. So right now remember if we go to like um ah you know the recipe versus an article? The article is a standalone page and if I go to one of these articles um you see I got the preview options and I can see that the recipe, even though I added the recipe view model, I don't have the, because the recipe remodel added is not do not implement patient review and it shouldn't implement because it's not a page but I still want to be able to preview rescues. So what I need to do is add the next commit which adds the previously building. Um So recipe pretty mild um implements the preview interview and then there's also this preview page view um which is generated by the wind started as well. And so this is all this water plate, basically the main thing here is this main that main is going to use our model and it's going to use the preview page, main field and this is what gets generated by the rapper. I understand that it was false. Well that triggered, this is basically a big group, here's all the group of all the different um non engaged level things. There's a huge list of things in here but one of them is going to be the recipe recipe module satisfies them. So by creating this view model, it's gonna it's not gonna be a preview entry. So it has the preview introduced. So the system will look for this when it's trying to render a preview and then um will render out the model. Is the recipes that will render out the main using the model and page mainly, which will then call into our recipe and uh so now that's built but your love this now, we should get a preview option as well. Okay, there it is there and I see we haven't really typed in much but it was just playing out, agreed, that was too almost to the unions here. Thanks for sharing. Um It's enough to it. No see my work as I go, so you know, whatever you're doing, um making sort of a non page level things. You might need to do the custom preview model. Um There is one already built in for modules, so all the sharing modules, get one for free, but since the recipe was not a shared module, because we have a separate module for it, that's why it didn't, it didn't satisfy. That's what we need to make our own previously model. But if you're just doing a regular module, um you wouldn't need to do anything special, it's only um sort of more custom work, like we just did with the recipe. So we've got our, I don't know PPG model. So now look at the recipe article of the model. I don't think there's too much to look at here. It's basically the same thing we kind of looked at already with um the recipe one thing is that it has Jason L. D. So there's some invitations to tell bryce about how to generate Jason L. D. For your content type. Um Some more of those at the bottom here, more than that. This is pretty similar to what I've got some business logic and various things. We've got great reviews calls. We've got the rich text details. Bill. Html. One thing I forgot to talk about is that building html versus building my html. So this sort of keys back into what I talked about with the rich text in line Foster. True. Um Back to the Recipe one. Remember the title was time, which text toolbar and was in line in line. And then the directions and the ingredients were in life. Also in line falls. Do you want to use build html in line? True. You would want to use building language too, you know? Okay, so that's it for the rest of the article. I think there's um Okay, so there's two pieces to this. So the first thing we did is we stick with the recipe model model real quick. So here's an example of um some more advanced few models things. Um So the model has a couple of methods but you can override should create an on crete. Um So these lights just a little bit extra logic before the view model gets actually executed. So it should create, it allows you to decide if you want to just bail entirely. So you know what? This view model doesn't make sense to generate. You don't missing some things we need or you know, you could potentially use this for like access permission, so not sure it'll be the best way to do. You potentially could use it for that. Is that this user is not authorized to see this. View models don't create it. Um So you return to our false literature be created to false to true. So you don't have to override this if you don't want to. Um And there's also on create which is kind of like you could sort of considered like a constructor a little bit. Um um but you get a view response passed in. And so this allows me to set cookies or the status code. It's also an exception. So you could throw it if there was a problem that you didn't want to generate the new models, that's another way you can sort of get like another way to replicate. What should create does is you can throw it a lot of different effects obviously because it'll sort of short circuit your entire request the most common pattern things. You need to just send a redirects, you could set a redirect status on the villa spots, then you could throw it So you wouldn't have to render anymore. View Miles, You would just say this, you know, this needs to senate redirect. Um Anyway, so we got the recipe model, the model we're using, this should create, we're setting a field on the female is just a class field um instance field and we're spending a recipe on that and then we're only going to create the rest of the email if the recipe is not at all. And so we go back to the abstract recipe, you know, module they gather required to select recipe but remember required. It could potentially still be normal for various reasons. So we should still do a null check and in this case, you know, we want to do another check in the email so that we don't try to generate a recipe module if there's no recipe. Uh and so now we've got the recipe in the field. I can again just reference it from these different methods and um I don't have to let college that recipe over time. Um we should create and the entree are guaranteed to run before any of your view interface methods run. So, you know, if you needed recipes and that like, you know, you know that it's going to be set before these run and again, this is just very similar to the recipe view model that we already looked at. It actually implements the same view, but we've got a different model. So right now the model is the model recipe model versus the other one had the model of just the recipe itself. And the main reason for this is we want to there's the override image on the module so the editors can place a different image and so we need to handle that in our view model. That's sort of the main distinction between these two. Otherwise it's just using the same stuff is a recipe one basically just pulling things off the recipe and then rendering. Um So the other thing I wanted to look at is uh shared recipe. I'm sorry, the certain policeman. Um so we've added on to this class. This model wrapper interface. And so basically the reason for this is the rest of the replacement. It's really just a wrapper around this shared module so that we can use it in an embedded context. Um so I really don't like want to have to do anything special about this class to make it render properly on the front end. But if I didn't do anything, I have to make a view model of rescue module, placement shared and have it like, you know, pull out the shared module and you didn't use render all of that kind of like what we did in the recipe module. View models, we don't have like another level of indirection there. Um So what bright spot provides is this model rapper interface, which basically what happens is every time the few system receives a model. If it implements model rapper, it will unwrap it until it no longer implements mild wrapper. And then we'll use that for the model. So what we're gonna do is we're gonna unwrap to the shared module which is a recipe module. And then the view system look at will um use that to render out the email. So what happens is I'm gonna call create views with this object. The placement shared the system will see that it's a model wrapper. It will call the unwrapped which will return the recipe module. And then we'll look for that's no longer a model rapper. And so we'll look for a few models for that. That's a little convenience. You don't have to mix so many of your models. Um So but those two classes now we've got all our recipe modules also able to render. So now um let's build that. We can actually place a recipe module on the page. See what that looks like. So I see what is this. Mhm. Yes. Mhm. Okay. So if I go to open the home things up, my spot will stare out, save your changes as you work. So if I was to make some changes here, we do this work in progress, created, gets shows up. So even if I don't publish this in my browser crashes or I lose internet. It will still save my changes. And when I come back. Well then um, how's that yellow papa. So if I don't want to. So let's add a mazel here. Um, sharing recipes two. Excuse me. Mm hmm. Now we go to the home graves, nope. Oh, that's nothing. So you're after this, this top list module. Got the rest. So, okay. I think that's it for the view system. Um, come so we're going to move on to ah Part five Indexes in the Slave Life Cycle. So we got some more requirements. Um, we want to be able to search for recipes by difficulty by the recipe tags by the times. And we want to be able to type a tag name. So like I have a recipe tag of like baking or something about a little type in bacon and see all the recipes and baking bread and having to like select the actual tag in the search. And we also want to be able to sort recipes by difficulty. Um, so let's apply the next commit and we'll see the changes. Um, so you can hear about it. Index onto a bunch of them fields. This will allow um, media query on these fields. And also they'll show up as filters in the CMS search potentially. Um, if I wanted to force them to show up, there's also an invitation for that called filter bubble. This will tell the system that it should show up as a filtering and sex search even without that, it often will show up on them just on its own. Um It's about a bunch of indexes have also added indexed onto this method here. Remember to the total time is either the some of the other times or it's the override time. And so we can't really index that on the field because the total time override may not be set if we use it to fall back. So I actually have to put the index on the method. Um And so basically you can you might think index will only work on fields but actually can go on message as well. Um And so in expenses have to be a little bit of rules you have to, they can't accept any parameters because otherwise, you know, dari wouldn't know what to pass in when it's trying to save the object to the database. Um And they must be named starting with get as there has I guess it's just a safety feature. Um So then what happens is whenever the record is saved, dari finds all the index methods and it calls them all and whatever they return is what indexes and as if it had been a regular field. So like under the hood it's really, you know, when I can say it in the database, there's no difference between whether it was an index method or the next field and then index methods will display as a read only field in the CMS edit form. So typically you're gonna want to hide it with the hidden intentions. That's what we've done here. Go down to the index method. I've had an index and if I didn't add hidden, then I would actually see the total time, twice, once for the field and once for the actual index value. Um so typically you don't want to see the index value. Um and then we've also got a couple of more index methods here. Um so it's about those over on the side. So first of all, we're gonna index the difficulty level. So we on difficulty was that email and we've got the codes of 1, 2, 3 of the level of difficulty. And so, um, having the next method, which because I'm gonna need to, I need to get some logic to pull out the, the codes off of the difficulty. So I knew I knew that in a, an index method and I've added this or double intention so that I can sort recipes by difficulty in the CMS search if you wanted to start on the front end. I think you will just get that for free. So there's there's two US durable and to you, I filter bowler specifically for the CMS search. We've also added uh index on the plain text title. Again, the title is rich text that potentially could have like um, uh, italics or various markets in there. And so we're going to index the plain text title uh as well. And the next one so we're just passing through that rich text or plain text. And finally the requirement, we wanted to be able to search for recipes by the tag name um Probably by the tag team. So we've already got we've added index on the recipe tags. We've added that this committee but this is only going to index the I. D. S. So um that's not really very useful for human because the human would know what the ideas are. So um this index method will actually pull out the tag names off with the recipe tags and then next to those. So when I searched for like baking and I had the bacon tag then it would show up, that result would show up. Um So then the basically what this is doing is de normalizing the tag name onto the record. And so with that um comes the possibility of the them getting out of sync. So if I go to the recipe tag maybe editor will go there and change baking to bakery or something. And so then all of my baby recipes are all have the wrong tagging index. You know they're not going to update automatically. Have to have to mainly do that. So the next commit shows how you would do that. Um So we go to recipe tag. Now I've added um some methods these are called lifecycle methods so there's a saved life cycle is a process that every everything that could save goes through before it gets actually put into the database. Mint. Actually, additionally after that was successfully saved. Um, so uh there's like six or seven methods here. So the first one that gets called is before safe. Um and really it should have been called on key press because basically this gets called every time the editor types in the CMS. So if I'm here typing that wasn't before safe call, that wasn't before safe call. Um so they're just, they're constantly happening. So those are four very quick things, basically something that you might need to use to like um keep things really it's not that common to need for safe. Um, but it is there there's also the invalidate which allows you to be custom validation. Um I don't think I have an example of that in this train, but you see if I can find classics already. He was doing that interesting. Mm hmm. That's a good one. Yeah. So we've got this I frame module as you put yourself in the eye frame, we want to validate the U. R. L. Make sure it's fully qualified. So I was not gonna do much good for everybody. So, um, if it's in a value or else we're going to um had an error out of the state. So that's why we need to pass in the name of the field and we're actually the actual field. So we get the field from the name of this. We know the name is the U. R. L. Because that's the name of the Jonah fields here. Well and then um we're just passing a message. Just a message must be a valid real. So if this triggers then um display like that warning red error message to the key editors so they know they need to fix the euro. Um So that's on validate and then basically you don't want to throw exception. You just add an error on the state and the militant reporting. There's also after about it which is pretty new and I don't think there's a whole lot of use cases for it yet. But basically after all young validates are done after that it was called. And regardless of whether it was a success or failure during errors at it it will still be called. So then a validation was successful before Quebec gets called and this is called right before I got saved into the database. Um We're going to show an example of what we use that for. There's also on duplicate which means if you had a unique index field. So one of the annotations on the index sanitation. So I wanted to have all of the hi it's me nick so I can actually and unique it's true onto that annotation that would mean that if I try to stay in a recipe that already has, there's already one with the same title that will have a validation here and so the on duplicate allows me to put in some logic to um rectify the area rather than just failing. Um So um allows you to to handle handle uniqueness, constraint violation. And finally if everything succeeded state of the database successfully then we also call after safe. And so now I'm gonna look at an example of um So first I got a question here, what's the benefit of index fingers is not indexing. So yeah so indexing um this already ties into this example actually. So if I got the recipe tag I want to be able to if I changed the name of the recipe tag I want to be able to find all the recipes that have the recipe tag and update them so that they have the correct updated needed. Um So As part of that I need I need to find all the recipes by recipe tags. I don't want to just save all of them. There could be thousands of recipes and maybe only 20 or with this tag. And so I need to have an index on the recipes signifying the recipe tax that I can find them all easily. So I don't have index uh an index field with that value. And I can't run a queer which is I had to just iterate over the entire database which is going to be very efficient. Um That's a big reason to have an index. Um Another reason to have an index is for boosting so on the front end search you can boost on index values um and so you might you know not one of the need to query on a specific index but if you need to be able to rank things by that. So like if so you know we want to be able to rank things higher. If the title has a has an exact match of their search query we would need to have the title index. Um so that we can do the boosting um You don't need to have the title index to just do a full text search because it's the full text let's get searched. So um it's only if you need to do a specific query against specific feel that you need to have an index. Um And the reason not to index is it's just it's going to be more data in your database and more you know more cycles to save things because you have two extra tables have to be updated and so there's you know if you can avoid indexing something um there's no reason to index something then you know you can save a little bit of efficiency there but obviously if you need to index something because you have a business rule or requirement or something that requires you to be indexed and you should go ahead and index it. Um but there is a trade off there as far as like more index it means more effort to save it basically. Okay so let's look at this recipe tag example now. So um well I want a recipe tag if the name has changed I want to find all the recipes that are tagged with the recipe tag and then update their index method values so that they have to update it. So this is gonna have to pieces. We're gonna need the before commit and we're gonna need after six remember before commit gets called right before we save the database. And so what I need to do here is get the previous version of this um Let's see if it exists and compare the names and the names are different than I want to then trigger um The recipe is to be really indexed. So the previous version I'm gonna query from query from all is basically um going to find everything in the database regardless of content type and regardless of whether it's published or it's been in draft or its archives or anything and possibly in the database it's gonna be fine. It's gonna be found through a query for us at all. So I want to query by I. D. The question mark is like a parameter substitution. So this would be this would be the record class. This will convert into like a query by U. U. I. D basically and then the most important thing here is I need this no cash because without this um bright spot heavily caches queries and results and so um if I was just a query this without no cash like this um bryce would say, hey I've already got this object right here in the cash, you're looking at it right now. Here it is. And so I would, I would get the current version, not the previous version. And so of course there would be exactly the same name even if it had been changed from the previous safe. So I need to have no cash to tell bright spots really go back to the database and get the full version and don't pull it out of the cash. So um and then Corey Kemal returns an object because it could be anything out of the database. Um there's also you can also acquire from a specific content type. I would look like this and the reason why I don't do that is because recipes that are like archives or in draft would not be found. This is really query from all the published recipes is what this really means. Um or if they're in workflow or any number of things. That one reason why they wouldn't talk there. So I want to be able to find every single one. So that's why he's acquitted from all. Well actually this is, this is interesting is the best tag. So yeah, pretty normal just because previous one could have been a draft or could be published or archived, who knows? So I just want to find the previous one no matter what status is it always this, it will always have the same idea. So I can definitely be guaranteed if it exists, I'll find it. Um Honestly this could return to all that. This is the first time we're saving this recipe tag. So I do need to still no check so I just know check bite, you know, it's not a recipe tag, there's no or any other kind of tight for some weird reason just bail, we don't want to look at it. Um So we did find one then we got the previous recipe tag and we're going to compare the names and if the names are different rather than going ahead right now and re indexing, we're going to just save the fact that we need to re index later because it's possible that the state would fail. And so if we say failed and we've already gone and re indexed everything now, we're kind of, we've kind of gotten into a bad situation because everything is out of sync. Um So we're going to attach the fact that we need to re index and then only in the after saying where we're going to act on that. So the state um provides um just like a map of, you know, parameters, values. It's called extras. And so I can just put string values um in there, it's kind of like to think of it like just the baggers you know there's like a Jason object or something. Um So I can just put a boolean value to say hey the name was modified and then later I can access that in the after save and you know act on that here so I know that by acting here. I know that the state was successful and so I can then trigger the recipes to be recalculated. And Bright Spot provides a specific our utility methods for that. Um So I can pass in a query and I can pass in the name of the of the index method I want to recalculate and then um it will handle that for me and it goes off into a separate task. So this will immediately return the editor can continue on with what they were doing. Um When editor saves all of these methods have to run before Um the editor will get the like the safe confirmation page to pop up. So if you have like 20 minutes of logic and you're after safety, editor's gonna be sitting there um you know for 20 minutes before they get the response back. So you want your after sales to be pretty quick. So if you've got a bunch of like heavy logic to do you should launch that in a separate task. Um so that it can run in some other thread and not hold up the editor. Um So yeah so basically we're gonna. Because if the name is modified we can trigger this recalculation. Let bright spot hang about. We've also got the after delete. Um So the recipe was deleted. We want to go ahead and delete re index all of their um tag names so that you know if we get rid of baking then we don't want recipes to continue to show up for baking anymore. So that we're going to also calculate on the african delete. Um So there's also the delete delete lifecycle which has the before and after. Delete before. It's actually pretty rare to use but actually you know it's pretty common. Um And it's only college until it was successful. Um I guess I mentioned state a couple of times and haven't really said what that is but state isn't provided by daria. It's basically this, it's like under the hood what a record would serialize as. Um. And so record has this murder, the state method gets state and that's just a tied to the record. It keeps everything um It's basically just a J. Sign object. So under the hood variable serialize this to Jason and put the Jason into the database. Um So you know has fields in it but also has like the extras map we talked about which allows you to sort of cash, you know like not things that are gonna be saved but just for like tracking purposes. Um. Okay so that's the complete lifecycle. There's also some more documentation which has um there's more in depth and I think it has some examples. So that might be useful for you as well. Okay, so now we're gonna get onto um modifications which is a more advanced data modeling um technique. So you know, what's even the point of modifications in the first place? So it's it's sort of a workaround because Jonah does not support multiple inheritance. Um and so you know, you sort of get multiple inheritance with interfaces but interfaces in java don't have fields so I can't have fields that are shared among multiple content types that all don't have some common Yeah, abstract base class or something it's apparent. So if we want, you know, we won't want to limit ourselves by having everything extend from a common base class. Um Typically it's considered with object oriented programming, it's more it's better to compose rather than inherent. So modifications allow a sort of a composition approach in java so basically you wanna be able to share fields and methods among multiple contacts without having to have to share a common parent. Um And so modifications allow us to share fields and methods among all classes, implementing an interface or extending some class don't get up. Um The modification is an abstract class which extends record. So it's kind of kind of looked like regular content type but it's special because it's not actually stand alone. It's um even though the defense record is never saved on its own, it's always part of some other record basically. And so it's a parameter class to t here is what will be modified and that could be an abstract class of concrete plasterboard interface. Um and everything extending or implementing that class will receive all the fields and the methods that were declared in the modification class, but it's still going to be a separate class. Like we don't we're not going to Dubai code modification here or anything like that, it's still a separate class, so I still have to get to it. Um And so we have the recordable as method which allows us to get um to the modified notification class and access the fields and values. So let's take a look at the next example. Okay, yeah, so the next example is this is a very common pattern to need an index that we want to share across multiple content types. Um but we don't necessarily want to have a single field supplier index values. Maybe um Sometimes we want the editors to select it in the field. Maybe sometimes we're gonna pull it from, you know, some other context have to pull it from some other place or it's not configurable, but we want to have it, you know, supply in some other way, but we need to have a single index so that we can query across all these common types together. So um if we index each field or index method independently on different content types and they're all separate indexes. And so I can't query across all those types together from one of them, sort it all together or show up, you know, in one common pool, I need to have a single index for that. And so we've come up with a pattern that satisfies that need and we've used it pretty frequently in the code base, so it's something you should be familiar with, There's sort of four pieces to it before classes. So in this case we're going to have recipes. So we wanna be able to have a bunch of different content types that can be associated to recipes. Um We've already got one recipe article, but maybe we're gonna have more in the future. Um Maybe we also we could add this on the recipe modules. Maybe if we needed to. Um It kind of depends on the use cases. Um So the main classes, this has recipes, so it's just gonna be an interface that has a method, supply and related value. Then we're gonna have has recipes data, which is a modification of the has recipes. Now I have the next method in it and we've got recipes with field which is going to supply, basically extend the recipes, has recipes and um supply the value from the field. And then we need to have a field place to put the field, so we need a modification for that too. So let's go take a look at what that looks like. Here's his masterpiece. So it's just it's just a method with uh start interface with a single method of get the recipes. Um but then we've also got the haze recipes data and this is a modification of has recipes. So anything that implements has recipes will also be tied into this modification will have this extra index method in this case, um couple of important things here. Um so remember the state object is just just like a Jason object, just a map. So each field is going to be key in the map and then each value of the field is going to be the maps value for that key. So it's possible that we could have with with with modifications and I have a modification that has another, maybe another modification that would also have to get recipes method that's totally different from this one. Um It's probably unlikely, but you know, other names could be more likely to be out of class. And so if we have multiple modifications and they have the same field names inside of them, then we're going to potentially, you know, we can only say one field of her name. So one of the, one of them would win out and the other one would get lost. Uh And so the way we avoid that is by adding this field internal name prefix, sanitation onto the modification class. And so what this means is that every field in this um class is not just gonna be called what you would expect like normal is what is called this field or index would be called get recipes. But with this field internal name prefix it's actually gonna be called has recipes dot get recipes. So we're going to add this prefix onto the front of each name. And so when I need to access this field like in the query I need to use the full has recipes dot recipes as the name. If I needed to put an error on this is this is a field and I wanted to put an error on it. I would have to use the internal name. Has recipes dot recipes and that's the difference why your job field name may not be the same as your dari. Like state field name or your query index field name. There's also another way to do that is with the internal name, invitation. So this allows me to I didn't have this, I could still have the internal I can do like this now would be the same attacked. So the internal name would be the prefix plus the java method name. Oh that's usually more tightening. So we typically just and you have to remember to do it in every single field. So typically that commitment to um use the field internally prefix annotations. Yeah, but they have equivalent with equivalent effects. Another thing to note here is we've got indexed on this method we've also hidden. We've also got the filter bubble. So we should be able to filter all these things in the CMS search recipes. And the final thing here is we're not just calling get recipes. So I could just do the original objects stop, that's going to return whatever this thing is up here, so that's going to return. It has recipes and I could then call the get recipes method on that. I could just do that. Um The reason why I don't do that is because depending on how you index something, it may not resolve the references and so you wouldn't actually um you just, you wouldn't, I think in this case I probably would need to do it, but it's a sort of a safety. But basically if I needed to access fields within the recipe, like maybe this is rescue names instead of recipes, I would need to access the name field on the recipe and the recipe wasn't resolved. I would just get no lag. Um so this unresolved utility just make sure that it does, it does get resolved. Um so that I needed to access fields on it. It would work. So I accepted this case is probably necessary, but it's just to be safe. Typically anytime you have an index method you probably are going to use resolve this unresolved state resolved and get and then you passed in the object that you want to get the value off of and then this is just a method reference. So um and there's been calls that method after it makes sure that the object was resolved properly. Um so that's the 1st 2. Then we've also got how's recipes must feel? So this extent has recipes and then it overrides supplies that method from that interface in your recipes and what this is doing is actually going to get call into another modification to get the recipe from the field. So, um, this method here is just a convenience here, is that as I was talking about, so basically anywhere I'm anywhere I haven't as as recipes, I can call as and then passing the modification class here and get back the modification classrooms that can access the fields inside there. Um but there's nothing preventing me from doing, you know, as anything here. I think this is just take the class, I could pass any class in here even though if it wouldn't make much sense. And so to keep things more strongly typed typically will have will supply this method as well on any kind of interface that has a modification attached to it that allows things to be a little more strongly typed um and I guess it says maybe a tiny bit of to um so we're calling that method and we're getting the recipes out of that. So finally we'll look at this um has recipes with field data. Um So this is another modification of just this time, it's that second interface. We've still got the feeling from lamed prefix and then we've got just a field inside here. So the editors will um be able to access to steal some recipes and then they will then get index through the other modification. So even though like sometimes we're going to supply them from these recipes, sometimes we're going to supply them from somewhere else. If we don't implement the has recipes with field that all goes to the same index, the next commit is actually showing how you add that to our recipe article. So remember recipe article. We only want a single recipe. This recipe we have single recipe for in the article is about a single recipe. So I don't want to use that has with field as recipes with field because that's multiple recipes. So we're actually going to implement as recipes directly. And then sorry if you can hear the sirens. Um um so we're going to supply the recipes with just a single a list of a single item, which is just a recipe. So then now with this in place, I can query for all of my recipe articles with um um you know, a single index and this and this this valuable index even though I don't have an index right here, it's index somewhere else. Right? Um So with that let's go ahead and build um I guess I didn't set up the data for this year but whenever you have an index to an existing content type You need to deal with the fact that you haven't yet populated that index. So saying we had 1500 recipe articles and we had this new recipe index with this with this code here. Um That's not going to automatically populate all the index values for the rest of the articles that already exist. I have to manually go through and do that. Um So in this case I haven't actually published any recipe articles so I won't be able to show you the results of that. I'll show you how you would do. Um Let's see um let's load here. But did I Yeah I meant it. Um Right. Mhm. Mhm. Okay. So um so provides the underscore debug area um on your local environment, you can just get to it, it's going to a it's going to be blocked behind basic off in production. You won't get to it all without getting into it special GPM. Um But it allows you to sort of see what's going on and um some status pages in here. The one thing we're gonna look at is the bulk operations. So if you were to um at a new index and you needed to populate it um you can come over here so I can choose the rest of the article and only one writer and I can start that. This is going to start a task that will re index all the recipe articles. There aren't any in this space to run really quickly, But if I had 15 hundreds or thousands of them would say this running for others would say green because of the green, I would say running and be able to sort of follow the process of that someone got here is this is only going to apply to my sequel, which is sort of the main database of truth, but we also want to re index Solar. So when you do that as we come down here to um the copy section, I can I can copy this content from sequel to solar um and that will populate solar with an updated indexes for those as well. You can also collect the lead before copy and I will clear out this kind of that before re indexing, I would usually not do that, especially in production unless you would know what you're doing. Um so we can start that as well and again it's not gonna do anything cause I don't have any data but um that will populate those um those values into solar as well. So something to remember, whenever you have an index, you've already got existing content, you need to re index that by going to this tv bulk or if you had something that was more involved, you potentially could write a script and run that script in the code windows here. Mr Salazar to execute code on your within your job Vm on your tomcat, I'm gonna go ahead and do that now. So I've got a script here I've written which will actually just generate some random recipes. This will be useful for what we're doing the draft well, so I'm going to run this now. Um especially just went to recipes, random data and saving them in the inspired confidence site, which is the main site that will be, there's one that um, it's complete enough to go to CMS and I go over here, I should be able to find a bunch of recipes now. Um Okay, so that's sort of the debug area, that's a very useful. Um especially when working locally, if you need to just fix things or create some random data or whatever, you can easily run things. There are system developer areas inside the CMS, um including the, you can see that same tasks window that we saw, you can also see that within the same s and you don't have to get into the, you know, gated off of debug, you can just get to it directly inside the CMS um another use bulk operations in here now, it's new. Yeah, so I didn't even need to go over there. I can still right here um, the same kind of thing. You picked the type and pick the source and destination database to copy and then the index, choose the type of the number of rights and whatnot. And then um you could then go to this tax space here to follow along and see the status. Um uh One thing to note about the developer area is you have to have a special permission to get into it. So on your local it's gonna show up but on QA or production you need to have um couldn't we talk about using roles but you need to have a special permission on your role to access that. See that 2nd real quick. Um So by default if you're if you're an admin user you won't have it. Actually here's my user. I don't have a role so I'm kind of an admin but um admin does not include developer access. So I would actually need to create a role, call it like developer. And then here I would need to choose all the development questions and then I would go to my user and select the role there. Now I'll be able to get it. So when your local it shows up automatically but on Q. A. You need to do that to be able to get to the area, you can read that later for the graphical stuff. So that's something you should um we'll need to set up at some point it's a working class girl. Um One other thing I wanted to mention before we move on. I think the next thing we're getting to is the basketball stuff I mentioned earlier that you might have to develop without the front end in place. Um And so you can still do that. Um even if we didn't have the template yet filled out for this recipe model. So this is just don't have a temple yet. We had the root style guide in place. Um and I wanted to make sure that my data was coming through from my model. What I can do is and this um I understand and agree with Jason parameter onto the U. R. L. And that will show that Jason that was generated from lizzie models. So in here I should be able to find search for this all the data to joint this entire paper. So the header information, there's a header here with all these values, all these images, it's all in the same Jason so I can go down here and find my rescue the model and I can do a standard check to make sure that what I'm expecting is showing up to your eyes in the form of expect like if this cook time, you know, was you know a number instead of a string, I would know something was wrong and I'm expecting a string or this didn't have the text still he was a blank string or wasn't maybe the still wasn't here at all. Um and so I would know that there was a problem on the back. There's also a very useful tool when you're trying to figure out if something is a front end problem or back end problems, you've got some, but that was reported and you're trying to figure out what's going on. This makes it really easy to say is it a front end problem? Is it a backing problem? And um, you know, if the value is in here and it's correct, then it's a friend of the problem because the back end is doing its job, the value is not in here or if it's incorrect and it's a backing problem in the front end is obviously not gonna do anything. Be able to do something correct with the incorrect dick from the back end. Um, so I understand under struggles underscore rounding illegals. Jason is a very useful, very useful tool. Um, so we got a question here about sort of how his content managed between sequel and solar. So I didn't really get into this, but I think we've got time to go over this. We're running a little bit short. So Dari provides this database interface. This is the um, what tells Dari how to say something to a specific database. And so you can see there's a bunch of different implementations, but the two main ones are my sequel database and solar dailies. And so that tells, you know, um sorry, how to say things into my sequence, how to say things in the soul and also had a query from those two and get things out of the database. Um But the default Senate we actually run is with adequate database. And what this does is um It combines a bunch of databases and makes them look like they're only a single data. And so the standard setup is to aggregate database backed by my sequel and solar. So whenever you save something you save it to aggregate database that aggregate down delegates to my sequel and Solar and make sure that it saves in both of those. And it only delegates to solar. If you've got that searchable annotation on your content type. So if you extend content or you added explicitly then it will also get saved in the solar but it always gets saved into my secret. My secret was the source of truth. Um And you can actually see that here we go back to the debug area is also a query but not this one. I don't think they've built this one yet into the CMS. So this actually allows me to run um queries basically against the database. So it's going to use the default database which is bright spots and bright spot is the aggregate database. Bright spot has two delegates sequel and solar. So I can actually specifically solar query from solar. You can see I've got way fewer items because not everything gets saved into sulfur. Whereas if I go to sequel, I should see that jump up to like a couple of 1000 or something. Um And then if I go to the bright spot in the aggregate um We've got something called it off from the database here. Um Some of this would be the same as as a sequel because the aggregate defaults to sequel and only if you forced it to go to solar, will it all query from solar instead of sequel as far as graphic as well and single and solar. It doesn't really care about the databases that sort of a lower level of abstraction than draft deals with. Um I will show you the next example though, a little bit about how you would query from solar directly for you to do. So let's move on to the graph if you will. Um So api graphical is in a pr um So by setting up a graph. QL endpoint you just kind of taking on additional responsibility of maintaining an A. P. I. Versus. If you just had handlebars that's all kind of internal and you've got the right style got to keep everything um You know, instinct and make sure everyone agrees on things. Whereas if you have an A. P. I got external consumers, they might even be different departments or different companies. So you really need to kind of up your game. Um When you're working with an api um So the roots dog item of views and the view models that are based on it are designed for use with handlebars and they aren't really meant for public consumption. Um with this higher level, higher standard of of maintain maintenance and robustness that make that would require. So you probably shouldn't use them with graphical better news case it may make sense to. Um and so oftentimes the format we need an external API is different from what you need in handlebars and so we typically recommend you to write custom view models specifically for graphic grill or for whatever api you're working with. You can also just sound like a chase on a P. I. And not use grass QL um Yeah, so for a view model for graph QL it's almost the same as a few miles from handlebars. The main difference is you're not going to be using the auto generated view interface and you typically don't even have a few interface at all. Um you will need to view interface that you need to have like a graphical interface or union in your graph QL schema. Um and then you need an interface on the job and the bright spots side and java to make that work but it's not required in principle like it kind of is for handlebars. Um so basically what happens is you're gonna have a view model. All the public no parameter methods would get exposed as fields in the graphical api and we need that the interface meditation that I talked about earlier on your view model class to tell the view system to do that. Otherwise we will we will have no fields at all. Um and if you if you have any Jason api you need to have the Jason view annotation, which is kind of like the handlebars template annotation, but it tells the system to use J sign instead of handlebars, the graphical you don't need that graphical just works with the with the interface only. And um from the violence was to take a look at the code. So okay, so what we've done here is we've created an endpoint for recipes and graphic well um so graphical provides this content delivery api endpoint class, abstract class. Um and just use this when you want to have um your content exposed in the Api was like, you know, view models. And you have, you can curate kind of the data that gets present. There's also something called content management aPI And that allows the raw model data to be exposed. And so you would use that if you were trying to like do an ingestion. Um we had an external service that wanted to get the raw data out maybe like for monitoring or analytics or something. Um you could use the management and you would not use the management, A P I for like an external like front end consumer because it exposes things that are much too low level. You would want to use content delivery guy for that. So that's what we're doing here. Um Singleton. Singleton, I think I mentioned singleton earlier. Singleton basically just means that a single instance of this class will be saved to the database automatically and it won't be able to save anymore. So whenever like bright spot starts up it will make sure all the single terms exist and then you won't be able to save anymore. So you know, there's gonna be a single instance of this in the entire, like in the database basically, um we need to tell the path of this endpoint will live at and um we also need to tell you what um like view models, basically this, this api is going to use and that's sort of what this next time is about is with the entry points. So graphical doesn't use the page entry view that handlebars does. Um so instead you would explicitly specify the view models or the views that you need to want to act as entry points. So you could potentially make a graphic dwell entry view marker interface will be very similar to this. Um and you have a bunch of different models that implement that. You actually could just go ahead and use page interview. Like I could just pass pay attention to you right here and then I would get all the handlebars, view models showing up. So you would only want to use that if you were going to use the handlebars and it made sense or if you did not have any handlebars at all, you're entirely a headless project, in which case you could just reuse page entry view for as gradual entry view. Um so basically like I passed in a bunch of this, probably return a list of entry point field so each entry point field has a marker, inter interface or view model class or whatever I'm going to use to say, here's the thing that's going to be, you know, the view model that's going to be exposed or the view that's gonna be exposed. And then I can also potentially put in a name if I want to change that by default it will use this would be the name, recipe, graphical endpoint would be the name of the field. The name of the type rather in the graphical schema. I don't like that. I can pass a different name in here and then I think it's the final field here and see what that is of Botox. I guess you can have a document comment that will show up in the in the schema. We should have supplied that Actually no, I think of it. This probably should have had some kind of explanation of what a recipe would be anyway. Um So with this built should have this building um that will still show up ah In the developer section. Under the settings section under 80 I someone stepped bills um we'll be able to see our configuration page in the CMS kind of like the sights and settings where I can uh configure additional things about that endpoint. Here's 11 thing to know a lot of the activity in the CMS gets logged. So that tasked script that I landed you debug code actually got logged out in the tomcat, so it's there for auditing purposes. So anything you do is being monitored um There's three purposes you also see log like out. If you can find examples, you'll see like editorial activity that's logged here as well. So if someone saves something that shows up in here doing something um logged out into the VR Catalina log tomcat log. Um So if I go down to the admin area, this is a P. I. Section and here I've got my recipe endpoint and already have been created because it's a single term, so I didn't have to like save it manually. Just got created overnight and because I don't have any fields to compete here um choice, but we're going to add some more fields here a little bit, we will stop them. Um So that's the only thing I will also need to remodel. Um So there's sort of two patterns that you would use here. Um Actually, yeah, so the this is telling the entry point is telling that use this view model as the entry point. So, you know here that the view of the model of this view model is actually the end point itself. And this is sort of a special case and um in bright spots graphical implementation. So by having them the model b the endpoint itself and the endpoint via singleton. That means that ah this will show up um in the api kind of has his own little thing as opposed to having to find an article by ID or something. I could just get directly to this. Um And the reason for that is I wanna be able to filter the results. So if you go to the graphics well area now. So under developer there's the graphical Explorer, this is what you need the developer permissions to get to the FBI is one is a separate collection. Um So um you can see this is called recipes. That was the name I specified. And then I get all the different uh search for answers. So I can filter by difficulty. I can get to the second page, third page of results. I can type in some terms to the query on person tags. And so by these are all correspond to these web parameter fields. This is again, a few miles. This is this is how you get like http parameters and the handlebars view model and graphical let's get you the parameters off of the graphical career. So let's just let's just grab a couple. So these are just my random recipes that I've created. Um But actually I can search a search term here now I should only get that one. Probably. So um so that's kind of how that all fits together. Let's take a look at the actual logic of this view model. Oh so going back to the pattern thing. So the view is kind of a special case of the model being the end point itself. This could also just be like recipe directly or something. In which case I would have to query for a recipe by I. D. Or my path to get something out here. I wouldn't be able to get these extra filters. I would just have I. D. And path here. So that's kind of to use cases if you need to expose just like specific records in the A. P. I. And people are going to find them from some other source. Um Then you would use just like the standard model up here if you want to have like a filter like a full on api like filtering and sorting and whatnot. Um Then you would need to have an endpoint B. The model and you have a bunch of parameters here and then your values would actually be and the items skills. So here we can see we're using the rest of the A. P. I. V. Model um as the actual value. So that's what this this type here. The recipes like these items here was in that field. Um So look at that except so we've got a bunch of different parameters so we can filter on here. I'm using the on create and the reason for that is I want to be able to set up the paginated result um once so I need to access it and both get items and the exchange. Okay. And so if I just like built all this logic into get items that have to do all the same thing here and I eventually run the same query twice and that would be inefficient. So here in the entree I'm going to do some setup work and I know this is going to run before any of my methods down here run. So I know that this paginated result will be set up properly before these guys can call it. Um So we're just doing some logic to calculate the offset limit based on the page and paige is a parameter which is optional. So we're going to supply a default value if it's not set 40. Um and then here is the build a query and then I'm going to select, Starting at the offset limit number of items limits. 20 limit. We didn't expose the limit of the guys. So it's always 2020. We couldn't expose that. Let them slept, You know 50 at a time or something instead. Um So here's the career. Um very queer is a little bit with the modification example and the the after saying before both before committee examples. Um So here we're gonna query from recipe, We only want recipes. Um, this is how you force something into solar. New matches. Matches is the full text search operator. So it's gonna have to go to solar. The database will try against solar against Sequels, Sequels say, hey, I don't know what matches is and then we'll try it against solar, that's kind of how those work. So queries will always go to my sequel. If they fail there, then they'll try to go to the sword. Um, so the matches will succeed in solar. So here I'm just saying where anything matches anything, that's just this sort of idiomatic way of forcing someone to go the solar and I'm doing that for performance reasons because this query is complex. It's got a lot of different joins on it. Those are going to perform better and solar and I also want for consistency. So like if I don't, if the, if the user doesn't type in, um, a parameter is going to go to a matches query, then without this, it would go to my sequel and so the query times would be different and potentially could open this up to, you know, um, attacks where people can notice that the timing is different based on parameters and they could potentially sort of exposes an internal detail. We wouldn't want to expose. So we're gonna always gonna go to solar. Um, and then we're also going to filter by site. Um So the site will be set based on the graphic. Well Um we'll set up a site were determined the site for us and put that here and then we're gonna filter on the site. Um so all the results will be returned or items that are accessible to that site. 10 sites only content only recipes in the one site we're in would be returned to me. That's an important thing. You probably need to add on any kind of career that's user facing. So anything direct driving site search or a P. I. S. You want to make sure you filtered by site items predicate And here we just go through each parameter. And if it was passed in for the from the graphical query, then we added on to our dark. So if we have a title we're gonna match the title, text field, plain text field on the title. And this is why we had that plain text the next method, that's what this is going because we wouldn't want them to have to type in the markup. That was that was happening having italicized title. Um So we have an index method for that. Um and then we've got the difficulties passed in. We can pass the difficulty the tags, we're gonna do matches on the tags names so that this is the full text search match. So it will handle like slight standing and whatnot. So the names were quite the same as what was typed into the api would still find matches. And then the search terms again. Um Are you done with that? We're actually doing phrases for that. This is a more advanced career thing. So because there were multiple. Like this is the search terms had spaces. You know this would make to make sure that you can carry on phrases and don't break those into separate tokens in the career. Um So this builds our query. We've got our query, we selected our results and now each result we're gonna render out as a recipe And the FBI. So here's our recipe graph 12 you model. And again this is not the same as the recipe view model. We've looked at this is a handlebars V. Model. Oh so this is tied to the recipe model view which is tied to handlebars through these plantations here. Instead we don't have the interface at all. We just have a view interface annotation and we specified the name of that interface. This is always show up in the graphical schemas recipe rather than otherwise it would be recipe I think we didn't have this, we just left this blank. We had this that would be recipe FBI in the mosquito. Um We're still extending the model though, just like the ottoman did and we still have a recipe as our model. So that that hasn't changed. And then we just have a bunch of public methods in here. And these all have um will explode, be exposed as fields in the A. C. I. So cook time difficulty directions. Um And then the one special one is the image image attributes tells the system that this is going to generate sort of, it's a map at this level but it's gonna be a specific map. It's gonna have the um crop information and source debts and whatnot um that are presented with images and it also allows um the editor or nothing considerably guided to pick on specific size that they want. So this is all the different image data. Um We're doing a little different here, so rich text. Again, it needs to be processed before you expose it on the front end but rather than using the rich text details like I did in the handlebars, the model, we're actually rendering out slightly differently. Um ah for use with graph QL and coming soon, I'm not sure exactly when it's completed. It's sort of, it's going to be a new way of rendering out rich text in graph QL. Um So this is sort of like a placeholder for that more improved way that's coming probably in the next major bright spot release. Um So and you still use create views like we did in handlebars but here I'm actually just passing the view model directly rather than passing interface. So this just says, you know, it's going to find the view model instead of a son of a view interface and it'll just render it directly. It's supposed to have him find the view model given a few interfaces that this will be a little bit faster. I guess actually, maybe if we don't we don't have a need for interface here so we can just use a few miles. Right, the note here that we're returning imagers for the times, whereas in handlebars we were returning strains of like a human readable text and that sort of one example of the difference between handlebars and graph QL R A P I do you um is we might have a more raw form for certain data types because yeah, the consumers can have their own logic. If they were to react after something, they can have their own way of rendering out times. Um, so you typically on a graph QL api you're going to have things in a little bit more raw form than you would otherwise. Obviously it will depend on your on your engine. Um so I think that's it for the graph QL pieces and I've got to move quickly because we're pretty much at a time. So one other thing I wanted to show was more advanced filtering in graph QL So when we have these times we cook time and total time and whatnot. And it'd be nice to filter on them with a range rather than having to say finding other things that are exactly 10 minutes. You know, I'd like to find the things that are 10 minutes to 30 minutes. All the things that I don't take too long. Um the graphical does support that. It's a little bit more advanced. Um So if I go back to the ground speed endpoint, wow. So we added this range graphics program. This is a custom annotation that we just made and these are now parameters. These are range parameter is the value instead of like extremely. So these are both new classes. Um it's arranged graphical parameter. It's annotation, just like the web parameter or there's other annotations um and you have to run a processor for it and the processor gives us sort of the raw value off of the graph graphical career. And let's just process that into a job class which is going to be this range. So the input is going to be a map. Let's get this building actually. Well, talking season, see what this looks like. The graft will query will expose a map. You have like a min and max values. You can specify either one or both and then we can pull them out of that map Using this. Um These utility methods here, this pulls this pulls the value out of the map and this converts it to the major so I can get managers off those and then I returned the french Bradley. And then here I'm still telling graph QL how to expose this in the schema for the graft. Well, query. So I'm saying there's a new object here. It's called range and it's got many mats and steals their images. So that's a really good time. And then finally the range frame is just a plain java objects which just didn't min and max in there. And I've added a method in here to update the query. So that because again, this is a lot that's gonna get repeated multiple times. So it's a lot winters we go back here we can see we've got the range parameter. So this annotation will tell the system to fill in these fields from the graphic will query based on the logic we just looked at. And then down here I can check if they were passed. If it's not at all, then I can update the query and passing in the query and the fields of query on. And then this that adds um greater than or less than operators. So this is a numeric field. So we can use range operator for comparison. That's good buying things in that. So I figure if you now mhm. So now I've got additional now you see the total time and actually got done done. That can put ranges on this. So I want to find all the things that are really quick. Yes. All right. So he was like eight minutes and well, I can find all the things that are really long. Yes. Where I can find women's with. Thank you. Um So that's an example of the more advanced filter. We've actually been on your own. Um wouldn't necessarily be numeric parameter range if you had any kind of thing that didn't fit into the fault types you can use the same wow for other more advanced query options come on. So then the final um soon uh grad school is an api so um we've got additional concerns around it like authorization course and also backwards compatibility. If you make changes, you know you don't want to break your FBI so things you need to keep in mind as you're working and then also this sort of keys back into that two approaches. I talked about where you could have the parameters of your model of your view model be either the endpoint itself, you need to have kind of lost searching or filtering content or you can have the parameter. The model will be just a regular content type in which case they would have to find things with ideal path only rather than any custom parameters. Um So this last commit is just showing how you would add. Um Yeah thank you. Go away. Um I would add more more settings onto your endpoints. So we were adding acts with options so you know whether you need to have a specific client um and credentials to access the api whether it's public and then also in the course how you configure course. Um and then also we've added this theme, a bowl. So this will allow us to um select a specific theme on the A. P. I. Um and that will mean the main purpose of that would be for image sizes. We looked at how in here you can on the image you could pass in a specific size that you wanted um So that the size is gonna be configured, the sizes available, it's going to be configured in this team three Bundle I guess you can call it now. Um So if we go here look up, so this is the image sizes for that, the bundle that week, we only have one bundle in this project. So this is all the images available, potentially you could have a separate bundle photograph Well if you want to have a specific set of images that were available to the FBI. Um So I can pass in small for instance, now we can see that the image values is with in the height, Uh huh. The small size of 157 as opposed to it, you know? So I can also pass into the, you can pass in multiple sizes too um multiple, so that's all kind of provided for you and that is all completed. So on the graphical endpoint itself um Now I've got the option to the theme, The one Gotcha here is the team has to be the same as the cycling. So your graphical endpoint is global, effectively you exposed to multiple sites but each side will have to have this theme uh sat on it, put it to work. Um We've also got the course configuration here, so I can certainly allowed domains here competitors and then I can also set up, you know, maybe you have to have an api key to access the guy that was said. I would need to then create a client over here and choose that endpoints will allow and by the conference site you have to generate a key um in this way that I'm able to use this client ecstasy of God, if I didn't have this access said is none or anyone, I can still for auditing purposes attribute, you know, it's a film can access is api without the client then, you know, here's the, we'll pretend that came with this client that will give them permission to um so that's kind of additional values. You can also add additional fields onto this. Again, the graphical bullet point is just, it's just a record class at some point in the hierarchy. This is going to extend records so you can put additional fields in here. Um I think that's pretty much everything, you know, we moved really quick um so feel free to go back through and, and we watch things um and then we've got a bunch of resources for you available, we have the training repo which has all the code we looked at has the docker with all the data that we've looked at. Um the exercises we went through on the exercise recipe branch. You can just go through commit by commit to follow along what we did in this presentation And then we're gonna make the slides and recording available soon. I think that will be emailed to you but I'm not 100% sure how that gets distributed. Um And then um the vice squad documentation website loads of stuff there um including graph QL so anything you have about that, you should be able to find reference on that. Um And then also the doctor we have to read me for if you have more advanced like settings you need to set up on their um that's documented there. And then finally we have a support portal available to um you didn't ask questions um Get advice so please contact your your product manager if you want to access that now if you have questions about this training that would be a good place to um to ask them. We can we can get them answer for you so I know we're past the time but I don't know if anyone has any final questions. I don't think I see anything come has come in. Um Yeah if you have any quick questions, feel free to ask them now um And if there aren't any, you know if you stick up questions later you can you can ask them to the support portal and just wait a minute and see if anyone has taken. Yeah, I guess if not the best of luck developing with Rice back and again, feel free to reach out and support portal. If you need assistance, thank you all.