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); } }Walidacja
W 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' ]);