From d69ea3652cc101306aaac87d629e28e9c36d851b Mon Sep 17 00:00:00 2001 From: Louis Charette Date: Mon, 26 Feb 2024 20:03:50 -0500 Subject: [PATCH] Add warning about MAMP, update "web dev, the right way" chapter, Database Gui list and misc spelling --- pages/01.quick-start/docs.md | 6 +- pages/02.background/01.introduction/docs.md | 11 +-- .../02.the-client-server-conversation/docs.md | 93 +++++++++---------- .../03.develop-locally-serve-globally/docs.md | 52 +++++------ .../04.dont-reinvent-the-wheel/docs.md | 27 +++--- .../01.server-misconfiguration/docs.md | 17 ++-- pages/02.background/05.security/docs.md | 5 +- pages/02.background/06.seo/docs.md | 11 +-- pages/02.background/chapter.md | 3 +- .../02.essential-tools-for-php/docs.md | 22 ++++- .../02.environment/02.docker/docs.md | 2 +- pages/04.installation/02.environment/docs.md | 2 + pages/06.sprinkles/03.recipe/docs.md | 2 +- .../03.front-controller/docs.md | 2 +- .../04.controller-classes/docs.md | 2 +- pages/11.cli/01.commands/docs.md | 4 +- .../01.webpack-encore/docs.md | 6 +- pages/14.database/03.migrations/docs.md | 2 +- pages/17.i18n/01.introduction/docs.md | 2 +- pages/17.i18n/03.translator/docs.md | 2 +- pages/17.i18n/04.custom-locale/docs.md | 2 +- pages/18.advanced/08.locator/docs.md | 4 +- pages/18.advanced/11.events/docs.md | 4 +- .../06.custom-namespace/docs.md | 2 +- .../22.upgrading/01.46-to-50/02.guide/docs.md | 4 +- 25 files changed, 148 insertions(+), 141 deletions(-) diff --git a/pages/01.quick-start/docs.md b/pages/01.quick-start/docs.md index 5781a8814..9454fda01 100644 --- a/pages/01.quick-start/docs.md +++ b/pages/01.quick-start/docs.md @@ -6,11 +6,11 @@ taxonomy: category: docs --- -[notice=note]This quick start guide is aimed at experienced PHP developers who already have a development environment set up. If that's not your case, head over to the [First Chapter](/background) to start your journey.[/notice] - UserFrosting is a free, open-source jumping-off point for building user-centered web applications with PHP and Javascript. It comes with a sleek, modern interface, basic user account features, and an administrative user management system - all fully functioning out of the box. -[notice]This is the documentation for **UserFrosting 5**. If you are looking for documentation for _UserFrosting 4_, please see [here](https://learn.userfrosting.com/4.6/).[/notice] +[notice=note]This quick start guide is aimed at experienced PHP developers who already have a development environment set up. If that's not your case, head over to the [First Chapter](/background) to start your journey.[/notice] + +[notice]This is the documentation for **UserFrosting 5**. If you are looking for documentation for _UserFrosting 4_, [click here](https://learn.userfrosting.com/4.6/).[/notice] ## Requirements diff --git a/pages/02.background/01.introduction/docs.md b/pages/02.background/01.introduction/docs.md index 414886095..5e1273320 100644 --- a/pages/02.background/01.introduction/docs.md +++ b/pages/02.background/01.introduction/docs.md @@ -1,27 +1,26 @@ --- title: Introduction metadata: - description: The PHP community has evolved considerably over the past decade, and this breakneck pace has caused a lot of people to get left behind. UserFrosting aims to help new and legacy developers navigate the overwhelming ocean of tools, packages, and concepts in PHP and the modern web development community as a whole. + description: The PHP community has evolved considerably over the past decade, and this breakneck pace has caused a lot of people to get left behind. UserFrosting aims to help new and legacy developers navigate the overwhelming ocean of tools, packages, and concepts in PHP and the modern web development community as a whole. taxonomy: category: docs --- -[plugin:content-inject](/modular/_update5.0) ## Motivation -The PHP community has evolved considerably over the past decade, beginning with PHP5's support for object-oriented programming in 2006, to the first meetings of [PHP-FIG](http://www.php-fig.org/) to develop a [set of standards for PHP code](http://www.phptherightway.com/#code_style_guide), to the release of Composer as the _de facto_ package manager in 2012. At the same time the web development community as a whole has been changing, with websites becoming more dependent on Javascript and CSS to provide sophisticated client-side features. +The PHP community has evolved considerably over the past decade, beginning with PHP5's support for object-oriented programming in 2006, to the first meetings of [PHP-FIG](http://www.php-fig.org/) to develop a [set of standards for PHP code](http://www.phptherightway.com/#code_style_guide), to the release of Composer as the _de facto_ package manager in 2012. At the same time the web development community as a whole has been changing, with websites becoming more dependent on Javascript and CSS to provide sophisticated client-side features. And Javascript has moved even faster! -This breakneck pace has caused a lot of people to get left behind. For someone who hasn't been doing web development continuously for the past ten years, it can feel like a hopeless task to try and get acquainted with all of the new tools and frameworks that seem to be coming out every day. Relevant comic from [Abstruse Goose](http://abstrusegoose.com/503): +This breakneck pace has caused a lot of people to get left behind. For someone who hasn't been doing web development continuously for the past ten years, it can feel like a hopeless task to try and get acquainted with all of the new tools and frameworks that seem to be coming out every day. Relevant comic from [Abstruse Goose](http://abstrusegoose.com/503): ![BlooP and FlooP and GlooP](/images/theoretical_mathematics_however_never_goes_out_of_fashion.png?resize=500) The problem is that when you're a busy developer with a lot of Real-Life (tm) projects to work on, it's very difficult to set aside time to read a book about technology X - especially when you're not even sure that you really _need_ to learn X! -UserFrosting has a better idea. Instead of learning about these technologies as a purely academic exercise, you'll work on one of _your_ projects, and learn what you need as you go! +UserFrosting has a better idea. Instead of learning about these technologies as a purely academic exercise, you'll work on one of _your_ projects, and learn what you need as you go! ## What exactly will I learn? -There are three main categories that UserFrosting attempts to cover: software architecture, tools of the trade, and best practices. Most of the PHP developers we see in chat or on Stack Overflow are behind in at least one these areas: +There are three main categories that UserFrosting attempts to cover: software architecture, tools of the trade, and best practices. Most of the PHP developers we see in chat or on Stack Overflow are behind in at least one these areas: ### Software architecture diff --git a/pages/02.background/02.the-client-server-conversation/docs.md b/pages/02.background/02.the-client-server-conversation/docs.md index 4a133ed26..0778dd326 100644 --- a/pages/02.background/02.the-client-server-conversation/docs.md +++ b/pages/02.background/02.the-client-server-conversation/docs.md @@ -1,43 +1,42 @@ --- title: The Client-Server Conversation metadata: - description: Many developers do not really understand the basics of how HTTP and web applications work. This discussion attempts to clarify some common misconceptions. + description: Many developers do not really understand the basics of how HTTP and web applications work. This discussion attempts to clarify some common misconceptions. taxonomy: category: docs --- -[plugin:content-inject](/modular/_update5.0) -One of the most common misconceptions is that web applications are coherent pieces of software that sit on a server somewhere, and that the client "runs" this application in their browser. This is actually an illusion, carefully crafted to provide a smooth experience for the end user. +One of the most common misconceptions is that web applications are coherent pieces of software that sit on a server somewhere, and that the client "runs" this application in their browser. This is actually an illusion, carefully crafted to provide a smooth experience for the end user. -In reality, web applications are *conversations* between two agents with very poor memory - the **server**, and the **client** - which may be a web browser, mobile app, or another application. In modern web applications both the client *and* the server are typically going to need to run some code throughout their conversation. What's more, in the case of a PHP application, the client and server don't even speak the same language! The server runs only PHP, while the client runs only Javascript. (Note that there *are* server-side Javascript stacks, but we do not use them.) +In reality, web applications are *conversations* between two agents with very poor memory - the **server**, and the **client** - which may be a web browser, mobile app, or another application. In modern web applications both the client *and* the server are typically going to need to run some code throughout their conversation. What's more, in the case of a PHP application, the client and server don't even speak the same language! The server runs only PHP, while the client runs only Javascript. (Note that there *are* server-side Javascript stacks, but we do not use them.) ## Server-side versus client-side code -Beginning developers are often confused by this, and you see questions on Stack Overflow like "how do I get my PHP in my Javascript" or "how do I keep the user from downloading the PHP and seeing my API keys?" These questions come from a misconception that users are actually *downloading* PHP files and then somehow running the scripts in their browser. This misconception is exacerbated by the way that web servers like Apache, by default, use the name and relative path of a PHP script as the URL required to run that script. Thus, it's easy to conclude that visiting **http://owlfancy.com/admin/login.php** is causing your browser to download **login.php** and run the script in that file. But this is not the case! +Beginning developers are often confused by this, and you see questions on Stack Overflow like "how do I get my PHP in my Javascript" or "how do I keep the user from downloading the PHP and seeing my API keys?" These questions come from a misconception that users are actually *downloading* PHP files and then somehow running the scripts in their browser. This misconception is exacerbated by the way that web servers like Apache, by default, use the name and relative path of a PHP script as the URL required to run that script. Thus, it's easy to conclude that visiting **http://owlfancy.com/admin/login.php** is causing your browser to download **login.php** and run the script in that file. But this is not the case! ### Server-side code -What actually happens is that users, through their browsers (clients), make a **request** to the **web server** for a **resource**. This is usually done via a Uniform **Resource** Locator, better known as a URL. The web server generates a **response** to the request, and in the case of image, Javascript, CSS, and other static resources, it often does simply return the contents of the corresponding file. But when the client requests a resource that is mapped to a PHP script, the web server doesn't return the contents of the script. Instead, it *executes* the script on the server and returns the *output* of that script. +What actually happens is that users, through their browsers (clients), make a **request** to the **web server** for a **resource**. This is usually done via a Uniform **Resource** Locator, better known as a URL. The web server generates a **response** to the request, and in the case of image, Javascript, CSS, and other static resources, it often does simply return the contents of the corresponding file. But when the client requests a resource that is mapped to a PHP script, the web server doesn't return the contents of the script. Instead, it *executes* the script on the server and returns the *output* of that script. -In the case of a web page, the output is usually an HTML document. However, a server-side script could produce JSON, XML, Javascript, CSS, or even dynamically generated images as its response. What's important is that the actual code of the script is never sent to the client - if it were, this could open all sorts of security risks! +In the case of a web page, the output is usually an HTML document. However, a server-side script could produce JSON, XML, Javascript, CSS, or even dynamically generated images as its response. What's important is that the actual code of the script is never sent to the client - if it were, this could open all sorts of security risks! ### Client-side code -There are cases when the server *does* need to send code back to the client. For example, we might want to allow the client to automatically check if the information filled into a form is syntactically valid, without having to submit another request to the server. For this to work, we need a language that is universally understood by all types of browsers and clients. Luckily for us, such a language exists - it's called Javascript. +There are cases when the server *does* need to send code back to the client. For example, we might want to allow the client to automatically check if the information filled into a form is syntactically valid, without having to submit another request to the server. For this to work, we need a language that is universally understood by all types of browsers and clients. Luckily for us, such a language exists - it's called Javascript. -When you visit any modern web page, you first get the page itself (usually an HTML document), but then it contains a bunch of references to images, Javascript files, CSS files, and all sorts of other resources that are meant to enhance your experience of the page. Your browser is smart enough to see those references, and automatically request those resources as well. Then when it's finished grabbing a resource, it takes some action - displaying an image on the page, running some Javascript code, or modifying the styles of elements on the page. +When you visit any modern web page, you first get the page itself (usually an HTML document), but then it contains a bunch of references to images, Javascript files, CSS files, and all sorts of other resources that are meant to enhance your experience of the page. Your browser is smart enough to see those references, and automatically request those resources as well. Then when it's finished grabbing a resource, it takes some action - displaying an image on the page, running some Javascript code, or modifying the styles of elements on the page. Thus, to answer the questions from earlier: > How do I keep the user from downloading the PHP and seeing my API keys? -You don't need to do anything. Your web server is configured to do this automatically. As long as you haven't changed the default behavior of your server in some bizarre way, the actual PHP code will *never* be sent back to the client. Only the *output* of the code is sent in the response. +You don't need to do anything. Your web server is configured to do this automatically. As long as you haven't changed the default behavior of your server in some bizarre way, the actual PHP code will *never* be sent back to the client. Only the *output* of the code is sent in the response. > How do I get PHP in my Javascript? -Again, clients can't run PHP in their browsers. If you want to pass along the values of some PHP variables to the Javascript you send back to the client, you need to explicitly *generate* Javascript variables using PHP. For example: +Again, clients can't run PHP in their browsers. If you want to pass along the values of some PHP variables to the Javascript you send back to the client, you need to explicitly *generate* Javascript variables using PHP. For example: -``` +```html I'm having trouble getting UserFrosting to work on (insert some obscure web hosting service). Can anyone help me? +> I'm having trouble getting UserFrosting to work on (insert some obscure web hosting service). Can anyone help me? -The first thing I do is ask them - **have you been able to get it to work locally?** More often than not, it turns out that they haven't even tried - in fact, they don't even have a local development environment set up! +The first thing I do is ask them - **have you been able to get it to work locally?** More often than not, it turns out that they haven't even tried - in fact, they don't even have a local development environment set up! If you're not sure what ["local development environment"](http://daraskolnick.com/developer-tip-tuesday-always-develop-locally/) means, then please continue reading. -#### Why you shouldn't test code on a live server +## Why you shouldn't test code on a live server -You don't need special hardware to run a web server. PHP, Apache, nginx, MySQL - these are all free open-source projects that you can install and run on just about any computer. When you pay your $60/year for Jimbo's Web Hosting, Inc., you're not paying for the software. You're paying for storage and bandwidth on a machine that is (hopefully) running in a well-maintained data center, with 24/7 uptime. Some of your money might also go to paying for basic sysadmin tasks, like updating software, maintaining mail servers, etc. +You don't need special hardware to run a web server. PHP, Apache, nginx, MySQL - these are all free open-source projects that you can install and run on just about any computer. When you pay your $60/year for Jimbo's Web Hosting, Inc., you're not paying for the software. You're paying for storage and bandwidth on a machine that is (hopefully) running in a well-maintained data center, with 24/7 uptime. Some of your money might also go to paying for basic sysadmin tasks, like updating software, maintaining mail servers, etc. -The 24/7 uptime is critical for your live application - no doubt about that. But for **developing** your application, you don't need -to run and test it on a computer in a data center. In fact, there are several reasons why this is a terrible idea: +The 24/7 uptime is critical for your live application - no doubt about that. But for **developing** your application, you don't need to run and test it on a computer in a data center. In fact, there are several reasons why this is a terrible idea: -1. Convenience. I've seen people who write their code in a text editor or IDE, but then upload their code to their hosting service and refresh the page *at their live URL* to "test" their code. This introduces an entire extra step into your development cycle. And what a pain it is! It's much easier if you can just test your code directly on your own machine. +1. Convenience. I've seen people who write their code in a text editor or IDE, but then upload their code to their hosting service and refresh the page *at their live URL* to "test" their code. This introduces an entire extra step into your development cycle. And what a pain it is! It's much easier if you can just test your code directly on your own machine. -2. Security. There are all sorts of opportunities for PHP to inadvertently disclose sensitive data, like database passwords and API keys. This is especially true if you are [dumping stack traces to the response](/background/security/server-misconfiguration), which many PHP installations and frameworks do by default! Developing in a local environment that only you can access ensures that you'll have the opportunity to iron out these vulnerabilities before the application goes live. +2. Security. There are all sorts of opportunities for PHP to inadvertently disclose sensitive data, like database passwords and API keys. This is especially true if you are [dumping stack traces to the response](/background/security/server-misconfiguration), which many PHP installations and frameworks do by default! Developing in a local environment that only you can access ensures that you'll have the opportunity to iron out these vulnerabilities before the application goes live. -Ultimately, you should not think of writing code as the only activity involved in building a website. Making a website or web application really consists of two distinct phases: **development** and **production**, each of which should happen in their own separate environments and involve automated testing, managing dependencies, compiling assets, and a variety of other tasks. +Ultimately, you should not think of writing code as the only activity involved in building a website. Making a website or web application really consists of two distinct phases: **development** and **production**, each of which should happen in their own separate environments and involve automated testing, managing dependencies, compiling assets, and a variety of other tasks. -In this same vein, any framework or CMS that has you do a "one-click install" is fundamentally framing the problem in the wrong way. There is no such thing as "installing" a web application. Rather, a web application is _developed_ and then _deployed_. By missing this crucial distinction, you lose out on the ability to maintain your application and roll out changes in an organized, controlled, and sane way. +In this same vein, any framework or CMS that has you do a "one-click install" is fundamentally framing the problem in the wrong way. There is no such thing as "installing" a web application. Rather, a web application is _developed_ and then _deployed_. By missing this crucial distinction, you lose out on the ability to maintain your application and roll out changes in an organized, controlled, and sane way. -#### Setting up a local development environment +## Setting up a local development environment -If you think that setting up a local environment is too much work, think again! +If you think that setting up a local environment is too much work, think again! On a MacOS or Linux computer, setting up a local environment simply consist of installing a couple of apps through the command line. On a Windows 10 or 11 machine, an additional step is required : Installing the *Windows Subsystem for Linux (WSL2)*! -There are a number of "one-click" installers available, which can set up your machine with a complete web application stack in just a few minutes: +And the sprinkle on the cupcake is the [next chapter](/installation) will teach you how to do everything yourself! -- [XAMPP](https://www.apachefriends.org/index.html) - a bundle that includes Apache, MariaDB, and PHP -- [MAMP/MAMP Pro](http://mamp.info) -- [WampServer](http://www.wampserver.com/en/) +[notice=warning]There are a number of "one-click" installers available, which can set up your machine with a complete web application stack in just a few minutes: **XAMPP**, **MAMP**, **WampServer**, etc. **These are not officially supported by UserFrosting and we do not recommend using them.** They can be slow, out of date or use obscure configuration. They were useful at some point, but with modern tools, especially with WSL2 on Windows, it's never been easier to install every tool you need locally If you insist on using a "one-click" solution, [Docker](#alternatives-to-installing-a-stack-natively-docker) is a [great, modern alternative](https://www.reddit.com/r/PHP/comments/gqhg15/comment/frt8cp0/).[/notice] -#### Alternatives to installing a stack natively +## Alternatives to installing a stack natively : Docker -If you don't have a laptop on which you can install a full solution stack natively, or you want to develop in an environment that **more closely resembles your production environment,** consider using [VirtualBox](https://www.virtualbox.org/manual/ch01.html). VirtualBox allows you to run a complete virtual operating system (such as Ubuntu) from within any parent operating system. +If you don't have a computer on which you can install a full solution stack natively, or you want to develop in an environment that *more closely resembles your production environment,* consider using [**Docker**](https://www.docker.com). When using Docker, you only install one app on your computer : **Docker Desktop**. -If you install [Vagrant](https://www.vagrantup.com/) as well, you can use pre-built and pre-configured environments like [Homestead](https://laravel.com/docs/8.x/homestead), which comes with PHP, nginx, MariaDB, Composer, and Node.js pre-installed. What's more, Vagrant can actually link up its virtual file system to your native OS's file system. This makes it easy to write code on your "real" machine, and then **run** it in the virtual environment instantly without having to actually **copy** it over to the virtual machine. +Docker allows you to run software in packages called *containers*. Because Docker containers are lightweight, you can run several containers simultaneously. What's more, Docker containers can actually link up their virtual file system to your native OS's file system. This makes it easy to write code on your "real" machine, and then **run** it in the virtual environment instantly without having to actually **copy** it over. -To get started with VirtualBox, Vagrant, and Homestead, head over to our documentation on [development environments](/installation/environment/homestead). +Docker makes abstraction of what environmental changes you have configured on your machine. When using Docker, you create a whole environment and this travels with your project. If your colleague needs to work on it, they can use the same Docker configuration and have your project running on their machine within minutes. Docker can also be used for continuous integration testing and even into production. In every step, you are sure to use the exact same configuration. The risk of a feature working on your machine, but not your colleague computer are minimal. -#### Collaboration and deployment +To get started with Docker, head over to our documentation on [development environments](/installation/environment/docker). -Even after you have a local development environment set up, you'll still need a way to collaborate with the rest of your team and, when you're ready to launch, push your code to a live server. - -It turns out that `git`, the popular version control software, can be used to do both! For collaborating with your team, we suggest that you set up a free private repository on [Bitbucket](https://bitbucket.org/). You should agree upon a proper [git flow](http://nvie.com/posts/a-successful-git-branching-model/), and each member of your team should have their own local development environment. For more information, see the installation guide, [Essential Tools for Modern PHP](/installation/requirements/essential-tools-for-php). +## Collaboration and deployment -When it comes time to actually deploy your application, you can [set up a special git remote on your live server](https://www.digitalocean.com/community/tutorials/how-to-set-up-automatic-deployment-with-git-with-a-vps). Then, deploying new changes will be as simple as: +Even after you have a local development environment set up, you'll still need a way to collaborate with the rest of your team and, when you're ready to launch, push your code to a live server. -```bash -git push deploy master -``` +It turns out that `git`, the popular version control software, can be used to do both! For collaborating with your team, we suggest that you set up a free private repository on [Github](https://github.com/). You should agree upon a proper [git flow](http://nvie.com/posts/a-successful-git-branching-model/), and each member of your team should have their own local development environment. For more information, see the installation guide, [Essential Tools for Modern PHP](/installation/requirements/essential-tools-for-php). -For more about deployment, see the chapter on [Going Live](/going-live). +When it comes time to actually deploy your application, you can [set up a special git remote on your live server](https://www.digitalocean.com/community/tutorials/how-to-set-up-automatic-deployment-with-git-with-a-vps). For more about deployment, see the chapter on [Going Live](/going-live). diff --git a/pages/02.background/04.dont-reinvent-the-wheel/docs.md b/pages/02.background/04.dont-reinvent-the-wheel/docs.md index 65b8eeb6f..23b38a6a5 100644 --- a/pages/02.background/04.dont-reinvent-the-wheel/docs.md +++ b/pages/02.background/04.dont-reinvent-the-wheel/docs.md @@ -5,34 +5,33 @@ metadata: taxonomy: category: docs --- -[plugin:content-inject](/modular/_update5.0) -I think that for a lot of developers - novices and professionals alike - building on top of others' work can seem like a betrayal of our trade. We're not "real" developers unless we built everything with our bare hands from scratch, and know firsthand the nitty-gritty details of how our code works. With third-party components, we have to take time to actually *learn* how to use them, and follow *their* rules. I get it. It all feels so antithetical to the DIY spirit that got so many of us into coding in the first place. Trust me, as someone who built a cold frame out of some doors and framing I found in the dumpster, I know: +I think that for a lot of developers - novices and professionals alike - building on top of others' work can seem like a betrayal of our trade. We're not "real" developers unless we built everything with our bare hands from scratch, and know firsthand the nitty-gritty details of how our code works. With third-party components, we have to take time to actually *learn* how to use them, and follow *their* rules. I get it. It all feels so antithetical to the DIY spirit that got so many of us into coding in the first place. Trust me, as someone who built a cold frame out of some doors and framing I found in the dumpster, I know: ![DIY cold frame](/images/cold-frame.jpg?resize=500) -However unlike me with with my cold frame, software developers aren't limited by the contents of their local dumpster. With the advent of Composer, the PHP community abounds with free, high-quality third-party packages for pretty much every task imaginable. The trick is to know *which* packages to use, and to avoid getting overwhelmed. +However unlike me with with my cold frame, software developers aren't limited by the contents of their local dumpster. With the advent of Composer, the PHP community abounds with free, high-quality third-party packages for pretty much every task imaginable. The trick is to know *which* packages to use, and to avoid getting overwhelmed. -Using third-party components solves a couple of problems. First and most obviously, we save time it would have taken write the code ourselves. However for a lot of people, this benefit alone is canceled out by the extra effort involved in learning how to use a particular software package. Fair enough. But consider the additional benefits: +Using third-party components solves a couple of problems. First and most obviously, we save time it would have taken write the code ourselves. However for a lot of people, this benefit alone is canceled out by the extra effort involved in learning how to use a particular software package. Fair enough. But consider the additional benefits: -### Software maintenance. +### Software maintenance -It's [well-established](http://www.eng.auburn.edu/~kchang/comp6710/readings/Forgotten_Fundamentals_IEEE_Software_May_2001.pdf) that on average, 60% of time and money spent on a software project goes into maintenance. Chances are, you won't be the only one using a given package, and this means more opportunities for the community to spot and fix bugs. Even if you don't care a whit about contributing to open source projects, other people do and you stand to gain tremendously from their efforts. You're effectively offloading a huge amount of work in debugging and improvement to the communities surrounding those packages. +It's [well-established](http://www.eng.auburn.edu/~kchang/comp6710/readings/Forgotten_Fundamentals_IEEE_Software_May_2001.pdf) that on average, 60% of time and money spent on a software project goes into maintenance. Chances are, you won't be the only one using a given package, and this means more opportunities for the community to spot and fix bugs. Even if you don't care a whit about contributing to open source projects, other people do and you stand to gain tremendously from their efforts. You're effectively offloading a huge amount of work in debugging and improvement to the communities surrounding those packages. -### Documentation. +### Documentation -In a few months or years, you (and perhaps other people) will have to read the code that you wrote today. And as we all know, writing code is easy, but reading code is [very, very hard](https://blog.codinghorror.com/when-understanding-means-rewriting/). Heck, sometimes I struggle to understand code that I wrote just a few months prior! High-quality packages are already documented for us. We can build an application using package X, put it down for a few months, and get back to work without having to dig through our code to figure out "how does feature A work?" A decent software package is already thoroughly documented! +In a few months or years, you (and perhaps other people) will have to read the code that you wrote today. And as we all know, writing code is easy, but reading code is [very, very hard](https://blog.codinghorror.com/when-understanding-means-rewriting/). Heck, sometimes I struggle to understand code that I wrote just a few months prior! High-quality packages are already documented for us. We can build an application using package X, put it down for a few months, and get back to work without having to dig through our code to figure out "how does feature A work?" A decent software package is already thoroughly documented! -### Community. +### Community -Components that are sufficiently popular will likely have an active community in chat rooms, discussion forums, IRC, and Q&A sites. As much fun as it is to solve everything ourselves, sometimes you really just need to ask for help. Hopefully as you learn more about a particular package, you will also start to help others. And as we all know, the best way to master a subject is to teach it to someone else. +Components that are sufficiently popular will likely have an active community in chat rooms, discussion forums, IRC, and Q&A sites. As much fun as it is to solve everything ourselves, sometimes you really just need to ask for help. Hopefully as you learn more about a particular package, you will also start to help others. And as we all know, the best way to master a subject is to teach it to someone else. -Ok, so maybe now you're thinking "but what if I end up using a package that's missing a feature that I realize that I need later?" That's where the beauty of the open-source community and the social coding movement come in. You can always make your own copy of a package and modify it to suit your needs (this is Github's "fork" feature). +Ok, so maybe now you're thinking "but what if I end up using a package that's missing a feature that I realize that I need later?" That's where the beauty of the open-source community and the social coding movement come in. You can always make your own copy of a package and modify it to suit your needs (this is Github's "fork" feature). -Of course at this point, the package is no longer a black box. You'll have to read through someone else's code in order to be able to modify it. But keep in mind that reading your *own* code from a few months prior can be just as difficult as reading someone else's - perhaps even moreso if their code is carefully documented and yours isn't. And of course, if you're the type that likes to give back, you can offer to merge your improvements into the main project repository (this is Github's "pull request" feature). +Of course at this point, the package is no longer a black box. You'll have to read through someone else's code in order to be able to modify it. But keep in mind that reading your *own* code from a few months prior can be just as difficult as reading someone else's - perhaps even more so if their code is carefully documented and yours isn't. And of course, if you're the type that likes to give back, you can offer to merge your improvements into the main project repository (this is Github's "pull request" feature). Hopefully I've convinced you by now that there's no real reason not to stand on the shoulders of others whenever possible. -It is, of course, important to pick the *right* packages. You want to choose packages that are well-maintained by an active community. This doesn't necessarily mean a large community - often a small but highly active community will be more productive than a large community that is swamped by feature requests, poor management, and more takers than givers. +It is, of course, important to pick the *right* packages. You want to choose packages that are well-maintained by an active community. This doesn't necessarily mean a large community - often a small but highly active community will be more productive than a large community that is swamped by feature requests, poor management, and more takers than givers. -In building UserFrosting, we have tried to collect what we believe are the best packages that the PHP community has to offer that are needed to build a basic web application. For functionality beyond the groundwork we've laid, your best bet is to carefully research your options before committing to a specific package. +In building UserFrosting, we have tried to collect what we believe are the best packages that the PHP community has to offer that are needed to build a basic web application. For functionality beyond the groundwork we've laid, your best bet is to carefully research your options before committing to a specific package. diff --git a/pages/02.background/05.security/01.server-misconfiguration/docs.md b/pages/02.background/05.security/01.server-misconfiguration/docs.md index 400be5075..a921a84b5 100644 --- a/pages/02.background/05.security/01.server-misconfiguration/docs.md +++ b/pages/02.background/05.security/01.server-misconfiguration/docs.md @@ -1,28 +1,27 @@ --- title: Server Misconfiguration metadata: - description: Server misconfiguration is one of the top 10 vulnerabilities of any web application, according to OWASP. Most of these misconfigurations occur because of inexperienced developers or system administrators, and are simple to fix. + description: Server misconfiguration is one of the top 10 vulnerabilities of any web application, according to OWASP. Most of these misconfigurations occur because of inexperienced developers or system administrators, and are simple to fix. taxonomy: category: docs --- -[plugin:content-inject](/modular/_update5.0) As we discussed in [The Client-Server Conversation](/background/the-client-server-conversation), it's important to distinguish between the code that is running on the server, and the response that it sends back to the client. -Many PHP developers are used to seeing server-side error messages and stack traces injected into the HTTP response, causing them to show up in their browsers automatically. In "plain PHP", this happens when PHP's `display_errors` directive in their PHP configuration file is set to `on`. Frameworks may do something similar, generating full debugging pages when something goes wrong in the developer's server-side code. +Many PHP developers are used to seeing server-side error messages and stack traces injected into the HTTP response, causing them to show up in their browsers automatically. In "plain PHP", this happens when PHP's `display_errors` directive in their PHP configuration file is set to `on`. Frameworks may do something similar, generating full debugging pages when something goes wrong in the developer's server-side code. -This is fine in development, and it makes the development cycle tighter by providing immediate feedback to the developer with a simple page refresh or click of a button. However in production (live server), this can lead to serious security breaches: +This is fine in development, and it makes the development cycle tighter by providing immediate feedback to the developer with a simple page refresh or click of a button. However in production (live server), this can lead to serious security breaches: ![Mysql password dumped to browser in PHP](/images/display-errors-on.png) -The lesson here is that code can contain sensitive information that we do not want to share with the end user - for example, passwords and API keys. If something goes wrong with the database connection code, it will generate a stack trace that contains the database credentials. By dumping this trace into the response, your application is risking making this information public. +The lesson here is that code can contain sensitive information that we do not want to share with the end user - for example, passwords and API keys. If something goes wrong with the database connection code, it will generate a stack trace that contains the database credentials. By dumping this trace into the response, your application is risking making this information public. -Therefore we want to keep a tight rein on what makes it into the response, and this means disabling response debugging in production. UserFrosting makes this easy to do with its `production` environment configuration mode. +Therefore we want to keep a tight rein on what makes it into the response, and this means disabling response debugging in production. UserFrosting makes this easy to do with its `production` environment configuration mode. -I should point out that there is a difference between *developer-facing* messages, and *user-facing* messages. User-facing messages are messages which are intended for the end user - things like "Please choose at least one owl" or "Sorry, your owlId is incorrect!" These are generally explicitly generated by your application, and can and should be sent in an HTTP response. +I should point out that there is a difference between *developer-facing* messages, and *user-facing* messages. User-facing messages are messages which are intended for the end user - things like "Please choose at least one owl" or "Sorry, your owlId is incorrect!" These are generally explicitly generated by your application, and can and should be sent in an HTTP response. -*Developer-facing* messages, on the other hand, should only be seen by developers and system administrators. These are things like the MySQL credentials error and stack trace we saw earlier. *These* are the types of messages we want to avoid injecting into our HTTP response. +*Developer-facing* messages, on the other hand, should only be seen by developers and system administrators. These are things like the MySQL credentials error and stack trace we saw earlier. *These* are the types of messages we want to avoid injecting into our HTTP response. In general, think of the HTTP response as a carefully crafted piece of content designed to be consumed in a specific way by the client - not a dump of every possible type of output that the server might generate. -Of course errors _do_ happen in production, and we need some way to deliver debugging and error messages to our tech team. This is typically handled with logging. By default UserFrosting [logs to files in production](/troubleshooting/debugging), but the [Monolog](https://github.com/Seldaek/monolog) logging package we use makes it easy to send error messages to email, databases, or other notification systems! +Of course errors _do_ happen in production, and we need some way to deliver debugging and error messages to our tech team. This is typically handled with logging. By default UserFrosting [logs to files in production](/troubleshooting/debugging), but the [Monolog](https://github.com/Seldaek/monolog) logging package we use makes it easy to send error messages to email, databases, or other notification systems! diff --git a/pages/02.background/05.security/docs.md b/pages/02.background/05.security/docs.md index baa2ba314..d0dbc3099 100644 --- a/pages/02.background/05.security/docs.md +++ b/pages/02.background/05.security/docs.md @@ -1,12 +1,11 @@ --- title: Security metadata: - description: It is essential to understand some basic security concepts before diving into web development. With an understanding of how the most common vulnerabilities work and some diligence in configuring your system, UserFrosting sets you up with an application that is robust against most common attack vectors. + description: It is essential to understand some basic security concepts before diving into web development. With an understanding of how the most common vulnerabilities work and some diligence in configuring your system, UserFrosting sets you up with an application that is robust against most common attack vectors. taxonomy: category: docs --- -[plugin:content-inject](/modular/_update5.0) It is essential to understand some basic security concepts before diving into web development. -If you aren't familiar with [OWASP](https://www.owasp.org/index.php/Main_Page), they are considered the authoritative source on web application security. Most of what we discuss in this section is covered in OWASP's [Top 10](https://www.owasp.org/index.php/Category:OWASP_Top_Ten_Project) list; nonetheless we paraphrase it here and discuss the strategies and features that UserFrosting offers to mitigate many of these vulnerabilities. +If you aren't familiar with [OWASP](https://www.owasp.org/index.php/Main_Page), they are considered the authoritative source on web application security. Most of what we discuss in this section is covered in OWASP's [Top 10](https://www.owasp.org/index.php/Category:OWASP_Top_Ten_Project) list; nonetheless we paraphrase it here and discuss the strategies and features that UserFrosting offers to mitigate many of these vulnerabilities. diff --git a/pages/02.background/06.seo/docs.md b/pages/02.background/06.seo/docs.md index a963bdf32..96ea3e13b 100644 --- a/pages/02.background/06.seo/docs.md +++ b/pages/02.background/06.seo/docs.md @@ -5,7 +5,6 @@ metadata: taxonomy: category: docs --- -[plugin:content-inject](/modular/_update5.0) Search Engine Optimization (SEO) is an integral part of the design and development process. Getting the public side of your website to rank well in search results should be something you consider from the very beginning, and not an afterthought once you're getting ready to deploy. @@ -66,17 +65,17 @@ Make your image files exactly the size at which you intend to display them (in s ### Use compiled assets in production -The way UserFrosting [serves raw assets](/asset-management/basic-usage) is great for development and debugging, but not so much for production. Each asset comes with the usual [round trip overhead](https://en.wikipedia.org/wiki/Handshaking#TCP_three-way_handshake) of an HTTP request. On top of that, raw assets are served through the underlying Slim application, which adds a considerable amount of overhead with each request. Finally, the asset files themselves (Javascript and CSS) are larger than they need to be to perform their function. +The way UserFrosting [serves assets](/asset-management) is great for development and debugging, but not so much for production. The asset files themselves (Javascript and CSS) are larger than they need to be to perform their function. -Using UserFrosting's `uf-bundle-build` and `uf-bundle` commands solves all three of these problems: +Using Webpack solves all of these problems: 1. It **minifies** your Javascript and CSS files, making files smaller by making variable names shorter and removing comments and whitespace; 2. It **concatenates** Javascript and CSS files, reducing the number of requests needed by the page; -3. It copies the assets to the `public/` directory, so that they can be served directly by your webserver instead of going through the Slim application lifecycle. +3. It copies the assets to the `public/` directory, so that they can be served directly by your webserver instead of going through the application lifecycle. ### Caching -Caching should happen on a number of levels throughout your application, on both the server and client sides. On the server, UserFrosting automatically caches route resolutions and fully-rendered Twig templates when you use the `production` configuration profile. You can also configure the webserver itself to cache entire responses. For example, see [nginx's caching documentation](https://www.nginx.com/resources/admin-guide/content-caching/). +[Caching](/advanced/caching/intro) should happen on a number of levels throughout your application, on both the server and client sides. On the server, UserFrosting automatically caches route resolutions and fully-rendered Twig templates when you use the `production` configuration profile. You can also configure the webserver itself to cache entire responses. For example, see [nginx's caching documentation](https://www.nginx.com/resources/admin-guide/content-caching/). Caching can also happen in the client's browser. For example, you don't want the client to have to retrieve images and Javascript files each time they visit your page, if those assets haven't changed since their last visit. Browser caching is handled by the `Cache-Control` response header, which is the server's way of telling the client's browser how long they should cache the response of a particular request. @@ -99,7 +98,7 @@ Nowadays search engines still take links into account, but they are careful to e 1. The [domain authority](https://en.wikipedia.org/wiki/Domain_Authority) of the linking site; 2. The [anchor text](https://moz.com/learn/seo/anchor-text) of the link; 3. The relevance of the linking page's content to the content of your page; -4. The prominance of the link on the linking page (position, number of other links, etc). +4. The prominence of the link on the linking page (position, number of other links, etc). All in all, this means you should focus on getting **good** links to your site, rather than **many** links. diff --git a/pages/02.background/chapter.md b/pages/02.background/chapter.md index b3e97d1fc..8732c0872 100644 --- a/pages/02.background/chapter.md +++ b/pages/02.background/chapter.md @@ -5,12 +5,11 @@ metadata: taxonomy: category: docs --- -[plugin:content-inject](/modular/_update5.0) #### Chapter 2 # Web Dev, the Right Way -UserFrosting has a not-so-secret ulterior motive: to get you to become a better developer. +UserFrosting has a not-so-secret ulterior motive: **to get you to become a better developer**. In this chapter, we'll talk about the state of modern web development tools and practices, and clear up some common misconceptions about how web applications actually work. Then, we'll go over key security concepts. Finally, we'll discuss best practices to make sure that users will be able to find and use your application when it's finished. diff --git a/pages/04.installation/01.requirements/02.essential-tools-for-php/docs.md b/pages/04.installation/01.requirements/02.essential-tools-for-php/docs.md index 201e90963..d2a02e1aa 100644 --- a/pages/04.installation/01.requirements/02.essential-tools-for-php/docs.md +++ b/pages/04.installation/01.requirements/02.essential-tools-for-php/docs.md @@ -6,7 +6,7 @@ taxonomy: category: docs --- -On the previous page, we saw the softwares required to run UserFrosting. Now it's time to look at tools you'll need during development to build your UserFrosting application. Theses tools are not strictly required to be installed on your production server, which we'll cover in a [later chapter](/going-live). +On the previous page, we saw the softwares required to run UserFrosting. Now it's time to look at tools you'll need during development to build your UserFrosting application. These tools are not strictly required to be installed on your production server, which we'll cover in a [later chapter](/going-live). During development, and before you're ready to deploy, you'll want to have the following tools installed: @@ -72,3 +72,23 @@ Other popular IDE includes : - [Eclipse](https://projects.eclipse.org/projects/tools.pdt) - [Komodo](https://www.activestate.com/products/komodo-ide/) - Etc. + +### (Optional) Database GUI + +In the past, PhpMyAdmin was the *de facto* tool used to view and edit databases content. It still "does the job", but can be hard to setup (unless you do through Docker!) and proper GUI desktop apps are much nicer to use for most database stuff. Desktop app can be useful to experiment with queries in a nice editor, can display your tables structure visually, allow you to save your query scripts to files, etc. + +Popular database GUI app includes : +- [Table Plus](https://tableplus.com) - A free perpetual trial is available +- [MySQL Workbench](https://www.mysql.com/products/workbench/) +- [DBeaver](https://dbeaver.io) + +### Other optional tools + +These tools are optional, but can be useful for any serious developer: + +- [PHP Intelephense](https://intelephense.com) - plugin for most editors that provides an essential set of code intelligence features for a productive and rich PHP development experience. +- [PHP-CS-Fixer](https://github.com/PHP-CS-Fixer/PHP-CS-Fixer) - fixes your code to follow standards +- [PHPStan](https://phpstan.org) - scans your whole codebase and looks for both obvious & tricky bugs +- [XDebug](https://xdebug.org) - an extension for PHP, and provides a range of features to improve the PHP development experience, like step debugging +- [Postman](https://www.postman.com) - API platform useful to build and debug REST API; +- [GitHub Copilot](https://github.com/features/copilot) - AI powered autocompletion for VSCode diff --git a/pages/04.installation/02.environment/02.docker/docs.md b/pages/04.installation/02.environment/02.docker/docs.md index d15c7429f..43e1efdf3 100644 --- a/pages/04.installation/02.environment/02.docker/docs.md +++ b/pages/04.installation/02.environment/02.docker/docs.md @@ -131,7 +131,7 @@ And then start the installation process again. At the heart of everything is the `docker-compose.yml` file. If you're experienced with Docker and Docker compose, this is where you can customize your Docker experience. For example, you can customize the port each service runs on. And since the file is located in *your Sprinkle*, aka your app, it's possible to save this file in your repo. -The `docker-compose.yml` file also contain the MySQL database and Mail environment variables. Since theses variables are defined globally inside the container, they don't need to be redefined inside `.env` file. +The `docker-compose.yml` file also contain the MySQL database and Mail environment variables. Since these variables are defined globally inside the container, they don't need to be redefined inside `.env` file. [notice=warning]If you have **two** instances of UserFrosting on your computer, **they will share the same config**. This means a couple of things: diff --git a/pages/04.installation/02.environment/docs.md b/pages/04.installation/02.environment/docs.md index 09807c8f5..a9652d0e1 100644 --- a/pages/04.installation/02.environment/docs.md +++ b/pages/04.installation/02.environment/docs.md @@ -16,3 +16,5 @@ The links below will guide you to the right installation guide for you, which ca - [I don't have a local environment - I want the easiest solution](/installation/environment/docker) - [I have a local environment set up already, I'll do everything myself](/installation/environment/native/install) - [I'm familiar with *Docker*, let's use that](/installation/environment/docker#get-userfrosting) + +[notice=warning]There are a number of "one-click" installers available, which can set up your machine with a complete web application stack in just a few minutes: **XAMPP**, **MAMP**, **WampServer**, etc. **These are not officially supported by UserFrosting and we do not recommend using them.** For "one-click" dev environment, we recommend **Docker**.[/notice] \ No newline at end of file diff --git a/pages/06.sprinkles/03.recipe/docs.md b/pages/06.sprinkles/03.recipe/docs.md index fcfb8c369..a740f3ba9 100644 --- a/pages/06.sprinkles/03.recipe/docs.md +++ b/pages/06.sprinkles/03.recipe/docs.md @@ -139,7 +139,7 @@ public function getRoutes(): array ### Services -Return an array of services definitions. Theses will be explored in [Chapter 7 - Dependency Injection](/dependency-injection) +Return an array of services definitions. These will be explored in [Chapter 7 - Dependency Injection](/dependency-injection) Example: ```php diff --git a/pages/08.routes-and-controllers/03.front-controller/docs.md b/pages/08.routes-and-controllers/03.front-controller/docs.md index 7747bd86a..8316d41ee 100644 --- a/pages/08.routes-and-controllers/03.front-controller/docs.md +++ b/pages/08.routes-and-controllers/03.front-controller/docs.md @@ -32,7 +32,7 @@ This is a very simplified example, but it illustrates the main features of a rou The first parameter is the url for the route. Routes can contain placeholders, such as `{username}` to match arbitrary values in a portion of the url. These placeholders can even be matched according to regular expressions. See the [Slim documentation ](https://www.slimframework.com/docs/v4/objects/routing.html#route-placeholders) for a complete guide to url placeholders. -After the url comes the **closure**, where we place our actual route logic. In this example, the closure uses three parameters - the **placeholder** variable, the **request** object (which contains all the information from the client request) and the **response** object (which is used to build the response that the server sends back to the client). Theses parameters can vary from routes to routes. Behind the scenes, PHP-DI will intelligently inject the proper services and variables into the closure, more on that in a bit. +After the url comes the **closure**, where we place our actual route logic. In this example, the closure uses three parameters - the **placeholder** variable, the **request** object (which contains all the information from the client request) and the **response** object (which is used to build the response that the server sends back to the client). These parameters can vary from routes to routes. Behind the scenes, PHP-DI will intelligently inject the proper services and variables into the closure, more on that in a bit. In the example above, we use the `username` placeholder to look up information for that user from the database. We then use the value of the `format` query parameter from the request, to decide what to put in the response. You'll notice that the closure writes to the body of the `$response` object before returning. Slim will return the response to the client, perhaps modifying it further through the use of [middleware](https://www.slimframework.com/docs/v4/concepts/middleware.html) first. diff --git a/pages/08.routes-and-controllers/04.controller-classes/docs.md b/pages/08.routes-and-controllers/04.controller-classes/docs.md index 291c82fe9..41044ce2e 100644 --- a/pages/08.routes-and-controllers/04.controller-classes/docs.md +++ b/pages/08.routes-and-controllers/04.controller-classes/docs.md @@ -85,7 +85,7 @@ class OwlController } ``` -[notice=tip]The `Response` and `Request` service are not required to be injected into the method. While most of the time the `Response` is required to write to the page (except when throwing an exception, for example), the `Request` might not always be useful. In theses cases, it's perfectly fine to omit it.[/notice] +[notice=tip]The `Response` and `Request` service are not required to be injected into the method. While most of the time the `Response` is required to write to the page (except when throwing an exception, for example), the `Request` might not always be useful. In these cases, it's perfectly fine to omit it.[/notice] When writing controllers, which often handles multiple routes, sometimes service needs to be shared between methods. Those can be injected into the class constructor instead of each individual methods, and will be properly injected : diff --git a/pages/11.cli/01.commands/docs.md b/pages/11.cli/01.commands/docs.md index 9a2ab1496..312b6d153 100644 --- a/pages/11.cli/01.commands/docs.md +++ b/pages/11.cli/01.commands/docs.md @@ -123,12 +123,12 @@ $ php bakery locale:compare [options] ``` This command is interactive, which mean it will ask for which locales to compare. Options can also be used to automatically compare the two locales without user interaction (See the table below for the list of available options). - +à This command will display : - Comparison between _Right_ and _Left_ locales : Returns al list of all differences in both locales using [`array_diff_assoc`](https://www.php.net/manual/en/function.array-diff-assoc.php). This can be used to compare the two locales. - Missing keys from _Right_ found in _Left_ : This can be used to see which keys are missing in the _Right_ locale, but that can be found in the _Left_ locale, so they can be added. - Same values found in both _Left_ and _Right_ locale : This can be used to find strings in the _right_ locale that is the same in the _left_ locale. When two locale have the same string value, it may means the string is not translated in the _right_ locale. - - Empty values for _Right_ locale : List keys with empty string for the _right_ locale. Theses strings might need to be filled in. + - Empty values for _Right_ locale : List keys with empty string for the _right_ locale. These strings might need to be filled in. | Option | Description | | ----------------- | ----------------------------------------------------- | diff --git a/pages/13.asset-management/01.webpack-encore/docs.md b/pages/13.asset-management/01.webpack-encore/docs.md index a976cf4fc..9bb18c1b1 100644 --- a/pages/13.asset-management/01.webpack-encore/docs.md +++ b/pages/13.asset-management/01.webpack-encore/docs.md @@ -55,11 +55,11 @@ Where Composer has it's `composer.json` file to defines the project dependencies } ``` -1. **dependencies** : Theses are the client dependencies, which are will eventually be passed to the Browser. For example, _JQuery_ is a dependencies, as it will be used by the browser; -2. **devDependencies** : Theses are CLI dependencies. They are required to run the building process; +1. **dependencies** : These are the client dependencies, which are will eventually be passed to the Browser. For example, _JQuery_ is a dependencies, as it will be used by the browser; +2. **devDependencies** : These are CLI dependencies. They are required to run the building process; 3. **scripts** : npm command alias for dependencies commands. -In the example above, you can see both the *Admin Sprinkle* and *AdminLTE Theme* are included as dependencies. While theses are also included by Composer, it's necessary to include them also here, so their assets can be accessed by npm and Webpack Encore. The dev dependencies includes, among others, Webpack Encore. It will then be installed when running `npm install`. Finally, the *scripts* section expose the encore build tasks. +In the example above, you can see both the *Admin Sprinkle* and *AdminLTE Theme* are included as dependencies. While these are also included by Composer, it's necessary to include them also here, so their assets can be accessed by npm and Webpack Encore. The dev dependencies includes, among others, Webpack Encore. It will then be installed when running `npm install`. Finally, the *scripts* section expose the encore build tasks. Dependencies installation will be automatically handled by the `php bakery bake` command. Alternatively, you can still uses the typical npm commands from the command line: diff --git a/pages/14.database/03.migrations/docs.md b/pages/14.database/03.migrations/docs.md index 378aa1f2b..e39b1e0ad 100644 --- a/pages/14.database/03.migrations/docs.md +++ b/pages/14.database/03.migrations/docs.md @@ -156,7 +156,7 @@ As for the `down` method, it simply tells the database structure to delete the t ## Dependencies -An important aspect of migrations is **data consistency**. Since migrations are like recipes used to create a database, the order in which theses migrations are executed is very important. You don't want to drop those cupcakes in the oven before mixing the flour and eggs, the same way you don't want to add a column to a table before said table is created! UserFrosting uses **dependencies** to make sure migrations are run in the correct order. +An important aspect of migrations is **data consistency**. Since migrations are like recipes used to create a database, the order in which these migrations are executed is very important. You don't want to drop those cupcakes in the oven before mixing the flour and eggs, the same way you don't want to add a column to a table before said table is created! UserFrosting uses **dependencies** to make sure migrations are run in the correct order. Some situations require a more complex way to make sure migrations are run in the correct order. This is the case when a Sprinkle requires that a migration from another Sprinkle is executed before its own migration. It can also be the case when two tables inside the same Sprinkle are dependent on one another. diff --git a/pages/17.i18n/01.introduction/docs.md b/pages/17.i18n/01.introduction/docs.md index 1127fbcc6..bfd7ae074 100644 --- a/pages/17.i18n/01.introduction/docs.md +++ b/pages/17.i18n/01.introduction/docs.md @@ -56,7 +56,7 @@ return [ ]; ``` -This information is stored in **languages files**. Theses are normal PHP files typically located in `app/sprinkles/{sprinkleName}/locale/{locale}/messages.php` and grouped into folders named after the locale code, as pictured below. Each locale can have as many files as needed (eg. `messages.php`, `foo.php`, `bar.php`, etc.) for easier maintenance. Those files will be merged together at runtime to create a **compiled dictionary** of all the keys available for the translator to use. +This information is stored in **languages files**. These are normal PHP files typically located in `app/sprinkles/{sprinkleName}/locale/{locale}/messages.php` and grouped into folders named after the locale code, as pictured below. Each locale can have as many files as needed (eg. `messages.php`, `foo.php`, `bar.php`, etc.) for easier maintenance. Those files will be merged together at runtime to create a **compiled dictionary** of all the keys available for the translator to use. **locale/es_ES/example.php** diff --git a/pages/17.i18n/03.translator/docs.md b/pages/17.i18n/03.translator/docs.md index 8beafba2a..6d1b121de 100644 --- a/pages/17.i18n/03.translator/docs.md +++ b/pages/17.i18n/03.translator/docs.md @@ -95,7 +95,7 @@ $this->translator->translate("HUNGRY_CATS", 5); $this->translator->translate("HUNGRY_CATS", ['plural' => 5]); ``` -If no placeholder value is defined, `1` will be used by default. For example, theses will return the same result : +If no placeholder value is defined, `1` will be used by default. For example, these will return the same result : ```php $this->translator->translate("HUNGRY_CATS"); diff --git a/pages/17.i18n/04.custom-locale/docs.md b/pages/17.i18n/04.custom-locale/docs.md index 7d3a358b8..4603b3d14 100644 --- a/pages/17.i18n/04.custom-locale/docs.md +++ b/pages/17.i18n/04.custom-locale/docs.md @@ -10,7 +10,7 @@ Whether to add an unsupported language (Klingon anyone?), to create a new dialec Two things required to make a new locale available in UserFrosting. The first it to create a **locale configuration file**. The second is to add your locale identifier to the available locale config. While the second part should be pretty straitfoward at this point, the locale file has some require information it need to provide for your new locale to work. -Theses informations need to be stored in a `locale.yaml` file, located in the locale folder and accessible accessible using the `locale://XX_YY/locale.yaml` URI, where `XX_YY` is your locale **language-country** code. +These information need to be stored in a `locale.yaml` file, located in the locale folder and accessible accessible using the `locale://XX_YY/locale.yaml` URI, where `XX_YY` is your locale **language-country** code. The configuration file can contain multiple options. For example, to create a French Canadian (fr_CA) locale : diff --git a/pages/18.advanced/08.locator/docs.md b/pages/18.advanced/08.locator/docs.md index 8da82bfb7..a6b054eee 100644 --- a/pages/18.advanced/08.locator/docs.md +++ b/pages/18.advanced/08.locator/docs.md @@ -117,7 +117,7 @@ $this->locator->getResource('schema://default.json'); // 'app/sprinkles/MySite/schema/default.json', ``` -The locator will return an instance of the `Resource` object (or an array of `Resource` objects). Theses objects can be cast as string and will return the absolute path to the resource (file or directory). Further [public methods](https://github.com/userfrosting/framework/tree/5.0/src/UniformResourceLocator/docs#resource-instance) can be used on the Resource object to get more information about the returned resource. For example, to return the sprinkle name where it was found : +The locator will return an instance of the `Resource` object (or an array of `Resource` objects). These objects can be cast as string and will return the absolute path to the resource (file or directory). Further [public methods](https://github.com/userfrosting/framework/tree/5.0/src/UniformResourceLocator/docs#resource-instance) can be used on the Resource object to get more information about the returned resource. For example, to return the sprinkle name where it was found : ```php $schema = $this->locator->getResource('schema://default.json'); @@ -127,7 +127,7 @@ echo $schema->getLocation()->getName(); // 'MySite' ``` -Note theses methods can also work on directories URI : +Note these methods can also work on directories URI : ```php $this->locator->getResources('schema://foo'); diff --git a/pages/18.advanced/11.events/docs.md b/pages/18.advanced/11.events/docs.md index ef7cec21d..6419db0a8 100644 --- a/pages/18.advanced/11.events/docs.md +++ b/pages/18.advanced/11.events/docs.md @@ -11,7 +11,7 @@ UserFrosting makes uses of *Event Dispatching* to enable customization of some b 3. User is authenticated, i.e. it's password is verified 4. User is written to the session, ready to be used on subsequent requests -It's understandable that your would want to step in during this process that is the core feature of UserFrosting to implement an additional step specific to your project. That is why after step #2 is done, the `UserValidatedEvent` event will be dispatched, after step #3, `UserAuthenticatedEvent` event will be dispatched, and after step #4, the `UserLoggedInEvent` event will be dispatched. Each sprinkle can intercept theses events and act upon then to change the default behavior. For example, the `UserLoggedInEvent` could be intercept to log the user activity. +It's understandable that your would want to step in during this process that is the core feature of UserFrosting to implement an additional step specific to your project. That is why after step #2 is done, the `UserValidatedEvent` event will be dispatched, after step #3, `UserAuthenticatedEvent` event will be dispatched, and after step #4, the `UserLoggedInEvent` event will be dispatched. Each sprinkle can intercept these events and act upon then to change the default behavior. For example, the `UserLoggedInEvent` could be intercept to log the user activity. The process of intercepting events and acting upon them is called **listening** to events through an **Event Dispatcher**. The [PSR-14 Standard](https://www.php-fig.org/psr/psr-14/) defines each part of an event dispatching system like this : @@ -175,7 +175,7 @@ php bakery debug:events ## Built-in events -Theses are the events the Framework and default sprinkles uses. You can easily listen to them in your Sprinkle to customize the behavior of the built-in sprinkle. +These are the events the Framework and default sprinkles uses. You can easily listen to them in your Sprinkle to customize the behavior of the built-in sprinkle. | Event | Description | |------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------| diff --git a/pages/20.recipes/06.advanced-tutorial/06.custom-namespace/docs.md b/pages/20.recipes/06.advanced-tutorial/06.custom-namespace/docs.md index 5ee29b379..ac22cac2d 100644 --- a/pages/20.recipes/06.advanced-tutorial/06.custom-namespace/docs.md +++ b/pages/20.recipes/06.advanced-tutorial/06.custom-namespace/docs.md @@ -53,7 +53,7 @@ You can now find and replace every reference of `UserFrosting\App\` for `UserFro ## Cleanup unused code -The Skeleton comes with some default pages and code we won't necessary need. Theses files and directory can (***optionally***) be safely deleted : +The Skeleton comes with some default pages and code we won't necessary need. These files and directory can (***optionally***) be safely deleted : - `app/assets/images/` - `app/src/Bakery/` diff --git a/pages/22.upgrading/01.46-to-50/02.guide/docs.md b/pages/22.upgrading/01.46-to-50/02.guide/docs.md index 5680cbaf5..8d35250b8 100644 --- a/pages/22.upgrading/01.46-to-50/02.guide/docs.md +++ b/pages/22.upgrading/01.46-to-50/02.guide/docs.md @@ -123,7 +123,7 @@ Remember, this guide will give you only the big picture of what changed, pointin ### Global changes -It's important to note some changes have been applied at large, and affect pretty much every PHP class, based on PHP 8 new features. Theses changes include: +It's important to note some changes have been applied at large, and affect pretty much every PHP class, based on PHP 8 new features. These changes include: - Extensive use of type declaration and [return types](https://dev.to/karleb/return-types-in-php-3fip) - [Named Arguments](https://www.php.net/releases/8.0/en.php#named-arguments) @@ -131,7 +131,7 @@ It's important to note some changes have been applied at large, and affect prett - [Union type](https://www.php.net/releases/8.0/en.php#union-types) - [Etc.](https://www.php.net/releases/8.0/en.php) -Keep this in mind, especially if you've extended built-in classes. Not only may theses classes been renamed or moved, the method declaration might have changed even if the code of theses method haven't. +Keep this in mind, especially if you've extended built-in classes. Not only may these classes been renamed or moved, the method declaration might have changed even if the code of these method haven't. ### Services -> Dependency Injection