Kontrolery i widoki w CakePHP 3

Teraz zajmiemy się utworzeniem kontrolera w celu pobrania danych oraz widoków aby je wyświetlić. Podczas gdy model jest używany do interakcji z bazami danych, kontroler jest używany do przetwarzania żądań oraz przekazywania zmiennych do widoku.

Prosty kontroler zawiera podstawowe operacje CRUD i wywołuje funkcje modelu w celu wykonania tych zadań. Dla tabeli users plikiem kontrolera będzie src/Controller/UsersController.php. Jego zawartość poniżej.
<?php
namespace App\Controller;

use App\Controller\AppController;

class UsersController extends AppController
{
    private $roles = ['User' => 'User', 'Admin' => 'Admin', 'Disabled' => 'Disabled'];
    public $paginate = [
        'limit' => 30,
		'order' => ['first_name' => 'ASC', 'last_name' => 'ASC']
    ];
	
    public function index() {
        $users = $this->paginate($this->Users);
        $this->set(compact('users'));
        $this->set('_serialize', ['users']);
    }
	
    public function view($id = null) {
        $user = $this->Users->get($id);
        $this->set('user', $user);
        $this->set('_serialize', ['user']);
    }
	
    public function add() {
        $user = $this->Users->newEntity();
        if ($this->request->is('post')) {
            $user = $this->Users->patchEntity($user, $this->request->data);
            if ($this->Users->save($user)) {
                $this->Flash->success(__('The user has been saved.'));
                return $this->redirect(['action' => 'index']);
            } else {
                $this->Flash->error(__('The user could not be saved. Please, try again.'));
            }
        }
        $roles = $this->roles;
        $this->set(compact('user', 'roles'));
        $this->set('_serialize', ['user']);
    }
	
    public function edit($id = null) {
        $user = $this->Users->get($id);
        if ($this->request->is(['patch', 'post', 'put'])) {
            if ($this->request->data['password'] == '') {
               unset($this->request->data['password']); // unset the blank password
            }
            $user = $this->Users->patchEntity($user, $this->request->data);
            if ($this->Users->save($user)) {
                $this->Flash->success(__('The user has been saved.'));
                return $this->redirect(['action' => 'index']);
            } else {
                $this->Flash->error(__('The user could not be saved. Please, try again.'));
            }
        }
        unset($user->password); // Unset the password so nothing is loaded or displayed in the form
        $roles = $this->roles;
        $this->set(compact('user', 'roles'));
        $this->set('_serialize', ['user']);
    }
	
