CRUD operation in CakePHP 4.0
The CakePHP team is thrilled to announce the immediate availability of 4.0.0.CakePHP 4 is coming with breaking changes. This new release is targeting the newest versions of PHP especially 7.2. CakePHP 4 supports FormHelper now generates HTML5 validation messages and DateTime inputs, Middleware for CSP headers, Form tampering prevention, and HTTPS enforcement.
CakePHP has a few system requirements:
HTTP Server. For example Apache. Having mod_rewrite is preferred, but by no means required. You can also use nginx, or Microsoft IIS if you prefer.
Minimum PHP 7.2
mbstring PHP extension
intl PHP extension
simplexml PHP extension
PDO PHP extension
Installing CakePHP 4
Before starting you should make sure that your PHP version is up to date.You should have PHP 7.2 (CLI) or higher.
php -v
Installing Composer
CakePHP uses Composer, a dependency management tool, as the officially supported method for installation.
Create a CakePHP Project
composer create-project --prefer-dist cakephp/app:~4.0 cms
Now make database cake_cms and make one table articles.
CREATE TABLE articles (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
title VARCHAR(255) NOT NULL,
slug VARCHAR(191) NOT NULL,
body TEXT,
published BOOLEAN DEFAULT FALSE,
created DATETIME,
modified DATETIME,
UNIQUE KEY (slug)
) CHARSET=utf8mb4;
Replace the values in the Datasources.default
array in your config/app_local.php file.
Now let’s make the heart of CakePHP. They enable us to read and modify our data. They allow us to build relations between our data, validate data, and apply application rules. The file we’ll be creating will be saved to src/Model/Table/ArticlesTable.php.
<?php
// src/Model/Table/ArticlesTable.php
namespace App\Model\Table;use Cake\ORM\Table;class ArticlesTable extends Table
{
public function initialize(array $config): void
{
$this->addBehavior('Timestamp');
}
}
We’ve attached the Timestamp behavior which will automatically populate the created
and modified
columns of our table. We’ll also create an Entity class for our Articles. Entities represent a single record in the database. Our entity will be saved to src/Model/Entity/Article.php.
Now we need controllers. Controllers in CakePHP handle HTTP requests and execute business logic contained in model methods, to prepare the response. Place ArticlesController.php inside the src/Controller directory.
Now create a listing page. Create templates/Articles/index.php.
<!-- File: templates/Articles/index.php --><h1>Articles</h1>
<table>
<tr>
<th>Title</th>
<th>Created</th>
</tr><!-- Here is where we iterate through our $articles query object, printing out article info --><?php foreach ($articles as $article): ?>
<tr>
<td>
<?= $this->Html->link($article->title, ['action' => 'view', $article->slug]) ?>
</td>
<td>
<?= $article->created->format(DATE_RFC850) ?>
</td>
</tr>
<?php endforeach; ?>
</table>
Now check http://localhost/cms/articles/index.
Now create view() action in the ArticlesController.php.
public function view($slug = null)
{
$article = $this->Articles->findBySlug($slug)->firstOrFail();
$this->set(compact('article'));
}
Now make the view action template file. Make templates/Articles/view.php.
<h1><?= h($article->title) ?></h1>
<p><?= h($article->body) ?></p>
<p><small>Created: <?= $article->created->format(DATE_RFC850) ?></small></p>
<p><?= $this->Html->link('Edit', ['action' => 'edit', $article->slug]) ?></p>
Let’s add the article.
public function add()
{
$article = $this->Articles->newEmptyEntity();
if ($this->request->is('post')) {
$article = $this->Articles->patchEntity($article, $this->request->getData());
// Hardcoding the user_id is temporary, and will be removed later
// when we build authentication out.
$article->user_id = 1;
if ($this->Articles->save($article)) {
$this->Flash->success(__('Your article has been saved.'));
return $this->redirect(['action' => 'index']);
}
$this->Flash->error(__('Unable to add your article.'));
}
$this->set('article', $article);
}
To show a successful message we are using Flash Component. Add following code to ArticlesController.php.
public function initialize(): void
{
parent::initialize();$this->loadComponent('Paginator');
$this->loadComponent('Flash'); // Include the FlashComponent
}
Create add() action view in File: templates/Articles/add.php.
<h1>Add Article</h1>
<?php
echo $this->Form->create($article);
// Hard code the user for now.
echo $this->Form->control('user_id', ['type' => 'hidden', 'value' => 1]);
echo $this->Form->control('title');
echo $this->Form->control('body', ['rows' => '3']);
echo $this->Form->button(__('Save Article'));
echo $this->Form->end();
?>
Now add simple slug generation.
// in src/Model/Table/ArticlesTable.php
namespace App\Model\Table;
use Cake\ORM\Table;
// the Text class
use Cake\Utility\Text;
// the EventInterface class
use Cake\Event\EventInterface;
// Add the following method.
public function beforeSave(EventInterface $event, $entity, $options)
{
if ($entity->isNew() && !$entity->slug) {
$sluggedTitle = Text::slug($entity->title);
// trim slug to maximum length defined in schema
$entity->slug = substr($sluggedTitle, 0, 191);
}
}
Now add edit action.
public function edit($slug)
{
$article = $this->Articles
->findBySlug($slug)
->firstOrFail();
if ($this->request->is(['post', 'put'])) {
$this->Articles->patchEntity($article, $this->request->getData());
if ($this->Articles->save($article)) {
$this->Flash->success(__('Your article has been updated.'));
return $this->redirect(['action' => 'index']);
}
$this->Flash->error(__('Unable to update your article.'));
}
$this->set('article', $article);
}
Create edit() action template.
<h1>Edit Article</h1>
<?php
echo $this->Form->create($article);
echo $this->Form->control('user_id', ['type' => 'hidden']);
echo $this->Form->control('title');
echo $this->Form->control('body', ['rows' => '3']);
echo $this->Form->button(__('Save Article'));
echo $this->Form->end();
?>
Update index.php view file.
<h1>Articles</h1>
<p><?= $this->Html->link("Add Article", ['action' => 'add']) ?></p>
<table>
<tr>
<th>Title</th>
<th>Created</th>
<th>Action</th>
</tr>
<!-- Here's where we iterate through our $articles query object, printing out article info -->
<?php foreach ($articles as $article): ?>
<tr>
<td>
<?= $this->Html->link($article->title, ['action' => 'view', $article->slug]) ?>
</td>
<td>
<?= $article->created->format(DATE_RFC850) ?>
</td>
<td>
<?= $this->Html->link('Edit', ['action' => 'edit', $article->slug]) ?>
</td>
</tr>
<?php endforeach; ?>
</table>
Add a validation rule to ArticlesTable.php.
use Cake\Validation\Validator;
// Add the following method.
public function validationDefault(Validator $validator): Validator
{
$validator
->notEmptyString('title')
->minLength('title', 10)
->maxLength('title', 255)
->notEmptyString('body')
->minLength('body', 10);
return $validator;
}
Add delete() action.
public function delete($slug)
{
$this->request->allowMethod(['post', 'delete']);$article = $this->Articles->findBySlug($slug)->firstOrFail();
if ($this->Articles->delete($article)) {
$this->Flash->success(__('The {0} article has been deleted.', $article->title));
return $this->redirect(['action' => 'index']);
}
}
Update index.php.
<h1>Articles</h1>
<p><?= $this->Html->link("Add Article", ['action' => 'add']) ?></p>
<table>
<tr>
<th>Title</th>
<th>Created</th>
<th>Action</th>
</tr>
<!-- Here's where we iterate through our $articles query object, printing out article info -->
<?php foreach ($articles as $article): ?>
<tr>
<td>
<?= $this->Html->link($article->title, ['action' => 'view', $article->slug]) ?>
</td>
<td>
<?= $article->created->format(DATE_RFC850) ?>
</td>
<td>
<?= $this->Html->link('Edit', ['action' => 'edit', $article->slug]) ?>
<?= $this->Form->postLink(
'Delete',
['action' => 'delete', $article->slug],
['confirm' => 'Are you sure?'])
?>
</td>
</tr>
<?php endforeach; ?>
</table>