1. Dodatkowe elementy aplikacji CakePHP część II Przygotowany w poprzedniej części projekt prezentuje podstawowe elementy aplikacji opartej o CakePHP takie jak: klasy modelu, kontrolery, widoki. W tej części przyjrzymy się narzędziom dostarczanym wraz z frameworkiem CakePHP, które ułatwiają wytwarzanie typowego kodu np. operacje typu CRUD create, read, update, delete na klasach modelu. Dołączymy również do aplikacji aspekt kontroli dostępu i rozwiniemy funkcjonalność dziennika o nowe możliwości. 2. Kontrola dostępu Dotychczasowy projekt pozwala na dodawanie, edycję i usuwanie notatek. W rzeczywistej aplikacji operacje te powinny być dostępne jedynie dla autora dziennika. Goście z zewnątrz powinni mieć jedynie dostęp do wyświetlania istniejących wpisów i ewentualnie dodawania komentarzy. Aby uzyskać taki efekt, należy wprowadzić do aplikacji aspekt kontroli dostępu. W przypadku frameworka CakePHP służy do tego komponent AuthComponent, który należy dodać do konfiguracji naszej aplikacji. Zanim jednak będziemy mogli to zrobić, konieczne jest przygotowanie odpowiedniej tabeli w bazie danych, która będzie przechowywać informacje o użytkownikach. Listing 1. Tabela przechowująca dane użytkowników 1. CREATE TABLE cakeblog_users 2.... ; Tabela powinna zawierać następujące kolumny: id identyfikator pełniący rolę klucza głównego, autoinkrementacja, username nazwa użytkownika, pole znakowe, maksymalnie 50 znaków, password hasło, pole znakowe maksymalnie 50 znaków, role rola przypisana użytkownikowi, pole znakowe, maksymalnie 50 znaków, created data utworzenia konta użytkownika, modified data ostatniej modyfikacji konta użytkownika. 2.1. Wykorzystanie konsoli Bake do wygenerowania klas modelu, kontrolera i widoków W poprzedniej części klasę modelu dla notatek, klasę kontrolera oraz zbiór potrzebnych do ich działania widoków utworzyliśmy ręcznie. Framework CakePHP umożliwia jednak wygenerowanie znacznej części kodu, który typowo powtarza się w przypadku wielu różnych klas modelu. Służy do tego konsola Bake, którą wykorzystamy w tym etapie, aby uzyskać funkcje pozwalające na zarządzanie użytkownikami. Konsola Bake jest jedną z konsol dostępnych z poziomu narzędzia CakePHP Console. Aby uruchomić konsolę Bake należy przejść do katalogu app/console i w terminalu wydać polecenie: Waldemar Korłub 1/7
Listing 2. Uruchamianie konsoli bake 1. # dla systemów z jądrem Linux/systemu z rodziny UNIX: 2../cake bake # dla systemów Windows: 5. cake.bat bake W przypadku systemów z rodziny Windows konieczne jest dodanie do zmiennej środowiskowej PATH folderu app/console oraz folderu zawierającego konsolowy interpreter PHP PHP CLI. Po uruchomieniu konsoli bake zobaczymy charakterystyczny dla niej znak zachęty: Listing Znak zachęty konsoli Bake 1. Welcome to CakePHP v2.4 Console 2. App : app Path: CakeBlog/app/ 5. 6. Interactive Bake Shell [D]atabase Configuration [M]odel [V]iew 11. [C]ontroller 12. [P]roject 1 [F]ixture 1 [T]est case 15. [Q]uit 16. What would you like to Bake? D/M/V/C/P/F/T/Q 1 > Wybierając opcje M, C lub V i postępując zgodnie z instrukcjami wyświetlanymi na ekranie, możemy wygenerować odpowiednio model, kontroler i widoki do zarządzania wybranymi tabelami z bazy danych. Po utworzeniu w bazie danych tabeli możemy wygenerować pożądane pliki w następujący sposób czcionka pogrubiona pokazuje komendy wpisywane przez programistę, po znaku # następują komentarze do wykonywanych operacji: Listing Znak zachęty konsoli Bake > M # przygotowujemy model danych Bake Model Path: CakeBlog/app/Model/ Possible Models based on your current database: 1. Post 2. User Enter a number from the list above, type in the name of another model, or 'q' to exit [q] > 2 #wybieramy model dla encji User tabela cakeblog_users A displayfield could not be automatically detected would you like to choose one? y/n > y #CakePHP nie znalazł domyślnego pola etykiety, wybieramy je ręcznie Waldemar Korłub 2/7
1. id 2. username password role 5. created 6. modified Choose a field from the options above: > 2 #kolumna username będzie używana jako etykieta Would you like to supply validation criteria for the fields in your model? y/n [y] > y #wybieramy kryteria walidacji dla pól Field: id Type: integer #lista skrócona ze względu na objętość wydruku [35] > 35 #nie wybieramy żadnej walidacji dla pola id Field: username Type: string [35] > 24 #walidator notempty dla pola username Would you like to add another validation rule? y/n [n] > n #nie wybieramy dalszych opcji walidacji dla pola username Field: password Type: string Waldemar Korłub 3/7
[35] > 24 #walidator notempty dla pola Would you like to add another validation rule? y/n [n] > n #nie wybieramy dalszych opcji walidacji dla pola username Field: role Type: string [35] > 15 #walidator notempty dla pola Would you like to add another validation rule? y/n [n] > n #nie wybieramy dalszych opcji walidacji dla role Field: created Type: datetime [35] > 35 #nie wybieramy żadnej walidacji dla pola created Field: modified Type: datetime [35] > 35 #nie wybieramy żadnej walidacji dla pola modified Would you like to define model associations hasmany, hasone, belongsto, etc.? y/n [y] > n #klasa modelu nie ma powiązań z innymi klasami Waldemar Korłub 4/7
The following Model will be created: Name: User DB Table: `cake`.`cakeblog_users` Validation: Array [username] => Array [notempty] => notempty [password] => Array [notempty] => notempty [role] => Array [inlist] => inlist Look okay? y/n [y] > y #analizujemy powyższą propozycję i ją akceptujemy Baking model class for User... Creating file CakeBlog/app/Model/User.php Wrote `CakeBlog/app/Model/User.php` PHPUnit is not installed. Do you want to bake unit test files anyway? y/n [y] > n # nie tworzymy testów jednostkowych dla wygenerowanego kodu Po wykonaniu powyższych czynności powrócimy do początkowego znaku zachęty konsoli Bake. W katalogach projektu możemy odnaleźć utworzony przez konsolę Bake plik app/model/user.php i zweryfikować jego zawartość, która przedstawia się następująco dla czytelności usunięto zbędne komentarze: Listing Wygenerowana klasa User 1. App::uses'AppModel', 'Model'; 2. class User extends AppModel { public $displayfield = 'username'; public $validate = array 5. 'username' => array 6. 'notempty' => array 'rule' => array'notempty' 'password' => array 11. 'notempty' => array 12. 'rule' => array'notempty' 1 1 Waldemar Korłub 5/7
15. 16. 1 1 1 20. 21. } ; 'role' => array 'inlist' => array 'rule' => array'inlist' Konieczne jest uzupełnienie reguły walidacji inlist o wartości dopuszczalne dla tego pola, czy o dopuszczalne nazwy grup np. admin i user. Listing 5. Kompletna reguła walidacji inlist 1. 'role' => array 2. 'inlist' => array 'rule' => array'inlist', array'admin', 'user' 5. Postępując analogicznie jak powyżej, należy wygenerować klasę kontrolera i widoki dla klasy modelu User. Po zakończeniu tych operacji możemy w przeglądarce przejść pod adres http://localhost:port/katalog_projektu/users/, aby zobaczyć w działaniu wygenerowane klasy i widoki. Posługując się tym interfejsem dodajmy dwóch użytkowników do bazy danych: jednego z roli admin i jednego o roli user. 2.2 Wykorzystanie komponentu AuthComponent Plik app/controller/appcontroller.php należy uzupełnić o konfigurację dla komponentu AuthComponent: Listing 6. Konfiguracja AuthComponent 1. class AppController extends Controller { 2. //... public $components = array 'Session', 5. 'Auth' => array 6. 'loginredirect' => array'controller' => 'posts', 'action' => 'index' 'logoutredirect' => array'controller' => 'pages', 'action' => 'display', 'home' 11. ; 12. public function beforefilter { 1 $this->auth->allow'index', 'view'; 1 } 15. //... 16. } 1 1 Plik app/controller/userscontroller.php należy uzupełnić o metody obsługujące logowanie użytkowników. Określamy również, że dodawanie nowych użytkowników będzie dostępne dla niezalogowanych. Waldemar Korłub 6/7
Listing Obsługa logowania, tworzenie kont dostępne dla niezalogowanych 1. public function beforefilter { 2. parent::beforefilter; $this->auth->allow'add'; } 5. public function login { 6. if $this->request->is'post' { if $this->auth->login { $this->redirect$this->auth->redirect; } else { $this->session->setflash 'Invalid username or password, 11. try again'; 12. } 1 } 1 } 15. public function logout { 16. $this->redirect$this->auth->logout; 1 } Konieczne jest także dodanie hashowania hasłem zapisywanych w bazie danych. W tym celu należy zmodyfikować plik app/model/user.php: Listing Użycie funkcji mieszającej na hasłach użytkowników zapisywanych w bazie danych 1. public function beforesave$options = array { 2. if isset$this->data[$this->alias]['password'] { $this->data[$this->alias]['password'] = AuthComponent::password$this->data[$this->alias]['password']; 5. } 6. return true; } Posługując się stroną pod adresem http://localhost:port/katalog_projektu/users/, należy dodać dwóch użytkowników do bazy danych: jednego o roli admin i jednego o roli user. Ostatnim brakującym elementem jest widok przeznaczony do logowania, który znajduje się w pliku app/view/users/login.ctp: Listing Widok logowania 1. 2. 5. 6. <div class="users form"> <?php echo $this->session->flash'auth';?> <?php echo $this->form->create'user';?> <fieldset> <legend><?php echo 'Proszę wprowadzić login i hasło';?></legend> <?php echo $this->form->input'username'; echo $this->form->input'password';?> </fieldset> <?php echo $this->form->end 'Login';?> </div> Po dodaniu wszystkich elementów można zweryfikować działanie kontroli dostępu. W kolejnym etapie należy dodać reguły kontroli dostępu dla kontrolera notatek, dodając metodę isauthorized do pliku app/controller/postscontroller.php. Waldemar Korłub 7/7