    public function delete($id = null) {
        $this->request->allowMethod(['post', 'delete']);
        $user = $this->Users->get($id);
        if ($this->Users->delete($user)) {
            $this->Flash->success(__('The user has been deleted.'));
        } else {
            $this->Flash->error(__('The user could not be deleted. Please, try again.'));
        }
        return $this->redirect(['action' => 'index']);
    }
}
Tablica roles zawiera listę dostępnych ról użytkowników, wartości do wyświetlenia i klucze, które mają być przechowywane w rekordach. Zmienna paginate zastępuje domyślny limit 20 oraz ustawia kolejność sortowania. Nie można używać wirtualnych pól, takich jak full_name, do sortowania list stronicowanych, ale można zdefiniować kolejność sortowania tak, aby była taka sama jak pole wirtualne. Jest mały problem z tym w widoku, ale omówimy to później. Być może zauważyłeś, że w funkcji edit(), unsetujemy pole hasła dwa razy. Najpierw (przy drugim wystąpieniu) usuwamy go przed wyświetleniem, aby pole hasła pozostało puste. Hashowana wartość przechowywana w bazie danych nie jest przydatna przy edycji użytkownika. Drugi raz przed przekazaniem danych do zapisu. Jeśli użytkownik nie ustawił nowego hasła, nie chcemy zapisywać pustego łańcucha w bazie danych, zastępując obecne hasło. Kod widoku listy użytkowników (src/Template/Users/index.ctp). CakePHP używa dla plików widoków i elementów rozszerzenia .ctp. Jest to domyślna lista rekordów z bazy danych.
<?php if (empty($_GET['direction'])) { $this->Paginator->options(['url' => ['direction' => null, 'sort' => null]]); } ?>
<div class="users index large-9 medium-8 columns content">
    <?php echo $this->Html->link(__('New User'), ['action' => 'add'], ['class' => 'right']); ?>
    <h3><?php echo __('Users') ?></h3>
    <table cellpadding="0" cellspacing="0">
        <thead>
            <tr>
                <th><?php echo $this->Paginator->sort('first_name', 'Name') ?></th>
                <th><?php echo $this->Paginator->sort('username') ?></th>
                <th><?php echo $this->Paginator->sort('email') ?></th>
                <th><?php echo $this->Paginator->sort('role') ?></th>
                <th class="actions"><?php echo __('Actions') ?></th>
            </tr>
        </thead>
        <tbody>
            <?php foreach ($users as $user): ?>
            <tr>
                <td><?php echo $this->Html->link($user->full_name, ['action' => 'view', $user->id]) ?></td>
                <td><?php echo h($user->username) ?></td>
                <td><?php echo $this->Text->autoLinkEmails($user->email) ?></td>
                <td><?php echo h($user->role) ?></td>
                <td class="actions">
                    <?php echo $this->Html->link(__('View'), ['action' => 'view', $user->id]) ?> |
                    <?php echo $this->Html->link(__('Edit'), ['action' => 'edit', $user->id]) ?>
                </td>
            </tr>
            <?php endforeach; ?>
        </tbody>
    </table>
    <div class="paginator">
        <ul class="pagination">
            <?php echo $this->Paginator->prev('< ' . __('previous')) ?>
            <?php echo $this->Paginator->numbers() ?>
            <?php echo $this->Paginator->next(__('next') . ' >') ?>
        </ul>
        <p>page <?php echo $this->Paginator->counter() ?></p>
    </div>
</div>
Niestety między CakePHP 2 a 3 zmiana modelu danych uniemożliwiła sortowanie po wirtualnych polach (np. full_name), więc zauważysz, że nagłówek pierwszej kolumny to "first_name", a nie "full_name". Ponadto kolejność sortowania jest teraz przekazywana za pośrednictwem adresu URL, niezależnie od tego, czy została wybrana kolejność sortowania, czy też nie, tracąc nasz domyślny rodzaj sortowania po first_name i last_name. Taki jest cel pierwszego wiersza pliku: czyszczenie opcji sortowania i kierunku, o ile nie zostały one wyraźnie zaznaczone. Widok dodawania użytkownika (src/Template/Users/add.ctp).
<?php $this->assign('title', 'Add User'); // Set the title for the page ?>
<div class="users form large-9 medium-8 columns content">
    <?php echo $this->Form->create($user) ?>
    <fieldset>
        <legend><?php echo __('Add User') ?></legend>
        <?php
            echo $this->Form->input('username', ['autofocus' => true]);
            echo $this->Form->input('first_name');
            echo $this->Form->input('last_name');
            echo $this->Form->input('password'); ?>
        <p class="helper">Passwords must be at least 8 characters and contain at least 1 number, 1 uppercase, 1 lowercase and 1 special character</p>
        <?php
            echo $this->Form->input('confirm_password', ['type' => 'password']);
            echo $this->Form->input('email');
            echo $this->Form->input('role');
        ?>
     </fieldset>
    <?php echo $this->Form->button(__('Submit')); ?>
    <?php echo $this->Html->link(__('Cancel'), ['action' => 'index'], ['class' => 'button']); ?>
    <?php echo $this->Form->end(); ?>
</div>
W CakePHP dzięki Form Helperowi łatwo stworzymy wiele pól formularza na podstawie typu pola z bazy danych. W niektórych przypadkach, takich jak pole roli, zdaje sobie sprawę, że istnieje tablica o nazwie $role i tworzy pole wyboru wykorzystujące tę tablicę. Ponieważ confirm_password nie jest polem w bazie danych, domyślnie jest polem tekstowym, więc wykorzystując tablicę $options, możesz powiedzieć Cakeowi, aby uczynił ją polem hasła. W celu dodania jakiegoś użytkownika wejdź w przeglądarce na adres localhost/users/add.