CakePHP 3 baza danych i model
W tej części zaczniemy tworzyć prosty interfejs do zarządzania użytkownikami. W tym celu utworzymy tabelę users w bazie danych. Pola w tabeli są w większości oczywiste, ale pola passkey i timeout są częścią funkcjonalności resetowania hasła, którą dodamy później.
CREATE TABLE `users` ( `id` bigint(11) NOT NULL, `username` varchar(15) COLLATE utf8mb4_unicode_ci NOT NULL, `password` varchar(61) COLLATE utf8mb4_unicode_ci NOT NULL, `email` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL, `first_name` varchar(30) COLLATE utf8mb4_unicode_ci NOT NULL, `last_name` varchar(30) COLLATE utf8mb4_unicode_ci NOT NULL, `role` varchar(8) COLLATE utf8mb4_unicode_ci NOT NULL, `passkey` varchar(13) COLLATE utf8mb4_unicode_ci NOT NULL, `timeout` timestamp NULL DEFAULT NULL, `modified` datetime NOT NULL, `created` datetime NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;Po utworzeniu tabeli możesz użyć wbudowanego skryptu wiersza poleceń (shell scriptu) aby wypiec (bake) model, kontroler i widok. Więcej na ten temat w dokumentacji. Model CakePHP określa interakcję aplikacji z tabelą bazy danych. Powinien być jeden model na tabelę. Dla naszej tabeli users należy utworzyć 2 pliki: Jeden o nazwie UsersTable.php, który znajduje się w katalogu src/Model/Table/ i jeden o nazwie User.php znajdujący się w katalogu src/Model/Entity/. Obiekty tabel służą do łączenia się z kolekcjami obiektów (tj. tabelami bazy danych). Chociaż wiele z poniższej klasy nie wymaga wyjaśnień, dodałam kilka komentarzy, aby wyjaśnić niektóre z poniższych linii.
Zawartość pliku UsersTable.php:
<?php
namespace App\Model\Table;
use Cake\ORM\Query;
use Cake\ORM\RulesChecker;
use Cake\ORM\Table;
use Cake\Validation\Validator;
class UsersTable extends Table
{
public function initialize(array $config)
{
parent::initialize($config);
$this->table('users'); // nazwa tabeli w bazie danych
$this->displayField('full_name'); // pole lub pole wirtualne (virtual field) używane do wyświetlania domyślnego w powiązanych modelach, jeśli brak będzie to "id"
$this->primaryKey('id'); // Primary key tabeli, jeśli brak będzie to "id"
$this->addBehavior('Timestamp'); // Pozwala modelowi na automatyczne datowanie tworzenia/modyfikacji
}
}
Encje (Entity) reprezentują poszczególne obiekty np rekordy.Zawartość pliku User.php:
<?php
namespace App\Model\Entity;
use Cake\ORM\Entity;
use Cake\Auth\DefaultPasswordHasher;
class User extends Entity
{
// Pola które mogą być zmieniane za pomocą newEntity() lub patchEntity()
protected $_accessible = [
'*' => true,
'id' => false
];
protected $_hidden = [ 'password' ]; // Pole wyłączone z wyświetlania
// Hashowanie hasła przed zapisem i walidacją
protected function _setPassword($value)
{
$hasher = new DefaultPasswordHasher();
return $hasher->hash($value);
}
}
WalidacjaW ramach interfejsu bazy danych model wykonuje również walidację danych. Istnieje wiele podstawowych reguł zaimplementowanych w CakePHP domyślnie, ale możesz również dodać własną regułę niestandardową. Fragment pliku src/Model/Table/UsersTable.php odpowiadający za walidację;
public function validationDefault(Validator $validator)
{
$validator
->integer('id')
->allowEmpty('id', 'create'); // id nie jest obowiązkowe
$validator
->requirePresence('username', 'create')
->notEmpty('username')
->add('username', 'unique', ['rule' => 'validateUnique', 'provider' => 'table']);
$validator
->requirePresence('password', 'create')
->notEmpty('password', 'You must enter a password', 'create')
->add('password', [
'length' => [
'rule' => ['minLength', 8],
'message' => 'Passwords must be at least 8 characters long.',
]
]);
$validator
->requirePresence('first_name', 'create')
->notEmpty('first_name');
$validator
->requirePresence('last_name', 'create')
->notEmpty('last_name');
$validator
->email('email')
->requirePresence('email', 'create')
->notEmpty('email');
$validator
->requirePresence('role', 'create')
->notEmpty('role');
$validator
->dateTime('timeout')
->allowEmpty('timeout');
return $validator;
}
public function buildRules(RulesChecker $rules)
{
$rules->add($rules->isUnique(['username']));
$rules->add($rules->isUnique(['email']));
return $rules;
}
Teraz zajmiemy się bardziej skomplikowaną walidacją.
Powszechnym sprawdzaniem poprawności przy tworzeniu użytkowników jest dwukrotne wpisanie hasła w celu potwierdzenia potwierdzenia wprowadzenia poprawnej wartości.
Z CakePHP można to łatwo osiągnąć za pomocą tymczasowego pola wirtualnego ("confirm_password") i reguły compareWith.
Dodaj następujący walidator do powyższej funkcji validationDefault:
$validator
->requirePresence('confirm_password', 'create')
->notEmpty('confirm_password')
->allowEmpty('confirm_password', 'update')
->add('confirm_password', 'compareWith', [
'rule' => ['compareWith', 'password'],
'message' => 'Passwords do not match.'
]);
Dodaj poniższą funkcję i zmień walidator.
/**
* Checks password for a single instance of each:
* number, uppercase, lowercase, and special character
*
* @param type $password
* @param array $context
* @return boolean
*/
public function checkCharacters($password, array $context)
{
// number
if (!preg_match("#[0-9]#", $password)) {
return false;
}
// Uppercase
if (!preg_match("#[A-Z]#", $password)) {
return false;
}
// lowercase
if (!preg_match("#[a-z]#", $password)) {
return false;
}
// special characters
if (!preg_match("#\W+#", $password) ) {
return false;
}
return true;
}
Innym powszechną walidacją jest wymaganie bezpiecznych haseł.
$validator
->requirePresence('password', 'create')
->notEmpty('password', 'You must enter a password', 'create')
->add('password', [
'length' => [
'rule' => ['minLength', 8],
'message' => 'Passwords must be at least 8 characters long.',
]
])
->add('password', 'custom', [
'rule' => [$this, 'checkCharacters'],
'message' => 'The password must contain 1 number, 1 uppercase, 1 lowercase, and 1 special character'
]);
