Warning: This page has not been updated in over over a year and may be outdated or deprecated.
videos:code_generators_2
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
videos:code_generators_2 [2020/10/13 10:57] – [Video 12: Code Generators, Part 2: Creating a Controller] demiankatz | videos:code_generators_2 [2021/10/22 14:44] (current) – [Video 12: Code Generators, Part 2: Creating a Controller] demiankatz | ||
---|---|---|---|
Line 1: | Line 1: | ||
====== Video 12: Code Generators, Part 2: Creating a Controller ====== | ====== Video 12: Code Generators, Part 2: Creating a Controller ====== | ||
- | The twelfth | + | The twelfth |
Video is available as an [[https:// | Video is available as an [[https:// | ||
Line 14: | Line 14: | ||
// This is a raw machine-generated transcript; it will be cleaned up as time permits. // | // This is a raw machine-generated transcript; it will be cleaned up as time permits. // | ||
- | :!: Coming soon. | + | |
+ | generators | ||
+ | this month we are going to talk about | ||
+ | customizing routes | ||
+ | and controllers in order to add new | ||
+ | functionality to viewfind | ||
+ | a viewfinder is built using the model | ||
+ | view controller model | ||
+ | which essentially means that the | ||
+ | software is | ||
+ | divided into a few distinct portions | ||
+ | which allows for separation of concerns | ||
+ | and can make it easier to customize | ||
+ | so there are the views which are for | ||
+ | displaying data that's our theme system | ||
+ | there are the controllers which are | ||
+ | the the pieces of code that contain the | ||
+ | business logic of viewfind that actually | ||
+ | make things | ||
+ | happen and then there are the models uh | ||
+ | which represent the data within the | ||
+ | system | ||
+ | and there are of course some sort of | ||
+ | services that help bring all of this | ||
+ | together | ||
+ | but the the important point is | ||
+ | the controllers are make think the | ||
+ | controllers are what make things happen | ||
+ | the views are what display things to the | ||
+ | user | ||
+ | uh and today we're going to make some | ||
+ | new things happen | ||
+ | and display some new things to users and | ||
+ | we're going to use | ||
+ | code generators to make the job easier | ||
+ | another concept that's important for | ||
+ | understanding all of this | ||
+ | is uh the router | ||
+ | so viewfind uses laminas' | ||
+ | for mapping urls to controllers | ||
+ | so whenever you access a url under | ||
+ | viewfind' | ||
+ | the router picks apart the pieces of | ||
+ | that url and uses them to decide which | ||
+ | controller code to run | ||
+ | and that's really how everything happens | ||
+ | in viewfind | ||
+ | routes are defined through configuration | ||
+ | uh which can be put | ||
+ | anywhere in the the frameworks | ||
+ | configuration stack but currently | ||
+ | most of you finds routes are found | ||
+ | inside the viewfind | ||
+ | code module and i'm just going to show | ||
+ | you | ||
+ | in the code under module viewfind config | ||
+ | and module.config.php at the very top of | ||
+ | the configuration there' | ||
+ | routes section and this contains | ||
+ | a number of predefined routes | ||
+ | you can override these or add to them in | ||
+ | your own local module if you need to | ||
+ | and we'll get to that a little later but | ||
+ | i just wanted to show you as a useful | ||
+ | example | ||
+ | the default route which is what | ||
+ | viewfind will use to match urls if it | ||
+ | finds no | ||
+ | more specific route later in the | ||
+ | configuration | ||
+ | this is using a segment routing method | ||
+ | which is what allows us to define the | ||
+ | route with these little named | ||
+ | placeholders | ||
+ | brackets indicate optional portions | ||
+ | so what this is saying is that if you | ||
+ | have a url that starts with a slash | ||
+ | and then optionally has some more text | ||
+ | and maybe | ||
+ | optionally has another slash and some | ||
+ | even more text | ||
+ | that first chunk of text between slashes | ||
+ | is going to be used as a controller | ||
+ | variable | ||
+ | and that second part is going to be used | ||
+ | as an action | ||
+ | we have some constraints on these | ||
+ | parameters so the route will only match | ||
+ | if we have alphanumeric or underscores | ||
+ | or dashes | ||
+ | in the in the values | ||
+ | and we also have some defaults so if one | ||
+ | of these sections | ||
+ | is omitted uh it'll use a default | ||
+ | instead | ||
+ | so what this is showing us is that when | ||
+ | you go to view finds | ||
+ | base url you go to the home action of | ||
+ | the index controller | ||
+ | but if you put names into the url | ||
+ | you override these defaults and you | ||
+ | affect | ||
+ | which controller and which action get | ||
+ | executed | ||
+ | so for today i'm going to create a new | ||
+ | controller called tutorial and put some | ||
+ | functionality into that | ||
+ | so based on this route you can see that | ||
+ | if i were to | ||
+ | just add slash tutorial to a viewfinder | ||
+ | url what's going to happen | ||
+ | is action is going to default to home | ||
+ | because i omitted it | ||
+ | and controller is going to get | ||
+ | overridden with tutorial | ||
+ | so let's just try that and see what | ||
+ | happens | ||
+ | not surprisingly i get an error message | ||
+ | telling me | ||
+ | controller is not found this is to be | ||
+ | expected | ||
+ | because we don't have a tutorial | ||
+ | controller yet | ||
+ | uh i should also note that i'm seeing | ||
+ | this detailed error message | ||
+ | uh because i've turned on development | ||
+ | mode in viewfind | ||
+ | if i had not turned on development mode | ||
+ | i would see | ||
+ | a generic message that would be far less | ||
+ | informative | ||
+ | it's always a good idea to have | ||
+ | development mode on while you' | ||
+ | developing | ||
+ | because it helps with troubleshooting | ||
+ | like this | ||
+ | that all being said let's go ahead and | ||
+ | make ourselves | ||
+ | a tutorial controller so that we can | ||
+ | start attaching some behavior | ||
+ | to this url | ||
+ | i'm going to assume that you already | ||
+ | have a local module called tutorial | ||
+ | and that you're somewhat familiar with | ||
+ | the plug-in code generator | ||
+ | because we talked about both of those | ||
+ | things last month | ||
+ | so i'm going to go to my viewfinder home | ||
+ | directory | ||
+ | and i am going to run the plugin | ||
+ | generator to build myself | ||
+ | a new controller inside my tutorial | ||
+ | module | ||
+ | so i do this by saying php public | ||
+ | index.php | ||
+ | generate plugin and i'm going to call | ||
+ | my controller tutorial backslash | ||
+ | backslash | ||
+ | controller backslash backslash tutorial | ||
+ | controller so the first part of the | ||
+ | namespace | ||
+ | will tell the plugin generator to | ||
+ | generate code in the tutorial module | ||
+ | the fact that the second part says | ||
+ | controller will tell it that we' | ||
+ | building a controller and then it will | ||
+ | create | ||
+ | a tutorial controller class | ||
+ | uh one important feature of the plug-in | ||
+ | generator that i'm going to take | ||
+ | advantage of here | ||
+ | is that the last parameter you can | ||
+ | specify | ||
+ | is the name of an existing factory for | ||
+ | building | ||
+ | your new class if i were to omit this | ||
+ | parameter it would just create a new | ||
+ | empty factory that i could fill in but | ||
+ | because | ||
+ | all of viewfind' | ||
+ | abstract base class that provides some | ||
+ | helpful functionality and requires | ||
+ | some specific constructor parameters i'm | ||
+ | going to use | ||
+ | viewfinder' | ||
+ | factory which is named | ||
+ | viewfind backslash backslash controller | ||
+ | backslash backslash abstract base | ||
+ | factory | ||
+ | so this will tell the generator | ||
+ | to reuse that existing factory to build | ||
+ | my new class | ||
+ | instead of building a new empty factory | ||
+ | that i would have to fill in | ||
+ | and also a reminder that i have to | ||
+ | double up all of these backslashes | ||
+ | because of the quirks of the command | ||
+ | line | ||
+ | but what i'm actually generating are | ||
+ | class names with single backslashes in | ||
+ | them as one would expect | ||
+ | so there we go i have just created | ||
+ | a tutorial controller and configured it | ||
+ | in my local module | ||
+ | so now if i go back over here and i | ||
+ | refresh this page | ||
+ | i have a new error message it now says | ||
+ | error controller cannot dispatch | ||
+ | this is because i created a controller | ||
+ | and viewfind was able to find it | ||
+ | but i haven' | ||
+ | that the route is | ||
+ | trying to execute so my next | ||
+ | task is to define a home action | ||
+ | so i'm going to go over to my editor | ||
+ | and go into my tutorial module where i | ||
+ | will see that | ||
+ | the code generator has created this | ||
+ | controller | ||
+ | folder under my source code and built an | ||
+ | empty tutorial controller | ||
+ | so in lobinos mvc the framework that | ||
+ | we're using | ||
+ | controllers are organized as a class | ||
+ | containing methods | ||
+ | whose names end with action so | ||
+ | because we want to route to a home | ||
+ | action i need to create a public | ||
+ | function called home action | ||
+ | and put something into it uh | ||
+ | as i mentioned we're using a model view | ||
+ | controller system | ||
+ | where the views are separated from the | ||
+ | controllers | ||
+ | and the way that these two pieces of the | ||
+ | system communicate with each other | ||
+ | is that every action returns what' | ||
+ | called a view model | ||
+ | which is just a container full of values | ||
+ | that the view will have | ||
+ | access to uh to get started with | ||
+ | we don't need to send any values at all | ||
+ | we're just going to | ||
+ | go with the default template render to | ||
+ | begin | ||
+ | so we can return an empty view model | ||
+ | with no special data | ||
+ | and as i mentioned viewfinder | ||
+ | controllers generally | ||
+ | extend this abstract base class which | ||
+ | includes | ||
+ | a helper function called create | ||
+ | view model which will give you an empty | ||
+ | view model | ||
+ | automatically with some useful values | ||
+ | pre-populated | ||
+ | so i'm just going to start out here with | ||
+ | this simple | ||
+ | uh public function home action that | ||
+ | simply returns | ||
+ | this create view model with no | ||
+ | parameters | ||
+ | so i've now defined an action that | ||
+ | returns the right kind of value so let' | ||
+ | refresh this page and see what our next | ||
+ | error message is | ||
+ | all right we've got a new error message | ||
+ | we were now able to | ||
+ | find a controller and dispatch an action | ||
+ | but now uh the framework is trying to | ||
+ | render the template associated with our | ||
+ | action | ||
+ | which by naming convention is going to | ||
+ | be tutorial for the controller slash | ||
+ | home for the action but we've created no | ||
+ | such template yet | ||
+ | so viewfind couldn' | ||
+ | created | ||
+ | yet another error so let's go | ||
+ | build a template in our theme so that we | ||
+ | can | ||
+ | resolve this latest problem | ||
+ | so if i go to my tutorial theme and my | ||
+ | templates directory | ||
+ | i just need to create a folder in here | ||
+ | called tutorial to match my controller | ||
+ | and then i want to create a file in here | ||
+ | called home.phtml | ||
+ | to match the name of my action and the | ||
+ | phtml extension just represents | ||
+ | a php html template and for now all i'm | ||
+ | going to put in here | ||
+ | is hello world | ||
+ | so now all of my pieces are in place | ||
+ | i have uh created a controller | ||
+ | and a route and a template so if i | ||
+ | refresh the page | ||
+ | hello world i have a message displayed | ||
+ | so this is how you create a new action | ||
+ | but you know displaying a piece of text | ||
+ | is not that exciting | ||
+ | why don't we look into how we can | ||
+ | actually interact with this a little bit | ||
+ | so suppose rather than saying hello | ||
+ | world i wanted to be able to specify my | ||
+ | name | ||
+ | uh as a parameter on the command line so | ||
+ | i could add question mark name equals | ||
+ | damien | ||
+ | and then i would like this to say hello | ||
+ | damien | ||
+ | instead of hello world the framework | ||
+ | makes this quite easy to achieve | ||
+ | first i need to go up to | ||
+ | my tutorial controller and add | ||
+ | some some logic | ||
+ | so every controller in the framework has | ||
+ | access to a helper called params which | ||
+ | you can access | ||
+ | uh by calling this | ||
+ | params with parentheses | ||
+ | and the params helper has various | ||
+ | methods on it you can use for | ||
+ | extracting values from the incoming | ||
+ | request | ||
+ | there is a from query method where you | ||
+ | can specify the name | ||
+ | of a parameter and also a default value | ||
+ | so if i say | ||
+ | name equals this params from query | ||
+ | name comma world that means it will set | ||
+ | the | ||
+ | name variable equal to the value of the | ||
+ | name | ||
+ | parameter in the query and if that is | ||
+ | undefined | ||
+ | it'll just use world instead | ||
+ | so i also mentioned of course that view | ||
+ | models are used for passing | ||
+ | values to the view and this create | ||
+ | view model helper function that you have | ||
+ | access to | ||
+ | in viewfinds controllers lets you | ||
+ | specify | ||
+ | an array of values to pass so i'm just | ||
+ | going to create an array | ||
+ | that includes this name value i've just | ||
+ | pulled out of the request | ||
+ | and passes it through as name | ||
+ | having done this uh i will now have | ||
+ | access to a name variable in my template | ||
+ | so i can replace the word world here | ||
+ | with a php echo tag | ||
+ | that displays this escape html | ||
+ | name note that it's always important to | ||
+ | remember | ||
+ | to html escape values that you display | ||
+ | to | ||
+ | prevent injection attacks | ||
+ | or simply garbled displays | ||
+ | so now just by pulling a value from the | ||
+ | query in the controller | ||
+ | passing it to the view displaying it in | ||
+ | the view | ||
+ | i have some interaction in place | ||
+ | and sure enough when i refresh the page | ||
+ | it says hello damian | ||
+ | and if i take my get parameter back off | ||
+ | again | ||
+ | the default kicks in and i still get | ||
+ | hello world | ||
+ | since we've made some nice progress here | ||
+ | i'm just going to take a moment and | ||
+ | do a git commit | ||
+ | to save all of this | ||
+ | progress and so that when i do some | ||
+ | subsequent | ||
+ | work i can more easily show you | ||
+ | what has changed | ||
+ | since this initial baseline was set | ||
+ | so it's nice to be able to specify get | ||
+ | parameters but suppose you want to | ||
+ | actually | ||
+ | seamlessly integrate a value into | ||
+ | the url itself so say for example | ||
+ | we want to be able to go to tutorial | ||
+ | slash home | ||
+ | slash custom location and | ||
+ | have the display tell us that we have | ||
+ | entered custom location | ||
+ | if i do this right now i get | ||
+ | a no route match instance provided | ||
+ | because i've created this three part | ||
+ | route with multiple | ||
+ | separated values and there is no route | ||
+ | configuration in viewfind that knows | ||
+ | what to do with this | ||
+ | the default route expects only two | ||
+ | pieces and we've just provided three | ||
+ | so if we want this kind of a route to | ||
+ | work | ||
+ | we need to generate a custom route | ||
+ | fortunately we have a command line | ||
+ | generator tool | ||
+ | that will do exactly that | ||
+ | so if i go back to the command line | ||
+ | where i'm in the viewfinder home | ||
+ | directory | ||
+ | i can run php | ||
+ | public index.php generate | ||
+ | dynamic route | ||
+ | and then i need to specify | ||
+ | the name of this route which i'm going | ||
+ | to call | ||
+ | tutorial dash home uh the route name | ||
+ | is important both because it's used as | ||
+ | the key | ||
+ | in the configuration array so that you | ||
+ | can potentially override it by name | ||
+ | in a later part of the configuration | ||
+ | process | ||
+ | it's also important because in templates | ||
+ | you can use | ||
+ | the url view helper to convert a route | ||
+ | name | ||
+ | into an actual working url which is a | ||
+ | great way to abstract your urls and make | ||
+ | it possible to override and customize | ||
+ | them | ||
+ | anyway i've named my route tutorial home | ||
+ | here | ||
+ | then i need to say which module or | ||
+ | rather i need to say | ||
+ | which controller i'm using the tutorial | ||
+ | controller | ||
+ | and then i need to provide uh the | ||
+ | remainder | ||
+ | of the route that i want to match so | ||
+ | i'm going to say home slash colon | ||
+ | location this is using the router' | ||
+ | segment syntax where you can put | ||
+ | any name beginning with a colon to use | ||
+ | as a placeholder | ||
+ | that will be passed through to your | ||
+ | controller as a route parameter | ||
+ | so the idea here is that we want to | ||
+ | allow | ||
+ | a location name to be appended after | ||
+ | the home part of the url | ||
+ | finally i say tutorial for the name of | ||
+ | the | ||
+ | module where i want this configuration | ||
+ | to be added | ||
+ | so when i hit enter here | ||
+ | it automatically makes some changes to | ||
+ | my tutorialsmodule.config.php | ||
+ | i should also note that dynamic route is | ||
+ | just one of several | ||
+ | uh route generating tools that viewfind | ||
+ | includes you can also create | ||
+ | static routes for simple pages that | ||
+ | don't take segment parameters | ||
+ | uh and you can create record routes for | ||
+ | linking to things that act like you find | ||
+ | standard record view | ||
+ | you can find more details on all of this | ||
+ | on the generator page of the wiki | ||
+ | but for now let's just take a look using | ||
+ | git diff | ||
+ | at what the generator just did for us | ||
+ | and as you can see it created | ||
+ | a route named tutorial home like i asked | ||
+ | it to | ||
+ | it's a segment route because i used | ||
+ | the appropriate generator to create | ||
+ | segment routes | ||
+ | and the full route is slash tutorial | ||
+ | slash home slash | ||
+ | location placeholder it got the tutorial | ||
+ | part from the controller name i provided | ||
+ | and the rest from the action i specified | ||
+ | and then it has defaults of tutorial | ||
+ | controller and home action | ||
+ | because we want those values to be | ||
+ | hard-coded in because we don't have | ||
+ | controller or | ||
+ | action segments in the route match | ||
+ | so let's see what that did for us | ||
+ | if i go back over here | ||
+ | and refresh the page sure enough | ||
+ | uh i no longer have an error because | ||
+ | there' | ||
+ | route that understands what to do with | ||
+ | tutorial slash home | ||
+ | custom location but i just have my | ||
+ | default hello world message | ||
+ | because i haven' | ||
+ | that route parameter yet | ||
+ | thus i need to go back to my code again | ||
+ | and back to my controller | ||
+ | and as i mentioned the controller' | ||
+ | params helper can get | ||
+ | values from a variety of places and from | ||
+ | the route | ||
+ | is one of those places so i can say | ||
+ | location equals | ||
+ | this params from route | ||
+ | specify location which matches that | ||
+ | segment name | ||
+ | uh in the route configuration we just | ||
+ | looked at | ||
+ | and just with uh just as with query | ||
+ | parameters | ||
+ | i can also provide a default value | ||
+ | should that | ||
+ | be omitted so i'll just say default | ||
+ | location here | ||
+ | and i need to pass that location value | ||
+ | along to the view | ||
+ | through the view model so i'm also going | ||
+ | to add | ||
+ | down here location key to | ||
+ | point to the location variable | ||
+ | save that go over to my template | ||
+ | and now i can just say you are in | ||
+ | and again i use a php echo tag | ||
+ | to display an escaped version of the | ||
+ | location | ||
+ | that comes through from the route | ||
+ | now if i go back and refresh again hello | ||
+ | world you are in custom location | ||
+ | i can add my name to this and it will | ||
+ | say | ||
+ | hello damien you are in custom location | ||
+ | pretty neat so these are two different | ||
+ | ways you can provide values | ||
+ | from the url and communicate them to | ||
+ | your controller | ||
+ | and this explains how a lot of the urls | ||
+ | in viewfind | ||
+ | actually work so | ||
+ | let's just do uh one more thing | ||
+ | what if we wanted to have | ||
+ | a less complicated url we don't like | ||
+ | this home portion | ||
+ | so we'd like to just be able to say | ||
+ | tutorial custom location right now if i | ||
+ | do that of course i get | ||
+ | cannot dispatch because there' | ||
+ | thing in my controller as a custom | ||
+ | location action | ||
+ | but we can take advantage of the router | ||
+ | to just change the way the tutorial | ||
+ | controller behaves | ||
+ | and make this a little simpler to | ||
+ | build our urls all i need to do | ||
+ | is go into my tutorial module | ||
+ | and edit the configuration there | ||
+ | so let's find my route down here | ||
+ | so right now this route is very specific | ||
+ | it has to have slash tutorial slash home | ||
+ | slash in it or it won't match and it | ||
+ | also has to have some kind of a location | ||
+ | placeholder | ||
+ | but let's make more things optional | ||
+ | so first of all we don't want to say | ||
+ | home anymore that's not interesting to | ||
+ | us | ||
+ | uh next let's make the location | ||
+ | value optional so that if you leave it | ||
+ | off you can have a default | ||
+ | let's also make this trailing slash | ||
+ | optional we'll wrap another pair of | ||
+ | brackets around | ||
+ | so now if you go to | ||
+ | [Music] | ||
+ | tutorial by itself you're going to get | ||
+ | the home action if you go to tutorial | ||
+ | slash | ||
+ | something you're still going to get the | ||
+ | home action because it's | ||
+ | set down here as the default but what we | ||
+ | need to do now | ||
+ | is add a default value for this location | ||
+ | placeholder | ||
+ | so that something gets passed through if | ||
+ | it is omitted | ||
+ | i'm going to say default route location | ||
+ | because this will be useful for | ||
+ | demonstrating something helpful | ||
+ | uh the other thing that we might | ||
+ | consider doing | ||
+ | is adding a constraint for our location | ||
+ | placeholder | ||
+ | these default controller and action | ||
+ | placeholders are actually | ||
+ | meaningless in this context because | ||
+ | these values can't be passed in but | ||
+ | they' | ||
+ | routes just as sort of a safety | ||
+ | mechanism and example | ||
+ | but since location is something that | ||
+ | users can provide input to we might want | ||
+ | to control what characters they' | ||
+ | allowed to pass through in that position | ||
+ | to protect against attacks or unexpected | ||
+ | behavior | ||
+ | so i'm just going to put the same | ||
+ | constraint | ||
+ | on location that is used for controller | ||
+ | and action | ||
+ | uh to require it to start with a letter | ||
+ | and then | ||
+ | follow that with the sequence of letters | ||
+ | numbers and separators | ||
+ | so with all of this saved if i | ||
+ | go back into the browser | ||
+ | and refresh my page | ||
+ | now i'm at my shorter version of the url | ||
+ | and it's working again because the | ||
+ | router matched this pattern | ||
+ | and took us to the home action and | ||
+ | passed through all of the values | ||
+ | the other thing i wanted to show you is | ||
+ | that if i leave | ||
+ | off this location placeholder | ||
+ | it now says i'm in default route | ||
+ | location | ||
+ | that is because i specified a default | ||
+ | value for location in the route | ||
+ | and even though my | ||
+ | controller when it reads the location | ||
+ | from the route | ||
+ | uses this default location value if the | ||
+ | placeholder is missing | ||
+ | the router default is going to get | ||
+ | applied first and that's going to take | ||
+ | precedence | ||
+ | over the default in my controller | ||
+ | so that's all i wanted to show you today | ||
+ | you should now know how to build routes | ||
+ | and how to build controllers and also | ||
+ | perhaps | ||
+ | understand a little bit better about how | ||
+ | user input from the browser | ||
+ | flows through into viewfind' | ||
+ | and how data gets displayed | ||
+ | uh if you don't want to build a whole | ||
+ | new controller there are also other | ||
+ | generators you can consider using such | ||
+ | as | ||
+ | the extend class generator that you can | ||
+ | use | ||
+ | to override an existing controller | ||
+ | in your custom module so you could | ||
+ | override just one method or you could | ||
+ | add a method to an existing controller | ||
+ | you can also as i mentioned use route | ||
+ | names | ||
+ | to override specific routes in your | ||
+ | local module if for example you wanted | ||
+ | to change the text that displays in the | ||
+ | url for certain kinds of functionality | ||
+ | these are all things i'd be happy to | ||
+ | demonstrate on a future video if there' | ||
+ | interest | ||
+ | so let me know in any case | ||
+ | thanks again for your attention and i | ||
+ | hope this has been helpful | ||
---- struct data ---- | ---- struct data ---- | ||
+ | properties.Page Owner : | ||
---- | ---- | ||
videos/code_generators_2.1602586658.txt.gz · Last modified: 2020/10/13 10:57 by demiankatz