Transcripts
1. Introduction: Welcome to this class on symphony PHP framework. It is awesome to have you here. Symphony is used by loads of real-world businesses. So you'll be both getting experience it can use in your personal projects and also commercial experience for feed going out there as a contractor or working for a software company. We net do it hands-on like all skill share projects and build an e-commerce store together. So let's get started.
2. Symfony CLI: The symphony CLI will give us a bunch of command line tools we can use to do load a helpful things. So to get to that, we can get at a symphony website and you'll get instructions for whatever platform you're on. So if you're on Mac, you just need to copy this into your terminal. Same thing with Linux. If you're on Windows, then you'll get downloadable executable and you can download that. And that will take you through the install process. However you do it once you're through that, then you can open up your terminal on Linux or Mac. And you can do command prompt or cygwin on Windows. And if you just type symphony, let's clear this first. Then if you get a command not found, you'll know it's not worked. If you get all this information with the symphony CLI and all the commands you can do, then, you know it's setup and ready to go.
3. Checking your environment: Once we've got the symphony CLI, so up, we can check whether everything else is setup using the symphony CLI. So if we do Symphony, and then if we do check colon requirements, this will check whether we have everything we need in PHP setup correctly. And in this case, good news, I do. Now there's some warnings here which are optional recommendations, and there's some stuff I could change, but you absolutely don't need to do these. As long as you get the ok here, you could ignore the warnings. Those might be useful for a production setup, but in case of Git's getting started, so we get this, okay, it doesn't matter if we've got a few warnings of pair.
4. Installing Symfony: Now that we know we've got our environments up correctly, let's go ahead and install off symphony project. So when it come to the command line, and I'm gonna type symphony New. And then we're gonna give our project name. Now we could do dash, dash fall. And that would install symphony and a bunch of libraries that we would typically need in a full-stack web application. But in this case, I wanna keep things slim lines that we only install what we need. We have what we need and nothing more. And we can show installing additional libraries on the way. So I'm going to skip that. And I'm going to call it project Bike Shop. So just symphony, new bike shop. And then symphony and we'll go off and start creating all of this. So we'll take a couple of moments for all this spin through IS symphony goes and fetches all the dependencies. And then we get, okay, great, so we can open up this in our code editor. I'm going to use Sublime here. But you can use whatever you want. Okay, nice. So we've already got a bunch of files there. Go to that public directory, a source directory. So I can ignore. The symphony will tell us the things that we shouldn't be committing to get. We've got the, all the configuration for Symphony lives in S config directory. And by default, we've already got a loaded this stuff. And we've got a composer file with a bunch of dependencies here as well. Okay, nice.
5. Symfony dev server: Now that we've installed our first symphony application, let's go ahead and run it. So we've got back to Terminal and we'll cd into the directory you just created. In this case, I called my bike shop. And we'll do symphony server, carillon start. And this will stop symphonies development server. We just kinda like PHP is built-in web server, but specific for Symphony. And then if we go to localhost, 8 thousand. Perfect. So we're just saying the default page that symphony creates when you create a new application. Obviously we're going to create our own page here, but this looks good. It's already up and running and working.
6. Symfony architecture: In this lesson, I want to cover some of the basic architecture of Symphony. Symphony uses an MVC Model-View-Controller architecture. And the way we're gonna do that is we're going to create some classes that are called controllers. And inside those controllers, that will have a bunch of functions. And each one of those functions will represent a different page and will output some things. So that could be a template or that could be a bunch of Jason, or that could be a bunch of raw HTML. However you want to output, that function will return, it will map a URL to a specific class and that specific function within that class, and then that method will return something. So if we look at the way the MVC structure, we've got our model, which is our database entities typically will store those in source entity. We then got a view which is typically our templates usually will reduce to again engine. And we'll cover all of this in more detail as we go through the course. And then we've got our controllers, which are our PHP classes, which connect the two together. Symphony is lightly, loosely coupled, so it's easy to decouple things. What that means is that you don't have to use doctrine to do your database and you don't have to use the twig engine to do your templating. If you want to swap a and propelled to do your databases or Smarty to do your templates, you can. But symphony also makes the default options really easy to integrate. So if you do just want to take the stuff that works really nicely at the box and you don't want to mess around bringing in different libraries. Things will work really nicely together.
7. Creating a controller: Now we've got this application up and running. Let's go ahead and actually create a page, or at least a simple little hello world. So the first thing we're going to need to do is create a controller. And we've got this controller folder, but there's nothing in it at the moment. So let's start by writing a new one. Stick it in the namespace. And we're going to need to return a response object. Symphony gives us one of these. And then we'll create our control loads call this first control lawn. I'll create a method which is called homepage. And it's going to return a response. And in Finnish response object, we can just give it a string with some HTML. I will say this pest control it up, hit me. So when that source controller directory, okay, so we've greater dot controller, we've created a homepage method is gonna return respondents. And then we actually returned this response, which we get from symphony here. And we just return some HTML that says, welcome. So next thing we need to do is why this route up to tell Symphony when they should send the user to this page.
8. Adding the route: To wire up path, we need to go into the config directory and find this routes.rb ammo. And somebody is already given as something to get started here. So let's say we want to this slash first. And this is gonna go to first controller and we call it the method homepage. So we're giving it the path. And I'm going to give you a controller and the method name, which matches up to what we create here. And so now, if we go to slash first, perfect, we've got our simple little welcome message.
9. Using annotations: We've got fast route here and we define this in routes.js demo. But the problem with this is then we'd have to add every r2 into this YAML file. And in a big project that would get unwieldy very quickly. So there is a more popular way to do it called annotations. Let's do that now first, un-comment this, which means this will stop working. Which is no problem. Because instead of that, we are going to use annotations. So we need to bring in the annotation, symphony component, routing annotation. And then all we're gonna do is add a comment here using some special annotation syntax, say root psi slash first. Okay, lovely. So we also need to bring in the annotations package. So let's just pause this and we'll do compose it, require annotations. Okay, now, let's restart the symphony depth. And then if we try it again now, perfect, back. So we no longer use in next routes.js homologs commented out. Now every time we create a method, we can add this row annotation and tell symphony what we want the URI to be for this particular method.
10. Templating: In this lesson, we'll introduce the concept of templating. So typically, when we're building websites, we want our logic and are designed to be a separate as possible so that we're not mixing everything together. And it's really easy to see which bits design, which bits logic. And when we want to edit one of them, we don't risk breaking the over one. And by default kind of symphony comes with twig. So we are going to need to install twig as a separate library. And you don't have to use twig, you could plug it different templating engine in such as mustache smartly. But if you do choose to go twig and we'll go to awaken nest example. It will integrate really well with symphony because twig is also built by the same team that builds symphony. And so they make sure it integrates really nicely if you choose to use that. You can also take twig outside of Symphony and use it in your own projects if you would like to, because they're loosely coupled. So a twig template looks like HTML, but just with some special twig syntax. So when we want to add a variable in there, we use this double curly braces and then the variable name. And we can also put some logic in there like loops, which is where we use the curly bracket and then the percentage sign. And this allows us to do some loops. We can also do a bit of filtering as well. I'm, I'll go through how to use all of this in this module.
11. Installing Twig: In our first controller, we just wrote The hates to mainland to a string, which is a bit messy. Be nicer to have templating. And symphony doesn't come with templating because it's loosely coupled. But there is a template library built by Symphony. It integrates really well called twig. And we can go ahead and install that now. So we'll go back to our command line. Want to compose a require twig. Great, so that's twig installed. And now he can go ahead and create a template.
12. Creating a template: Now that we have twig installed, let's create a template. Keep it pretty simple. And well cone. In fact, this might be the homepage, let's say homepage. And that's all we need for now. Let's call it welcome, and we'll call it welcome dot HTML, dot twig. So a template name, then they datatype. And then we're going to add this dot twig on the end. And we're going to put this in the templates directory. Great, now let's wire this up in our controller.
13. Using the abstract controller: Let's create controller to render out this template. So we can probably copy and paste this code from first controller, and let's call it welcome controller. In the source control or direct tray. I'll change the name. Slash welcome. We can still call the method homepage and Bob and then loading in the tweet library and rendering our self. We can use symphonies abstract controller to give us a nice little helper method. So the first thing we need to do is bring in abstract controller. And then this class is going to extend. Abstract controller now extends even. And what this means is that we now have this lovely run the method where if we give it the name of our template, which is what we call, Hey, welcome to HTML that twig. We can just return the result of this random method and that will render out the template. Hopefully. So save what we've done that and then we'll go back to a development server. And we've got a slash. Welcome. If we stopped it when we instill twigs, let's restart that. And there we go. It's rendered a template perfect.
14. Variables in Twig: This is fine for a very simple static page. But realistically at some point we're going to want the controller to inject some data into this template. And that's really easy to do with a little helper. So here for this random effort, we can just pass an array of data into here. And in this case, I'm just going to add what day it is. So called the standard date method with lowercase l that will give us the day. And then we can add that to our template as well. So let's say today is and in twig to render out a variable, we use double curly brackets. So passing in the die here, and then we're rendering a template. Haha. And if we refresh the page, it says Today is Wednesday, which is the diam filming this on. So pay it. Right. So that looks like it's working.
15. Twig security: If we're rendering out variables into the template, and that could potentially cause security issues. But luckily, twig except to handle that by escaping by default. So let's say I change this and somehow I'm maliciously passed in a script tag, something like this. What would happen then? Well, twig would actually just render it out so it would escape the special characters and just rendering our plain text, so nothing to worry about that. But what happens if you genuinely need to render out some, You've got a variable that contains some HTML and you need that HTML to be rendered. Well, you can do that just by having a pipe and then using this raw function, which will tell twig not to escape it. Now in this case, this would be bad because now it's just executing the code. Although in this case is, Let's change that to a certain small visible nafta refresh. And now we've got this crazy JavaScript popping up. Not good. So if you do need to render HTML, you can use this rule tag. But you do need to make sure that you've sanitized your input to make sure that nobody is injecting any dangerous scripts into there. But by default, even if someone does inject a script somehow, it'll just render it as text. Okay, that looks good. Let's reset and S two hat was. And move on.
16. Using layouts: This template is working, but it doesn't have, for example, a title or any of the HTML head body tags. Now we could just add this to welcome dot HTML that twig, but now would be a massive effort because then we'd have to do it for every template we created. And if we ever wanted to update it, we'd have to go through everything. So a better way we can use its template inheritance. And we can create a standard layout template and then include that in all of this. Let's do that now. So we will stop by all this layout.html twig. And we'll save this into the templates directory. Widgets gonna answer. And that will put the main inside of main will come back to that as well. And it's on some line breaks here because we haven't styled the header on the flutter yet, so it's not going to be obvious. And then inside here is where the magic is going to happen. So we're going to in twig, when we do curly brackets percent, then we're doing some kind of logic. We're going to call this content block. And then we're going to add this n block here. We don't need that, I think in that. So what we've done here is we've defined a layout. And then we've said right here, we're going to place the content. So then if we go back into a welcome template and we're gonna make some changes here. So I'm gonna say this template extends, lad I HTML that twig. And then this bit is going to be the content block. And we could add as many blocks as we wanted. So if we want to a separate photo block or a head block up here, we could also add those and we could get as many blocks as we wanted here. Right now with saying to use layout as the base. And in the content space that we defined, haha, insert this HTML. So it's refreshes now. And great, so we've got our header, we've got foot to, we've got all the stuff in the lab. And then in the middle, here, we've got our content that's specific to this template.
17. What are static assets?: Let's briefly clarify what static assets are. So we've our regular pages with our PHP, we're generating a page on demand and that might be personalized to this user. But some things are just deliver the same thing to everyone, such as images, icons, style sheets, and JavaScript. We can compile these ones and then send them out to everyone. We could put them in a CDN, a content delivery network. And we don't want them to go through the whole PHP stack because we, we don't really need to check things like permissions or personalization. We just need to send them the CSS, and that's what we're talking about here.
18. Serving static files: Symphony gives us this public directory here to save assets out of and not swear it, saving this auto-generate index.html, which sets everything up full symphony. So let's say we wanted to have a robots.txt file. We could just go into the public directory and save that. And then straight away, if we try and access that, then it works, which is great. Now we could do a similar thing for CFS, where we just save it into the public directory and then we put it there. But it'd be nice if we could do something a bit more elaborate with it. And we'll look in the rest of this module.
19. SASS pre processing: We've got our website here, but it looks pretty ugly. So be nice if we could style it with CSS. But ideally we want to use some kind of CSS pre-processor like lasts or socks. Because these give us all kinds of nice extensions to CSS. So for this example, we're gonna use SAS. If you haven't seen it, you can look it up on the website. And it provides us loads of cool things such as variables. So that if we want to define, say, a color and use it in loads of different places in our style sheets, we can just define it wardens. And then we can use that variable. And if we ever want to update it, we just need to update it in one place. So I'll put a link to the SAT stocks in the resources section of this lesson. But luckily, Symphony has some great support of this. We have what's called symphony on-call, and we'll look at how to configure that now.
20. Installing Encore: Let's get up and running. We have Symphony own co-ops. I'm going to open a new terminal tab here. We're still in the right directory. And I'm gonna run it. Compounds that require symphony slash web pack on coal bundle. So this will bring down some of what we need. But the other thing that we're gonna need is because the web part runs on no tasks rather than PHP. We're also going to need to install all of our node dependencies, which is NPM is like the composer of NodeJS. So we're gonna go ahead and run an npm install here as well. And take over that time. Npm. But literals can be huge. Ok. Nice. And that's done. So we look at project now there's a couple of changes as well as our composer dependencies. We've got this package.json, which is what? Which is NPM dependency management. It's installed a bunch of scripts for us, for our end goal. And it's also create these dependency files that we just installed with NPM install.
21. Compiling assets: So we've got dependencies here and that will much like composer has this vendor directory. We've got this node underscore modules, that's where npm puts its dependencies. And we've also got these little commands here. And to rename them, we can do npm run dev. And this is the command we're going to use to build static assets. So in regard to now goodness assets, where we've got this CSS and we've got this JS file as well. And so this is the place where we'll edit them. And then when I rendered that created in this build file, where we get this compressed version. That's the web pack output. And these are the copies will break in to our web page. So we're writing them here and web pack will compile them into this build directory. And we can include them from that.
22. Enabling SASS: So we've now got web pack taking our CSS and JavaScript and compiling it ready for our Including. But we haven't actually enables tax yet because on-call supports multiple different CSS preprocessors, You can also use less and overs. So we need to go ahead and configure it for SAS as well. So we'll start by changing this. We're gonna rename this. Sas uses SCSS. So we'll change that. And then we'll go into this app.js and we'll update this reference here. So it is pointing at the right file. And then we'll go down to this web part, dot-com ab.js. It was created when we installed onco. And by default, and we've got this SAS preloaded, but its commented out. So let's remove that comment. And then we've got this enables Sass loader in there. And then finally, we need to install another dependency using npm to get it to process that. So we'll go back to our command line. Do npm install dash, dash save dev to install the dependency and write that change to the package.json. So when we've been installing Composer dependencies, Jews automatically being adding it. Here, we need to explicitly tell npm that we want it to remember that we've installed this dependency and we're going to need a Sass loader. And SAS. Okay, great, and that's installed. So now let's do npm run dev. Just to check that everything's working. Great, so we haven't exploded anything. That's good news. Now, let's go ahead and bring in the assets that we've created here.
23. Including our assets: Now that we've got ours SS compiling into this public build directory, How do we get it into our template? Well, we've got a nice little tag that will help us with that. So we open up our template file layout.html, twig. We can do on core entry link tanks. And then if we refresh this page by affects though the background is gone gray. And that's that was the default CSS in that. So this is SaaS, even though we're not using any SAS is then put into here where it's compiled. And then we're bringing the end. So if we look at HTML, puts EUR LAN. Let's also quickly go to Google Fonts and bringing an ice foam. Open Sans will do. And we want the regular and the bold. I think. I will just grab this. And I think I have opened sends installed, but I want it to work on everyone's computer. So nice. So we're bringing in CSS, we're also bringing in a font from here. And so now, probably you don't want it to look like this. So we can go start writing some CSS.
24. Adding some CSS: Let's turn this pretty ugly page into something a bit nicer. So first we're gonna go back to our command line and we're gonna run npm run watch. This is similar to NPM when dev, but it will work for any file changes. So as soon as we make a change in the file, it's going to recompile automatically. So here we close all this down, and let's open up this app dot CSS. Firstly, I'm gonna create a variable. So we've got a standard sizing forever hanging. And here She's that nice Open Sans font. We will n set font signs. Let's get rid of any margin around there as well. And style F0 over things that style of foot leaves that standard putting variable. We've gone. And now that we've got some color differentiation, we can turn off the horizontal line. And we'll do a similar thing with a header. Again also the prior ground to line blue. And give it a nice big font size. And some padding again, using the variable of grade. Go into the main tag as well. And I'll add some padding. And then as we save that, it will recompile everything. Now if we refresh the page, perfect, you might need to do a hard refresh because there's no cache busting. So that B control, think control shift or maybe on Windows. I am just to clear out the cash so you're not getting the old version and the style sheet, but as you can see, now that we refreshed, we've got all our CSS working nicely, and this is starting to look like a respectable webpage.
25. Doctrine ORM: In this module, we're going to look at databases and symphony specifically using doctrine of RM. Orm stands for object relational mapper. So this is about mapping objects in PHP to database rows. Someone we pull the data out. How do we get it into a nicely usable PHP object and how do we put it back? And the idea of using an ORM is the ORM takes care of all of this forest. So we can just write PHP objects and we don't have to worry about the SQL. Most popular ORMs in PHP are doctrine am propel. And if you're from other languages, you might have heard of things like hibernate and Active Record. The all do the same thing. You don't have to use dark green for Symphony, but it is really nicely integrated, so it's loosely coupled, but it does integrate very well. And you get a lot of easy functionality out of the box. And doctrine allows us to use pretty much any database platform. So we could use MySQL, MariaDB, and I'm gonna use MySQL in this example because that's the most common for pairing with PHP applications. But you could also use Postgres, Oracle, SQL Server, SQL lie. And you don't really need to make many changes to this. You just tell doctrine what you want to use. You write your PHP objects. And again, doctrine takes care of all of this. So how does it work? How do we actually map our PHP objects to the database? We use special classes that we're going to call entities, but essentially Git from regular PHP classes with some annotations on. And this is an example of when we're going to write for a product and we use an annotation to say, okay, this is and entity. So an entity is analogous to a table in the database. So hey, we've got a product class. And then we're going to have instances of that class. And that's like saying we've got product table in the database and there's going to be rows inside that table. And then each of the columns we use annotations to map as well. So for example, we might have an id property and a punchy getters and setters on the class. And we'll mark that up using annotations to say, okay, this is the ID column in that table, and that's how doctrine knows how to map it.
26. Local database setup: In this module, we're going to configure the database. Doctrine supports a bunch of platform so you could technically use anyone you wish. If you have MySQL and PHP, my admin installed locally, then great, this lesson is for you. All we wanna do is go create a database. So I'm jets in PHP, my admin here. I'm going to create a database called Byte Shop. And then I'm gonna go to the privileges tab. And when I go up to the top, because I want to create a new user. Let's get a user accounts and grit Nuan, criminal combined shot from local host. I'm going to let pitch by half min, generate the password. And importantly, we're going to need to use native MySQL authentication view on some of the new innovations a PDR, you might not need to, but it's just a long-running issue with PHP that you need to use native MySQL authentication or homework. So that's just Slashdot somewhere safe. And I could've just create the user account first. Fight to wonder what happens if I take matte. Ok, so that lets it go. Okay, now, so we've created this bike shop user, and we've created this bike shop database as well. That's how we're gonna do it. If you have MySQL and PHP, my admin installed locally. If not, I'll show you how we can do it on Amazon without you having to install it locally. In the next lesson.
27. Alternative AWS setup: If you don't have MySQL such that locally and you thinking, Chris, I really don't want to do that. It's a lot of effort. My computer doesn't have that much memory. The good news is that you could also get Amazon web services to host your database for you. So if you're already set up with Amazon Web Services, you can probably use that free tier to get through this course. And the way to do that is to log into the console, console.log AWS to amazon.com. And he you could access all of Amazon's web services like EC2 and S3 and all of that we want today we won't RDS Relational day by service. And this will essentially give you a MySQL database in the cloud. And this is when two different setup, this Amazon of aura is fine because that's MySQL compatible. So we click create database and we're going to, even now, there is an option for MySQL. Mariadb would be fine as well. We're going to use Amazon Aurora because it is, and we can see here it's MySQL compatible. We can select version scanf, something a bit more modern. This one. And it's going to be a Devin test1. That TV classifier is fine. Let's just use the same password here. Obviously, I'm gonna delete only these credentials. After I finish filming this course. All of those options are fine. Let's go ahead and click create database. And it takes a little while for Amazon to do anything in the cloud. So it'll take maybe 510 minutes to set this up. But if we go up to this view credentials here, then we can see we've got the admin and password. And once it so we'll be able to connect up to database as well. So those are the credentials you need if you're going to access it this way, obviously won't have PHP my admin. You could configure PHP my admin to do that. But what more likely you are to do is use software like I've got SQL prohibit a Mac. But also Heidi is really good. If you're on Windows. And you'll be able to create a new connection here. And you'll just put in all of the credentials that you'll get from hair. Great, so now, now it's loaded. We've also got a ha, admin. We've got username, password, and we've also got the location that we need to connect to as well. So those are the credentials that you'll need to put in when logging in using some kind of SQL client, like SQL bro
28. Configuring the database: Now that we've created a database on MySQL and whoever platform you're using, we need to go configure our symphony app to be able to connect to it. So we go back to our terminal, will just cancel out and we need to start installing stuff. Slats do compose that require symphony ORM pack. And this'll bring in the libraries we need to use doctrine ORM. So just give that a minute to spin over. Okay, nice. And then we also to help us do some of the building, we gonna do require but dash, dash, dash, because this is going to be a dev dependencies that we're going to use it when developing locally, but we're not gonna need it for production. We're going to need the symphony may come bundle. Okay, now, so we've got all the dependencies we need. Now. We also need to configure this in a.m file. So we've got this database URL here. So we call the use of bike shop and we've got a password here. And let's change this to localhost. And D b is also called buying shop. And the other thing we need to do is pass in the version of MySQL running if we're connecting to a MySQL. I think I'm running quite a light version 8. Okay, now, so we've installed our dependencies and we've updated our database URL with the correct path.
29. Creating a product entity: Now we've configured our database, it's time to make our first entity. And an entity represents a database table. And we could write it all from scratch. But it's often easier to use the built-in tools that we get. We have doctrine and symphony. So we're going to petri Ben console. When you do make colon entity. And I'm gonna give it a name. In this case, we're going to call it product. And this will take us through a series of questions as to what we want the entity to look like. So we need to arrange properties, for example, a name. And it's going to be a string. Okay, nice. And sat up price is going to be a decimal sides, an image which in this case is also going to be a string. It can just point to a filename. Say this one can be nullable. And we're going to have a description. It's gonna be a text. Next, one can be nullable as well. Okay, nice, and that's done. Let's go see what that's created. So we've now got this inside the source. We'll call this entity folder. And we've got this product. So it's any entity namespace. And it's got all the properties we've created, the name, price, image description. It's also got getters and setters generated for all of those methods. And we've also got its ID property that is automatically added for us. And then we've also got this product repository which we'll use for searching the table as well. So that's all we had to do was answer those questions. And all of this code was generated for us.
30. Generating the schema: We've got our product entity class here with our database itself is still empty. Now we could manually create the tables. But because we've already defined what we want our product entity to look like. We don't need to do that. We can get doctrine to do that for us. And we do that by there in PHP been console make colon migration. And that should have created a migration file. So if we're looking at now, inside are returned to us migrations directory. And this gives us a way to programmatically upgrade and downgrade the database. And it's got its own method where it's creating this table and a down method to get rid of it. And then we can run that. We could automate that as part of our build process. But here we're going to just run it manually. So let's go back. And now that we're happy with with the SQL that is generated when run doctoring colon migrations, colon migrate. And that will run the migration script. And now if we go back to our database, perfect, we've got our product table. If we look at the structure, it matches the structure of the entity. So we've now, we just wrote the PHP code and all of the SQL was taken care of for us using doctrines, tools.
31. Importing sample data: Now that we've got database or from running this juice Bev admin today. So if we go into the product table, it's empty. And be nice if we had some examples in there. So I've provided those for you. So if we sample SQL code, we can run fine. Let's just dig it and stick into the SQL here. So hopefully you've downloaded the example code. And I've got it here. I'll just open this up. If you go into the example code that you can get from GitHub and you go into this resources file. That's this example products, the SQL to copy and paste that in and can do this in PHP, my admin. Or if you're using the Amazon database, you could use SQL pro or Heidi will have SQL client you configured and just run the SQL. And then you'll get all these examples. Here are couple of other things we want to copy over from the example code into our project in public. Let's bring in all these images. And also in the assets and CSS has allowed of nice CSS air. So again, let's just copy that over. And if you go back to your project, then find all Less CSS. And let's just bring them up to date. So we'll say npm run dev just to rebuild the CSS we've got. So by the end of this should have some example products in your database. You should have some updated CSS. And you should have a bunch of images in here too. And this'll Git's helpers speed things up as we go through the project.
32. Listing the products: Now that we've got everything set up, let's go ahead and create a controller and render out some of these database objects. So we've got, so we'll go in and just copy him priced. Let us take a welcome controller. And we'll call this products Control-A. And we're going to want to bring in that repository that was great for us. We'll rename this to products controller homepages. Fine. Let's make this the actual harm pledged to the root will just be slash. And then we're going to use some of the magic wiring and symphony, say, bring in the repository and call it repo. So this means that when Symphony calls this method, it's going to automatically inject the Paul repository, which is the thing will use to search the database. And then here, let's get a list of bikes budget saying repo, Find By. This is a method where we could put columns in here. So we could do name equals bike x. But in this case we're just going to find everything. So we're just going to leave it like that. And then here we're going to tell it to render a homepage. And we'll pass in our list of bikes. Okay, this all looks good for the products controller. Now it's go Create template in the next lesson.
33. Product listing template: Now if we create our controller, let's create a template as well. So I'll just copy and paste. Welcome. And we'll call this home page HTML the twig. They've been template's directory. And we're going to extend the layout as before. We're going to change this code. We copied in some nice CSS, and we'll use that here. And we use some twig logic. So we'll say for bike, in bikes, OK. And close the div. And then it is going to create a loop in here. Say if bike image. And we're eventually going to route this to a product page. So let's say something like that. And that's how the byte name, and it's going to be a link as well. And then finally we'll put price. There we go. Cool. So let's take a look at what we're doing here. Is we are looping through eat to the bikes. And we're saying if it's got an image, display the image. If not, just display the name and price. Okay, so if we check our dev server still running, looks like it is restarted just to make sure we've got all the lights dependencies in. And then if we just get a slash, can't find our product repository, I think because I've got a namespace wrong there. So it's gonna be app entity for opponents of tree. Let's double-check here. Yet. It isn't repository. Let's troubleshoot less in the next lesson.
34. Viewing our product list: Okay, so simple issue here, since I'm an extra S in there. And once we fix that, it works fine. Great. So we are taking all of the records at the database, which we're doing using this product repository, passing into the template. And the template is then looping through them and displaying them all. There. We've got our database connection up and working and retrieving data.
35. Routing options: Symphony offers us a bunch of options when we're defining roots. So, so far we've just defined a static route. Wove just said, this is our way. We want it to map to the method that we've annotated. But we can also use variables. Having that second example, we've got this idea of slug for say, a blog post. Each blog post is going to have its own slogan site to access that, we'll need to get there. We can also limit the methods that people used to call it. So things like get, post, put, delete, we can say, OK, we only want these roots to map here if it's one of these methods by default, if they will accept monks to them. But we can limit that if we want. We can give the route and name, which is useful if we're doing things like redirects. And we want to redirect to a specific route. We can give it a name, and we can also add filters to the parameters. So for example, in the third example, if ID is only supposed to be a number, and we don't want the route to match if there's any characters and that, and the alphabetical characters, then we could add requirements and to say, okay, this has to match this regular expression. So symphonies, routing annotations, even though we've only really used basic ones so far, have a bunch of other options. And we'll get into some of these parameters in this module.
36. Product details page: We've created a list, but we want to be able to click through on these and view the details. So let's go ahead and take care of that. So we're gonna create a new method inside our products controller. And let's start by defining the root. So there's gonna be slash products. And then we're gonna have the ID. And we'll put the ID and curly braces to let symphony now it's variable. And then we'll define the methods. Because we've added up variable here, we can take ID as a variable into the method. And we'll also gonna want a bunch of other stuff. So we'll take a request in. And we're going to want our product repository again. And we're going to return a response. If I, let's let's get rid of that request for now. And I think we're going to use that here. And first thing we need to do is find the correct bike. And we can do that just using the find method that lets us pass in a primary key. And in this case we have the ID, so we can do that. And then all we're gonna do is render a template class. We're gonna pass in the bike. So that should be all we need initially for this. Let's go ahead and create a template for it in the next lesson.
37. Product details template: Let's create a template. So we can probably use homepage as a base. We'll call it details to HTML twig. And put some bread comes up. So this user to easily navigate back to the homepage. And then this is going to be product details. Some nice pre-built CSS. We're not going to be looping through the bikes because we've only got one bike. And here, let us take the bike image. And then the second div, and put a byte name in H1 and put the price underneath it. And knocks Good town here. Say if a bike has a description. Okay, looks good. So now if we go to here and we click through to a bike, perfect, so we got a little bread crumb, we've got our image, you put the name and the price. And we've got the description reading out in the bottom as well.
38. Handling not found errors: This works fine for going from the homepage and clicking into by details what happens if this ID was wrong? It was for a non-existing bike. May we removed a bike and there was an old link still there. Well, I'd all Condie goes wrong and we get 500 era because the bike is null, but we're still trying to access the image. So let's add some handling to double-check that. So let's go into a details page. And here I'll say if bike is no, sorry. And that's what we get from the fine method. If it can't find the ideal, Just give us know. Then we can use some other symphonies, nice helper methods. Just to say this byte does not exist. So for, for forever. And if we go back, okay, this is good. So it kinda looks the same because it's still an error page, but we now get an a for row four rather than a 500 error. So the server's not exploding. This is an area that we're expecting to happen and we can make this page look a bit prettier for the user.
39. Customising the error page: If the user does get a four or four era, than we want it to look a bit prettier than this ideally match our design. And we can pretty easily do that. So let's take, let's just grab a homepage again and will do. But if customization air, so we're still going to bring in the layout. But let's get rid of this old content. I'll say page not found. And then we'll say somebody like, sorry, the page you are looking for does not exist. And we give them a link back to the homepage. Now the way we get this to work is super-simple into AIG, but a bit fiddly. So we need to specifically calling error for or for the HTML dot twig and inside the templates directory when any two credit aren't trickle bundles. And then inside Bundles We're gonna create one called twig 10. And inside that we're going to need to create one called exception. And then we'll finally save it. So it pretty specific templates, bundles, twig bundle, exception error for four. And that's just not a bit of spacing and that too, okay, that looks good. Now because we're running the development server, we won't actually get the error page here will continue to get the symphony Debug thing. But if we want to test what are our page looks like, we can do that by going to underscore era and then put the error code in this case four or four. And this here we can see we've got our page not found error, and this is what the user will say in production. So in development we get the full symphony ever stacks that we can debug blame production. The user would see this nice error page we just created.
40. Add to basket: In this module, we're gonna take care of the anti basket functionality. So we're going to need some kind of add to basket button that allows users to add bikes to lie basket just like any e-commerce platform. And we're gonna need to persist that basket of multiple pages. So once they've added, it doesn't disappear on the next page. And luckily, symphony mx is really easy to do it by wrapping up the PHP session functionality in some nice easy-to-use functions.
41. Add to basket button: Going to details template here. So let's go ahead and add this Basket button to it. So if we open up the details template and under price, we're just going to crap form. And then n hat, we'll use a variable we haven't created yet. And we will say f in basket. If it's already in the basket and we don't want the US to build to add again. So we'll make a disabled button and we give them some feedback. It's Odeon saying added to basket. And if not, then we'll create a button until basket. And we'll do the M deaf. And we've already closed our foam. Great. So if we refresh now, it's gonna complain the basket doesn't exist. So let's go create that. And want to false for now. Perfect. So we've now got this button. It doesn't do anything, but the button itself is that let's wire it up in the next lesson.
42. Configuring the session service: Configuring the session is going to be nice and easy because session handling comes with symphony. Even on a basic install, there is some configuration we can look at. So if we go into the config and then into packages, we're going to this framework. Hey, we have a bunch of options for the session so we could change the session handling if we wanted to. But in this case, everything that symphony gives us by default is fine. So we can leave this framework dot yaml as it is, and we're ready to go. We can just use session out of the box. We don't need to install any of the packages.
43. Handling request input: Now that we know we can use a session service and we've got a template. We can go in and wired up in products controller. And a couple of things we'll need only the request object because one was the response object for my HTTP Foundation. And also may need to bring in our session. Again, this is also an HTP foundation package and I section does session interface. So we've gotten IOs. So we can now use those down here. And again, we've symphonies, magic where I ring. We get towel symphony what we want. And it will take care of actually wiring it in that for us. So we don't have to explicitly pass any of these n. We just say Won't the request and the session interface and symphony and we'll take care of the rest. Ok, so now let's add some handling for this code. The first thing is we will get basket. And the second parameter we calling on the gatt is the default. So if there is no basket in the session, we did, it's gonna get an empty array. And then we're gonna say, is this request a post request rather than a GET request? If so, we know that we've clicked the anthro Basket button and EFSA. And we're going to add the bike. And then one final thing is, and we need to update this in basket variable. And we'll just enter scared and I will talk for it. Okay, so we are getting the scarab, the session. And if it's not, then I will just have an empty array, which is fine, that's an empty basket. And then we're saying if this is a post request, the users click the button. Then what we wanna do is add the bike to the basket. We're gonna use the ID as the K in an associative array and then save the byte to that. And then we're going to write the updated basket back to the session. And then down here, we're gonna say, okay, search the basket full this bike. And if it's A1, then the bikes already in the basket so we can display the over button. So let's just refresh this page and onto basket. And boom, there it is. We're now really added to Basket button because it's being added. And as we reload the page, it looks in the session, finds the bike is already there. And let's just refresh to make sure sticking around, it is perfect.
44. Basket controller: We've gotta add to basket functionality working. So next thing we want is to be able to actually view a basket. Cloud somebody's down. And I'll copy and paste. Products can try a lot. And we'll call this one basket controller. This will rename it as well. And then we'll just call this basket and we'll set a root to slash basket. I don't know how this ID OK. Nice. And then we'll just get rid of all of this code as well. The first thing we're gonna do is same thing we did before if just getting a basket. And that's the basket is empty, will default to an empty array. And let's add the ability to delete things from the basket as well. So psi is method. We're going to get the ID and this'll make more sense when we do the template. So if a user wants to delete something from the basket, we will post the ID and we'll get the idea, hey, remove it from the basket array. And then we'll write that basket back to the session with the removed item. And the next thing we wanna do is we want to provide some kind of total. So let's iterate through the basket and pull out each price. So here we're going to map through the basket. Knew I went and sat in here and they infringe one get price. And then once we've got all the prices, just sum them together. And that'll give us a title. And then we're gonna render everything out. So well. Template called basket dot HTML look twig that will create later. And I'm going to pass some things. And so we're going to pass the basket in so that we can iterate through everything in there. And we're gonna frost the total that we've calculated as well. Okay, that looks nice. Let's create the template in the next lesson.
45. Basket template: Now that we've got a basket controller, let's go ahead and create a template. So I'll just grab details dot HTML at twig, save, that's basket Dykstra amounts at twig in the templates directory. We use the breadcrumbs, everything else can go. I'm going to call it basket grad div with the basket class. Once again, we've already got some nice CSS in. And the first thing is we're going to loop through all the bikes. And we're going to use a little filter in twig. So call the number format method. And this will automatically add a in commas I'm decimal places and make it look nice. And we're also going to add it in this ability to remove some fan. So here I'm going to add a button that says Remove. And we're going to add a hidden by KID. Yep. So now form a remove button, sends a bike ID so that in the where we're grabbing the ID, removing it from the array. We've got that. Nice. And hey, we're gonna add a final row. I'm just gonna say title. And again, we're going to call this little helper method on twig number format. That works just like pitch base number format. It's almost certainly the same underlying function. Okay, and that looks nice. And the last thing that's out of button's check out. Obviously this won't do anything because we haven't built a checkout, but we're gonna use it later. Okay, so that template looks good to me. Let's try again a slash basket. And there we go. We've got our bike. Let's go back to the homepage. And that's that's more bikes. And then we'll never get it back to basket. Ohms, if I could spell basket, right. And then we go through all three of our bikes nicely formatted to use the dollar sign rather than a pound sauna. Skype. Fix that. Okay, nice. And we can also hit this Remove button and it disappears from the basket. Okay, lovely. So the only thing we're really missing now is this new way to get to the basket. So let's fix that in the next lesson.
46. View basket link: Let's add a link so we can get to the basket from one we're on the homepage. So we'll go into layout lab, has twig and we'll say f session, which will give us access to the session object from inside twig and its app variable has loads over useful Stefan. So if you have a need to get access to a variable that you kind of a global variable that she's throughout the application. You can often find the on app. And we'll say get basket. And then do an endif. And then we'll create a link to slash basket. And we'll just call it v basket. Refresh the page. And now we have this nice big V Basket button that takes us to the basket page. Perfect.
47. Installing the form package: What the basket work in, but now we need the strikeout page. And to do that, we could use manually write a form. But that sounds like a lot of effort when we can have Symphony still allow the heavy lifting for us and we can do that with symphony form. So let's go ahead and do the pleasure require symphony dash form. We'll let that spin over for a moment and, and that will bring down the form library that we're going to use. And then we can get started on creating the PHP code itself.
48. Creating an order entity: The first thing we're gonna need is some kind of order entity that we can persist the database to make a record of it. And we could use the make utility again, but why don't we get some hands-on experience creating an entity. And we'll start lazy way by just copying and pasting product dot PHP in older dot PHP. And we'll get rid of that. But we will bring in an inevitable tool from doped drain is the array collection. So I'm not going to involve this point with a repository class, but we are going to need to mock as an entity and we are going to give it a table name because if we just called it older than the database table would be called order. And of course, order is a reserved word in SQL. And so whenever we try to run a query, MySQL would give us an error saying, don't understand what's going on here. This is a reserved word. So we can use this annotation to tell It's the migration scripts to call it orders rather than order. Let's see what else we've got here. So we're going to need the ID, of course. And we're going to want a name as well. And then we're also gonna want an email address. And we're going to want a postal address as well. I think all of us as required, not gonna need this pixel image so we can get rid of that. And then the other thing we're gonna need to do is we're going to need to have a list of products. And we'll just run some code and then we'll talk through it. So we've got this variable called products and what type of data is it? For example, this one's attacks. This one's a string. Well, this one, it's an F type product tends t, It's an array of products. And so we can use this many-to-many tag to tell doctrine to get relationship between the order and the product entity. Now if we're gonna do that over things we need to do is give it a default value because it's going to be an array of products. So we need to set by default, it wants to be an array collection. And then even if it's empty, then we're still going to get all of those values. Well, get rid of this price and image. But we want guys and satisfy for the email. Then this description is going to be address. We're going to set up a trust. And then the last thing we need to do is add a data to get the array of products we don't need to set. Okay, nice. So we've now got our second ends to the Order entity, which we'll have an id, name, email address, and address. Hello the person making the purchase. And an array of products that have been the ADA as well.
49. Building the checkout: Now that we've got older entity, let's go ahead and create a controller. That will be our checkout controller. So I'll just copy and paste this basket controller and we'll call it checkout controller. One of those things are fine. We'll need to bring in some new things as well. From the form package should be extension coal type. I'll bring in a bunch of these types founded for now on needed textile and the text area type. And then we'll need a few local packages as well. So we need to bring in the Order entity that we just created. And the product repository as well. We use always further down. So we'll have our rudeness a slash checkout as well. And in fact, that will do for now. We can get a basket again as before. And we're going to work out as well. So let's just move that code up to the and we can go ahead and create a new order entities so that C and C we just created. And then we're going to use this to create a form using symphonies form library. So we're going to call the form builder. And this is going to create a form around the n states. It's going to use that as the base so that it can add validation and understand what's going on. And then we can add our fails to it. So we're going to add a name. I'm going to add an email address, the postal address. And this one's gonna be a text area type. And then we're going to add a save button. And we can give this a label that says confirm order, call, get form. And then finally down here, we render that chef count here into the basket. Still want a total. Okay, so let's talk through the code that we've implemented here. So great does New Order entity. And we've used that as the basis for our form. And then we said, OK, create these form fables and name and email and address. And these are the types we want. And we then added the submit button. It's called the save here. And we've given a label. And then once we've got this form ready, we're gonna create a HTML version of vet. All of this is provided by symphonies Form Component and we're going to send it to this checkout template that we're going to create in the next lesson.
50. Checkout template: And we've created our checkout with our form. So let's go ahead and create the template. Just use basket as a base, but we can get rid of most of it. Just save as checkout into HTML, twig. Let's get rid of all of this carrot here. So I'll use that low number format helper again here. And then cutting the foam is going to be super simple. We're gonna call the form helper and I'm going to pass in the form. So on checkout controller, we called it form here. We could have called this form 123. And then we just put form 123 here. But as we just called it form, slightly confusingly it to calling for method with the form variable. But that's actually all we need to do. So let's hit, let's proceed. Checkout button which attenders to slash checkout and see what happens. So we've got an error at troubleshoot that in the next lesson.
51. Testing the checkout: We've got one tiny thing to clear up here, and that's what we're going to entity. Namespace should be collections rather than collection. Refresh that now, ok, perfect. So this has all been magically built by Symphony for us. So remember all we did was in the controller. We said, we want to create off this entertained and these failed. And symphonies going ahead and create labels and the fields, forests and configured all us fail, so we try and submit it. It's already got the basic HTML validation on E and F, we fill out some values here and submit it. Nothing's going to happen because we haven't added any handling for it yet. But already out of the box, we've got all of the form HTML built for us. And fluently to date the form or we'd have to do is go update the entity in the controller and all the HTML, all widgets magically update forest.
52. Processing the order: Now that we've got a form created, let's add some processing for it. And the first step is really CB easy. We can just say request, a handle request. Doesn't make any sense such preform, I'm going to say form handle request. And that's going to tell a form to take the incoming request and map it over the form. So let's just philosoph again and show what happens. Now if I submit it. It will save all of my values. Nice. Because when the request comes in, maps everything here. Because still nothing really happening because we haven't handled the submission. So let's add that. So let's say if submitted and it's only do this if the form is valid as well. First of all, we're going to update this Order entity because until this point, we've saved all the values that it saved. They'd been saved into this form. But they're not actually older entity. But if we call this get data and sell order, that will update the order that we have here with the name, email address, address. And the next thing we need to do is we need to add the products to the basket. So we're going to call that get products that calls the array collection on the order. And I'm going to talk to you. And so what's going on here? Well, we're looping through the basket and getting each product. And we using that product ID to find the entity in the database here. And then we're adding that entity into the array of products on the order. So if we had free bikes and our basket, it would loop through the basket gauge or the free GET AID. Find the entity and add n. Could we take because we stored the bike in a session, could we just add it straight onto the array collection will know, because if we did that, it would think that it was a separate entity. So when I'm adding it here, we need to go fetch from the database again. So that doctrine knows that we're not creating a new bike here. It's an existing bike in the database that wants to be attached to this order. So once we've done that, then we built a whole Order entity. And now we just want to save this to the database. And the way we do this is we need to get the entity manager, which we can do with that. And then we're gonna say persist, which means save the audit to the database. And then we need one final call, which is flush, which tells doctrine to ruin all the SQL. It's got buffered. So if you're gonna write multiple entities to the database, you could call persist on a bunch of different ones, and then none of them would actually get written until you call this flush method. So you have to do that manually to say, OK, now write this to the database. And the reason is just for efficiency because of allies doctrine, if you're trying to add five things, doctrine would go to the database five times. And much more efficient for you to tell doctrine when you want it to go and write to the database. So now that we've got and we save that, we can return a separate template. And let's go ahead and create that template as well. So we just want a super simple one head just says, congratulations or didn't. So that's just save. This has confirmation dot HTML, twig. And I'll just say something like we were see. Spell it wrong and go back and fix that in a minute. Yeah. Okay, nice. Now and let's go back to this page. And what's going to happen when we submit this? There's going to be an era. Can you guess why? Okay, perfect. So we've got an error here because this table doesn't actually exist. We create the entity we haven't created in the database. So let's go do that in the next lesson.
53. Migrating the orders table: And as expected, we got this error because we haven't created the database table yet. So let's go ahead and do that. Same way we did before. We're gonna run PHP been dashed console. Make migration next to that of creators. A second migration file. Yep, so it's going to create is these tables of li. And then to execute that doctrine, colon migrations, colon migrate. Nice. If we go look at database now, will say we've got our oldest table. And because doctrine is managing the relationship between the orders and products. So let's equate this order product table with a link between the two. But we don't need to worry about that doctrine handles all the foreigners. Let's try and submit our order. Yet we've got our confirmation screen that great. And here's our order. So go are older and in order products. We can see it's linked up the two bikes that we've got there as well. So that's perfect. Just a couple of cleanup tasks to do that we will take care of in the next lesson.
54. Tidying up checkout: Last thing we want to do here is clear the basket down because even though we've submitted the olga, actually everything still in the basket. So we can really easily do that. And checkout controller once the oldest been submitted. And we already brought session and up here so we can just say session set basket. And we could just unset it, broke it also just set it to an empty array. And so now if we go through the checkout process again, perfect. So the order's been submitted. We've got a new row in our orders database and it cleared Dan a session so the bikes and no longer in the basket.
55. Email and transport layers: In this module, we're going to look at sending email in symphony. But before we do that, I just want to get into this idea of using a transport layer and be really clear as to what that is. So the transport libraries really who's gonna send the email. So if you think about the symphony mail, a component that's kind of like your email client. Like you might have Outlook or Thunderbird or a web-based client like G emails, web interface, or maybe the mail app on your phone. But that's not doing actual sending of the emails. You need to have some kind of email account. And the software just interacts with that email account. And it's the same with symphony mailer is that that's going to interact with the thing that's actually sending the emails. And there's a bunch of options we can do that. We can just use standard email account or we can use what's called a transactional email service. So this is kind of like an API that we connect to and say, okay, sent this email to this person. And it's called transactional because you tend to send them out one at a time compared to say, a mailing list where you would go out and say, okay, I want to send this one email to all these people. Transactional tends to enroll one at time using an API. Now, in terms of getting the email to the person, email isn't a perfect system and some get lost, some independent spam. And generally so the reason you might pay more for a transactional email service rather than just using your email account is it might be better and avoiding spam. Or it might be worse. It's good to test these things because he never really can't tell. We've got a bunch of transport layer options in symphony. It comes with, by default will just get SMTP. So this is the normal way you would configure an email client is go to your email account, get the settings and it will give you a username and a password and probably an IMAP and SMTP server to connect to. And you can also use Gmail. Gmail slightly different, even though it is just a regular email account. There is a separate library that seven-day provides if you want to use Gmail. And then there's a bunch of transactional email services. So things like mail, guns, Send grid, postmarked. Amazon's AWS has its own email service costs, simply mail service and male chimp as well. Now we've male chimp, we're specifically talking about mandrel. So you might have a male chimp camps and that newsletters to your mailing list. But there's an additional add-on transactional email service called mandrill that cost extra money that you can add onto your account as well. So it's not the regular mail chimp email list thing, it's the additional mandrel service that they provide. All of them are good. I really like nail gun person they but if you do want to go for transaction email service, then just do a bit of research and see which one works for you. Or you can just use a regular email account as we're going to do in this example.
56. Installing the email package: In order to send emails, we need to install the mailer package. So let's go ahead and do that. We'll just do composer require symphony slash Mila. We give that a minute to take over that. I'll bring down the middle library and then we can get to work using it and customizing and implementing it. Okay, perfect. We're ready to send emails.
57. Configuring the email service: Let's go ahead and configure the email service. So we're gonna go into our file and then we've got this mailer, the sun here. And the form of this will depend on which transport layer using, in this case, we're just using the basic SMTP server. So you'll need your SMTP details discussed, style a module. Or you could use a different service if you wish. And it takes the form of user password. And then the SMTP details and the port. Now I'm going to go ahead and swap these out for my real details. But obviously you wanna put your personal details in here instead.
58. Sending a confirmation email: Now that we've configured the email service, let's go ahead and update checkout to use it. So we're gonna need to bring in even more classes here. In the mail interface. We're going to bring in the twig integration as well because we want it to be nice and template it. And then let's use symphonies wiring to bring in the mainland. And then so we're going to clear the basket just before we do this. We're going to call the send email confirmation. And I'm going to pass in the order. And the myelin. Now let's functions and we're about to go down and create it. So let's go do that now. It's a private function because we're running into call it from here. And we call it send email confirmation. Can take an order. And a mailer interface. Say, New. Start configuring this from send it from my domain. And we're going to two, and we're gonna use this a dress function. And we bought and we could just put the email address in there as a string. But this will be better because we can also give the name. So we'll get the e-mail out. We'll get the name as well. Subject. I'll say older confirmation. And I'm because we're using a template today. Now, we'll pass that list. Email such order dot HTML twig again doesn't exist. And then context is always passing in a twig variables. So just older in there. And that's done. And then here I'm gonna say my, let's send this email. Okay, so that's the first part done. Let's go create the email template in the next lesson.
59. Email template: Now we've got our Sandy malfunction. Let's go ahead and create a template. And this time we're not going to extend because it's an email. Let's just save this as ordered, our HTML twig. And we placed in a directory and it was e-mails and sesame line, thank you for your order. And then we can list them. Down hand will say we will confirm. Order has been dispatched. Jose for water in all the products. Say per object dopamine. Okay. That looks fine. Pretty simple, pretty basic. But it will form an order confirmation with the order ID and list out the products they bought back to them. Great, so let's test this out in the next lesson.
60. Testing the email confirmation: We've configured all of services and environments for the email. So let's go ahead and test that. First of all, let's just add a couple of bikes to our basket. There we go. Great with Godfrey bikes now basket on a purchase that would fill in my details. And we'll confirm order requests isn't super snappy cuz it's gonna speak to the email service. Or if you were doing this in a big commercial project, you would do this asynchronously, but I put an email in a queue and having someone deal with that later, but this works fine for now. We've got a confirmation. Thank you for Shaphan was and if I open up my emails, we now well, it's all the conformation or the number seven and it's got the bikes. I've lifted that too. So Alex, perfect. Now may be the case if this email doesn't show up in your inbox straight away, you need to go down to your spam folder and have a look in their email. Git's has, most people will know, I guess you're just not very reliable these days because the map spam protection, and especially if you don't get that email set up really well and really genuine provider, then you might get caught in a spam filter. And the way they're avoid IS just tease him hard, expensive email provider unfortunately. But hopefully should be able to find this email somewhere and see the mailer working.
61. Final thoughts: Congratulations on making it to the end of this class. If you've been coding along, you'll have built your first symphony e-commerce store and now know how symphony worked and I would love for you to share your completed code with the class. Good luck and happy developing.