diff --git a/user_guide_src/source/images/tutorial9.png b/user_guide_src/source/images/tutorial9.png
deleted file mode 100644
index 39986162c65b..000000000000
Binary files a/user_guide_src/source/images/tutorial9.png and /dev/null differ
diff --git a/user_guide_src/source/tutorial/create_news_items.rst b/user_guide_src/source/tutorial/create_news_items.rst
index 2c49a17c2f0a..4ed6badbae07 100644
--- a/user_guide_src/source/tutorial/create_news_items.rst
+++ b/user_guide_src/source/tutorial/create_news_items.rst
@@ -3,7 +3,7 @@ Create News Items
.. contents::
:local:
- :depth: 2
+ :depth: 3
You now know how you can read data from a database using CodeIgniter, but
you haven't written any information to the database yet. In this section,
@@ -29,33 +29,17 @@ You can read more about the CSRF protection in :doc:`Security <../libraries/secu
Create a Form
*************
-View
-====
+Create news/create View File
+============================
To input data into the database, you need to create a form where you can
input the information to be stored. This means you'll be needing a form
with two fields, one for the title and one for the text. You'll derive
-the slug from our title in the model. Create a new view at
-**app/Views/news/create.php**::
+the slug from our title in the model.
-
= esc($title) ?>
+Create a new view at **app/Views/news/create.php**:
- = session()->getFlashdata('error') ?>
- = validation_list_errors() ?>
-
-
+.. literalinclude:: create_news_items/006.php
There are probably only four things here that look unfamiliar.
@@ -72,43 +56,61 @@ The :php:func:`csrf_field()` function creates a hidden input with a CSRF token t
The :php:func:`set_value()` function provided by the :doc:`../helpers/form_helper` is used to show
old input data when errors occur.
-Controller
-==========
+News Controller
+===============
+
+Go back to your ``News`` controller.
+
+Add News::new() to Display the Form
+-----------------------------------
-Go back to your **News** controller. You're going to do two things here,
-check whether the form was submitted and whether the submitted data
-passed the validation rules.
-You'll use the :ref:`validation method in Controller ` to do this.
+First, create a method to display the HTML form you have created.
.. literalinclude:: create_news_items/002.php
-The code above adds a lot of functionality.
+We load the :doc:`Form helper <../helpers/form_helper>` with the
+:php:func:`helper()` function. Most helper functions require the helper to be
+loaded before use.
+
+Then it returns the created form view.
+
+Add News::create() to Create a News Item
+----------------------------------------
-First we load the :doc:`Form helper <../helpers/form_helper>` with the :php:func:`helper()` function.
-Most helper functions require the helper to be loaded before use.
+Next, create a method to create a news item from the submitted data.
-Next, we check if we deal with the **POST** request with the
-:doc:`IncomingRequest <../incoming/incomingrequest>` object ``$this->request``.
-It is set in the controller by the framework.
-The :ref:`IncomingRequest::is() ` method checks the type of the request.
-Since the route for **create()** endpoint handles both: **GET** and **POST** requests we can safely assume that if the request is not POST then it is a GET type.
-the form is loaded and returned to display.
+You're going to do three things here:
-Then, we get the necessary items from the POST data by the user and set them in the ``$post`` variable.
-We also use the :doc:`IncomingRequest <../incoming/incomingrequest>` object ``$this->request``.
+1. checks whether the submitted data passed the validation rules.
+2. saves the news item to the database.
+3. returns a success page.
+
+.. literalinclude:: create_news_items/005.php
+
+The code above adds a lot of functionality.
-After that, the Controller-provided helper function :ref:`validateData() `
-is used to validate ``$post`` data.
+Validate the Data
+^^^^^^^^^^^^^^^^^
+
+You'll use the Controller-provided helper function :ref:`validate() ` to validate the submitted data.
In this case, the title and body fields are required and in the specific length.
CodeIgniter has a powerful validation library as demonstrated
above. You can read more about the :doc:`Validation library <../libraries/validation>`.
-If the validation fails, the form is loaded and returned to display.
+If the validation fails, we call the ``new()`` method you just created and return
+the HTML form.
+
+Save the News Item
+^^^^^^^^^^^^^^^^^^
+
+If the validation passed all the rules, we get the validated data by
+:ref:`$this->validator->getValidated() ` and
+set them in the ``$post`` variable.
-If the validation passed all the rules, the **NewsModel** is loaded and called. This
-takes care of passing the news item into the model. The :ref:`model-save` method handles
-inserting or updating the record automatically, based on whether it finds an array key
-matching the primary key.
+The ``NewsModel`` is loaded and called. This takes care of passing the news item
+into the model. The :ref:`model-save` method handles inserting or updating the
+record automatically, based on whether it finds an array key matching the primary
+key.
This contains a new function :php:func:`url_title()`. This function -
provided by the :doc:`URL helper <../helpers/url_helper>` - strips down
@@ -116,26 +118,29 @@ the string you pass it, replacing all spaces by dashes (``-``) and makes
sure everything is in lowercase characters. This leaves you with a nice
slug, perfect for creating URIs.
-After this, view files are loaded and returned to display a success message. Create a view at
-**app/Views/news/success.php** and write a success message.
+Return Success Page
+^^^^^^^^^^^^^^^^^^^
+
+After this, view files are loaded and returned to display a success message.
+Create a view at **app/Views/news/success.php** and write a success message.
This could be as simple as::
News item created successfully.
-Model Updating
-**************
+NewsModel Updating
+******************
The only thing that remains is ensuring that your model is set up
to allow data to be saved properly. The ``save()`` method that was
used will determine whether the information should be inserted
or if the row already exists and should be updated, based on the presence
of a primary key. In this case, there is no ``id`` field passed to it,
-so it will insert a new row into it's table, **news**.
+so it will insert a new row into it's table, ``news``.
However, by default the insert and update methods in the Model will
not actually save any data because it doesn't know what fields are
-safe to be updated. Edit the **NewsModel** to provide it a list of updatable
+safe to be updated. Edit the ``NewsModel`` to provide it a list of updatable
fields in the ``$allowedFields`` property.
.. literalinclude:: create_news_items/003.php
@@ -146,19 +151,28 @@ never need to do that, since it is an auto-incrementing field in the database.
This helps protect against Mass Assignment Vulnerabilities. If your model is
handling your timestamps, you would also leave those out.
-Routing
-*******
+Adding Routing Rules
+********************
Before you can start adding news items into your CodeIgniter application
you have to add an extra rule to **app/Config/Routes.php** file. Make sure your
-file contains the following. This makes sure CodeIgniter sees ``create()``
-as a method instead of a news item's slug. You can read more about different
-routing types in :doc:`../incoming/routing`.
+file contains the following:
.. literalinclude:: create_news_items/004.php
+The route directive for ``'news/new'`` is placed before the directive for ``'news/(:segment)'`` to ensure that the form to create a news item is displayed.
+
+The ``$routes->post()`` line defines the router for a POST request. It matches
+only a POST request to the URI path **/news**, and it maps to the ``create()`` method of
+the ``News`` class.
+
+You can read more about different routing types in :ref:`defined-route-routing`.
+
+Create a News Item
+******************
+
Now point your browser to your local development environment where you
-installed CodeIgniter and add ``/news/create`` to the URL.
+installed CodeIgniter and add **/news/create** to the URL.
Add some news and check out the different pages you made.
.. image:: ../images/tutorial3.png
@@ -176,9 +190,29 @@ Congratulations
You just completed your first CodeIgniter4 application!
-The image underneath shows your project's **app** folder,
-with all of the files that you created in red.
-The two modified configuration files (**Config/Routes.php** & **Config/Filters.php**) are not shown.
-
-.. image:: ../images/tutorial9.png
- :align: left
+The diagram underneath shows your project's **app** folder, with all of the
+files that you created or modified.
+
+.. code-block:: none
+
+ app/
+ ├── Config
+ │ ├── Filters.php (Modified)
+ │ └── Routes.php (Modified)
+ ├── Controllers
+ │ ├── News.php
+ │ └── Pages.php
+ ├── Models
+ │ └── NewsModel.php
+ └── Views
+ ├── news
+ │ ├── create.php
+ │ ├── index.php
+ │ ├── success.php
+ │ └── view.php
+ ├── pages
+ │ ├── about.php
+ │ └── home.php
+ └── templates
+ ├── footer.php
+ └── header.php
diff --git a/user_guide_src/source/tutorial/create_news_items/002.php b/user_guide_src/source/tutorial/create_news_items/002.php
index be1ad6a54836..0b196dfa7245 100644
--- a/user_guide_src/source/tutorial/create_news_items/002.php
+++ b/user_guide_src/source/tutorial/create_news_items/002.php
@@ -3,46 +3,18 @@
namespace App\Controllers;
use App\Models\NewsModel;
+use CodeIgniter\Exceptions\PageNotFoundException;
class News extends BaseController
{
// ...
- public function create()
+ public function new()
{
helper('form');
- // Checks whether the form is submitted.
- if (! $this->request->is('post')) {
- // The form is not submitted, so returns the form.
- return view('templates/header', ['title' => 'Create a news item'])
- . view('news/create')
- . view('templates/footer');
- }
-
- $post = $this->request->getPost(['title', 'body']);
-
- // Checks whether the submitted data passed the validation rules.
- if (! $this->validateData($post, [
- 'title' => 'required|max_length[255]|min_length[3]',
- 'body' => 'required|max_length[5000]|min_length[10]',
- ])) {
- // The validation fails, so returns the form.
- return view('templates/header', ['title' => 'Create a news item'])
- . view('news/create')
- . view('templates/footer');
- }
-
- $model = model(NewsModel::class);
-
- $model->save([
- 'title' => $post['title'],
- 'slug' => url_title($post['title'], '-', true),
- 'body' => $post['body'],
- ]);
-
return view('templates/header', ['title' => 'Create a news item'])
- . view('news/success')
+ . view('news/create')
. view('templates/footer');
}
}
diff --git a/user_guide_src/source/tutorial/create_news_items/004.php b/user_guide_src/source/tutorial/create_news_items/004.php
index 3de06f181d29..6b04f3c66ffd 100644
--- a/user_guide_src/source/tutorial/create_news_items/004.php
+++ b/user_guide_src/source/tutorial/create_news_items/004.php
@@ -5,10 +5,10 @@
use App\Controllers\News;
use App\Controllers\Pages;
-$routes->match(['get', 'post'], 'news/create', [News::class, 'create']);
-$routes->get('news/(:segment)', [News::class, 'view']);
$routes->get('news', [News::class, 'index']);
+$routes->get('news/new', [News::class, 'new']); // Add this line
+$routes->post('news', [News::class, 'create']); // Add this line
+$routes->get('news/(:segment)', [News::class, 'show']);
+
$routes->get('pages', [Pages::class, 'index']);
$routes->get('(:segment)', [Pages::class, 'view']);
-
-// ...
diff --git a/user_guide_src/source/tutorial/create_news_items/005.php b/user_guide_src/source/tutorial/create_news_items/005.php
new file mode 100644
index 000000000000..6d565789141a
--- /dev/null
+++ b/user_guide_src/source/tutorial/create_news_items/005.php
@@ -0,0 +1,40 @@
+validate([
+ 'title' => 'required|max_length[255]|min_length[3]',
+ 'body' => 'required|max_length[5000]|min_length[10]',
+ ])) {
+ // The validation fails, so returns the form.
+ return $this->new();
+ }
+
+ // Gets the validated data.
+ $post = $this->validator->getValidated();
+
+ $model = model(NewsModel::class);
+
+ $model->save([
+ 'title' => $post['title'],
+ 'slug' => url_title($post['title'], '-', true),
+ 'body' => $post['body'],
+ ]);
+
+ return view('templates/header', ['title' => 'Create a news item'])
+ . view('news/success')
+ . view('templates/footer');
+ }
+}
diff --git a/user_guide_src/source/tutorial/create_news_items/006.php b/user_guide_src/source/tutorial/create_news_items/006.php
new file mode 100644
index 000000000000..b19bbfe9b2c5
--- /dev/null
+++ b/user_guide_src/source/tutorial/create_news_items/006.php
@@ -0,0 +1,18 @@
+
= esc($title) ?>
+
+= session()->getFlashdata('error') ?>
+= validation_list_errors() ?>
+
+
diff --git a/user_guide_src/source/tutorial/index.rst b/user_guide_src/source/tutorial/index.rst
index 85675764eceb..830ab6568f9a 100644
--- a/user_guide_src/source/tutorial/index.rst
+++ b/user_guide_src/source/tutorial/index.rst
@@ -76,7 +76,7 @@ Setting Development Mode
By default, CodeIgniter starts up in production mode. This is a safety feature
to keep your site a bit more secure in case settings are messed up once it is live.
-So first let's fix that. Copy or rename the ``env`` file to ``.env``. Open it up.
+So first let's fix that. Copy or rename the **env** file to **.env**. Open it up.
This file contains server-specific settings. This means you never will need to
commit any sensitive information to your version control system. It includes
diff --git a/user_guide_src/source/tutorial/news_section.rst b/user_guide_src/source/tutorial/news_section.rst
index 9fa090701f67..183b2f0c8570 100644
--- a/user_guide_src/source/tutorial/news_section.rst
+++ b/user_guide_src/source/tutorial/news_section.rst
@@ -51,7 +51,7 @@ The seed records might be something like::
Connect to Your Database
************************
-The local configuration file, ``.env``, that you created when you installed
+The local configuration file, **.env**, that you created when you installed
CodeIgniter, should have the database property settings uncommented and
set appropriately for the database you want to use. Make sure you've configured
your database properly as described in :doc:`../database/configuration`::
@@ -71,7 +71,10 @@ are the place where you retrieve, insert, and update information in your
database or other data stores. They provide access to your data.
You can read more about it in :doc:`../models/model`.
-Open up the **app/Models/** directory and create a new file called
+Create NewsModel
+================
+
+Open up the **app/Models** directory and create a new file called
**NewsModel.php** and add the following code.
.. literalinclude:: news_section/001.php
@@ -81,6 +84,9 @@ creates a new model by extending ``CodeIgniter\Model`` and loads the database
library. This will make the database class available through the
``$this->db`` object.
+Add NewsModel::getNews() Method
+===============================
+
Now that the database and a model have been set up, you'll need a method
to get all of our posts from our database. To do this, the database
abstraction layer that is included with CodeIgniter -
@@ -101,7 +107,7 @@ query; :doc:`Query Builder <../database/query_builder>` does this for you.
The two methods used here, ``findAll()`` and ``first()``, are provided
by the ``CodeIgniter\Model`` class. They already know the table to use based on the ``$table``
-property we set in **NewsModel** class, earlier. They are helper methods
+property we set in ``NewsModel`` class, earlier. They are helper methods
that use the Query Builder to run their commands on the current table, and
returning an array of results in the format of your choice. In this example,
``findAll()`` returns an array of array.
@@ -112,8 +118,12 @@ Display the News
Now that the queries are written, the model should be tied to the views
that are going to display the news items to the user. This could be done
in our ``Pages`` controller created earlier, but for the sake of clarity,
-a new ``News`` controller is defined. Create the new controller at
-**app/Controllers/News.php**.
+a new ``News`` controller is defined.
+
+Create News Controller
+======================
+
+Create the new controller at **app/Controllers/News.php**.
.. literalinclude:: news_section/003.php
@@ -126,7 +136,7 @@ access to the current ``Request`` and ``Response`` objects, as well as the
Next, there are two methods, one to view all news items, and one for a specific
news item.
-Next, the :php:func:`model()` function is used to create the **NewsModel** instance.
+Next, the :php:func:`model()` function is used to create the ``NewsModel`` instance.
This is a helper function. You can read more about it in :doc:`../general/common_functions`.
You could also write ``$model = new NewsModel();``, if you don't use it.
@@ -134,6 +144,9 @@ You can see that the ``$slug`` variable is passed to the model's
method in the second method. The model is using this slug to identify the
news item to be returned.
+Complete News::index() Method
+=============================
+
Now the data is retrieved by the controller through our model, but
nothing is displayed yet. The next thing to do is, passing this data to
the views. Modify the ``index()`` method to look like this:
@@ -143,8 +156,12 @@ the views. Modify the ``index()`` method to look like this:
The code above gets all news records from the model and assigns it to a
variable. The value for the title is also assigned to the ``$data['title']``
element and all data is passed to the views. You now need to create a
-view to render the news items. Create **app/Views/news/index.php**
-and add the next piece of code.
+view to render the news items.
+
+Create news/index View File
+===========================
+
+Create **app/Views/news/index.php** and add the next piece of code.
.. literalinclude:: news_section/005.php
@@ -158,11 +175,14 @@ wrote our template in PHP mixed with HTML. If you prefer to use a template
language, you can use CodeIgniter's :doc:`View
Parser ` or a third party parser.
+Complete News::show() Method
+============================
+
The news overview page is now done, but a page to display individual
news items is still absent. The model created earlier is made in such
a way that it can easily be used for this functionality. You only need to
add some code to the controller and create a new view. Go back to the
-``News`` controller and update the ``view()`` method with the following:
+``News`` controller and update the ``show()`` method with the following:
.. literalinclude:: news_section/006.php
@@ -171,23 +191,27 @@ the ``PageNotFoundException`` class.
Instead of calling the ``getNews()`` method without a parameter, the
``$slug`` variable is passed, so it will return the specific news item.
+
+Create news/view View File
+==========================
+
The only thing left to do is create the corresponding view at
**app/Views/news/view.php**. Put the following code in this file.
.. literalinclude:: news_section/007.php
-Routing
-*******
+Adding Routing Rules
+********************
-Modify your routing file
-(**app/Config/Routes.php**) so it looks as follows.
-This makes sure the requests reach the ``News`` controller instead of
-going directly to the ``Pages`` controller. The first line routes URI's
-with a slug to the ``view()`` method in the ``News`` controller.
+Modify your **app/Config/Routes.php** file, so it looks as follows:
.. literalinclude:: news_section/008.php
-Point your browser to your "news" page, i.e., ``localhost:8080/news``,
+This makes sure the requests reach the ``News`` controller instead of
+going directly to the ``Pages`` controller. The second ``$routes->get()`` line
+routes URI's with a slug to the ``show()`` method in the ``News`` controller.
+
+Point your browser to your "news" page, i.e., **localhost:8080/news**,
you should see a list of the news items, each of which has a link
to display just the one article.
diff --git a/user_guide_src/source/tutorial/news_section/003.php b/user_guide_src/source/tutorial/news_section/003.php
index 13c3b7263db6..22b24577b01e 100644
--- a/user_guide_src/source/tutorial/news_section/003.php
+++ b/user_guide_src/source/tutorial/news_section/003.php
@@ -13,7 +13,7 @@ public function index()
$data['news'] = $model->getNews();
}
- public function view($slug = null)
+ public function show($slug = null)
{
$model = model(NewsModel::class);
diff --git a/user_guide_src/source/tutorial/news_section/006.php b/user_guide_src/source/tutorial/news_section/006.php
index 657211792f46..95e48aa77586 100644
--- a/user_guide_src/source/tutorial/news_section/006.php
+++ b/user_guide_src/source/tutorial/news_section/006.php
@@ -9,7 +9,7 @@ class News extends BaseController
{
// ...
- public function view($slug = null)
+ public function show($slug = null)
{
$model = model(NewsModel::class);
diff --git a/user_guide_src/source/tutorial/news_section/008.php b/user_guide_src/source/tutorial/news_section/008.php
index 077efd42254d..df11598451a1 100644
--- a/user_guide_src/source/tutorial/news_section/008.php
+++ b/user_guide_src/source/tutorial/news_section/008.php
@@ -2,12 +2,11 @@
// ...
-use App\Controllers\News;
+use App\Controllers\News; // Add this line
use App\Controllers\Pages;
-$routes->get('news/(:segment)', [News::class, 'view']);
-$routes->get('news', [News::class, 'index']);
+$routes->get('news', [News::class, 'index']); // Add this line
+$routes->get('news/(:segment)', [News::class, 'show']); // Add this line
+
$routes->get('pages', [Pages::class, 'index']);
$routes->get('(:segment)', [Pages::class, 'view']);
-
-// ...
diff --git a/user_guide_src/source/tutorial/static_pages.rst b/user_guide_src/source/tutorial/static_pages.rst
index d39224f3b018..25b514b51c4b 100644
--- a/user_guide_src/source/tutorial/static_pages.rst
+++ b/user_guide_src/source/tutorial/static_pages.rst
@@ -16,6 +16,9 @@ It is the glue of your web application.
Let's Make our First Controller
*******************************
+Create Pages Controller
+=======================
+
Create a file at **app/Controllers/Pages.php** with the following
code.
@@ -47,6 +50,9 @@ The **controller is what will become the center of every request** to
your web application. Like any PHP class, you refer to
it within your controllers as ``$this``.
+Create Views
+============
+
Now that you've created your first method, it's time to make some basic page
templates. We will be creating two "views" (page templates) that act as
our page footer and header.
@@ -80,15 +86,21 @@ includes the following code::
Adding Logic to the Controller
******************************
+Create home.php and about.php
+=============================
+
Earlier you set up a controller with a ``view()`` method. The method
-accepts one parameter, which is the name of the page to be loaded. The
-static page bodies will be located in the **app/Views/pages/**
-directory.
+accepts one parameter, which is the name of the page to be loaded.
+
+The static page bodies will be located in the **app/Views/pages** directory.
In that directory, create two files named **home.php** and **about.php**.
Within those files, type some text - anything you'd like - and save them.
If you like to be particularly un-original, try "Hello World!".
+Complete Pages::view() Method
+=============================
+
In order to load those pages, you'll have to check whether the requested
page actually exists. This will be the body of the ``view()`` method
in the ``Pages`` controller created above:
@@ -129,23 +141,22 @@ view.
throw errors on case-sensitive platforms. You can read more about it in
:doc:`../outgoing/views`.
-Routing
-*******
+Setting Routing Rules
+*********************
We have made the controller. The next thing is to set routing rules.
Routing associates a URI with a controller's method.
-Let's do that. Open the routing file located at
-**app/Config/Routes.php**.
+Let's do that. Open the routes file located at **app/Config/Routes.php**.
-The only line there to start with should be:
+The only route directive there to start with should be:
.. literalinclude:: static_pages/003.php
This directive says that any incoming request without any content
specified should be handled by the ``index()`` method inside the ``Home`` controller.
-Add the following lines, **after** the route directive for '/'.
+Add the following lines, **after** the route directive for ``'/'``.
.. literalinclude:: static_pages/004.php
:lines: 2-
@@ -160,7 +171,7 @@ arguments.
More information about routing can be found in the :doc:`../incoming/routing`.
Here, the second rule in the ``$routes`` object matches a GET request
-to the URI path ``/pages``, and it maps to the ``index()`` method of the ``Pages`` class.
+to the URI path **/pages**, and it maps to the ``index()`` method of the ``Pages`` class.
The third rule in the ``$routes`` object matches a GET request to a URI segment
using the placeholder ``(:segment)``, and passes the parameter to the
@@ -170,8 +181,8 @@ Running the App
***************
Ready to test? You cannot run the app using PHP's built-in server,
-since it will not properly process the ``.htaccess`` rules that are provided in
-``public``, and which eliminate the need to specify "**index.php/**"
+since it will not properly process the **.htaccess** rules that are provided in
+**public**, and which eliminate the need to specify "**index.php/**"
as part of a URL. CodeIgniter has its own command that you can use though.
From the command line, at the root of your project::
@@ -179,9 +190,9 @@ From the command line, at the root of your project::
> php spark serve
will start a web server, accessible on port 8080. If you set the location field
-in your browser to ``localhost:8080``, you should see the CodeIgniter welcome page.
+in your browser to **localhost:8080**, you should see the CodeIgniter welcome page.
-Now visit ``localhost:8080/home``. Did it get routed correctly to the ``view()``
+Now visit **localhost:8080/home**. Did it get routed correctly to the ``view()``
method in the ``Pages`` controller? Awesome!
You should see something like the following:
diff --git a/user_guide_src/source/tutorial/static_pages/003.php b/user_guide_src/source/tutorial/static_pages/003.php
index bf0466ca2192..fc4914a6923b 100644
--- a/user_guide_src/source/tutorial/static_pages/003.php
+++ b/user_guide_src/source/tutorial/static_pages/003.php
@@ -1,7 +1,8 @@
get('/', 'Home::index');
-
-// ...