Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file removed user_guide_src/source/images/tutorial9.png
Binary file not shown.
162 changes: 98 additions & 64 deletions user_guide_src/source/tutorial/create_news_items.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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.

<h2><?= esc($title) ?></h2>
Create a new view at **app/Views/news/create.php**:

<?= session()->getFlashdata('error') ?>
<?= validation_list_errors() ?>

<form action="/news/create" method="post">
<?= csrf_field() ?>

<label for="title">Title</label>
<input type="input" name="title" value="<?= set_value('title') ?>">
<br>

<label for="body">Text</label>
<textarea name="body" cols="45" rows="4"><?= set_value('body') ?></textarea>
<br>

<input type="submit" name="submit" value="Create news item">
</form>
.. literalinclude:: create_news_items/006.php

There are probably only four things here that look unfamiliar.

Expand All @@ -72,70 +56,91 @@ 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 <controller-validatedata>` 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() <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() <controller-validatedata>`
is used to validate ``$post`` data.
Validate the Data
^^^^^^^^^^^^^^^^^

You'll use the Controller-provided helper function :ref:`validate() <controller-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() <validation-getting-validated-data>` 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
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::

<p>News item created successfully.</p>

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
Expand All @@ -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
Expand All @@ -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
34 changes: 3 additions & 31 deletions user_guide_src/source/tutorial/create_news_items/002.php
Original file line number Diff line number Diff line change
Expand Up @@ -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');
}
}
8 changes: 4 additions & 4 deletions user_guide_src/source/tutorial/create_news_items/004.php
Original file line number Diff line number Diff line change
Expand Up @@ -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']);

// ...
40 changes: 40 additions & 0 deletions user_guide_src/source/tutorial/create_news_items/005.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

namespace App\Controllers;

use App\Models\NewsModel;
use CodeIgniter\Exceptions\PageNotFoundException;

class News extends BaseController
{
// ...

public function create()
{
helper('form');

// Checks whether the submitted data passed the validation rules.
if (! $this->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');
}
}
18 changes: 18 additions & 0 deletions user_guide_src/source/tutorial/create_news_items/006.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<h2><?= esc($title) ?></h2>

<?= session()->getFlashdata('error') ?>
<?= validation_list_errors() ?>

<form action="/news" method="post">
<?= csrf_field() ?>

<label for="title">Title</label>
<input type="input" name="title" value="<?= set_value('title') ?>">
<br>

<label for="body">Text</label>
<textarea name="body" cols="45" rows="4"><?= set_value('body') ?></textarea>
<br>

<input type="submit" name="submit" value="Create news item">
</form>
2 changes: 1 addition & 1 deletion user_guide_src/source/tutorial/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading