Журнал LinuxFormat - перейти на главную

LXF141:CackePHP1

Материал из Linuxformat
Перейти к: навигация, поиск
CakePHP Про­стая раз­ра­бот­ка web-при­ло­же­ний с БД. Ну, до­воль­но про­стая…

Содержание

CakePHP: Раз – и web­-приложениe!

Чаcть I Ес­ли ста­тья LXF138 по­дог­ре­ла ваш ап­пе­тит к на­пи­са­нию про­стых и бы­ст­рых web-при­ло­же­ний, Грэм Уэл­дон рас­ска­жет о CakePHP еще кое-что.


На про­шлом уро­ке мы соз­да­ли ба­зу дан­ных филь­мов, где мож­но бы­ло хранить все ва­ши филь­мы в раз­лич­ных фор­ма­тах, и освои­ли осно­вы за­пуска про­ек­та в CakePHP. На сей раз с по­мо­щью тех же прие­мов мы соз­да­дим при­ло­жение по­сложнее, с боль­шим ко­ли­че­­ст­вом мо­де­лей хранения дан­ных, и про­де­мон­ст­ри­ру­ем свя­зи ме­ж­ду мо­де­ля­ми – вы уви­ди­те, как это про­сто.

Пой­дем ко­рот­ким пу­тем, при­менив bake – ути­ли­ту CakePHP, что­бы умень­шить вре­мя раз­ра­бот­ки и сбе­жать в паб по­рань­ше. [Раз­ра­бот­чи­ки лю­бят иг­ры слов: cake – пи­ро­жок, bake – вы­пе­кать, а идио­ма “а piece of cake”, «ку­сок пи­ро­га», оз­на­ча­ет «очень про­сто», т. е. CakePHP – «про­стой PHP», – прим. ред.]

Начнем с оп­ре­де­ления таб­лиц ба­зы дан­ных. Мы по­стро­им мно­го­поль­зо­ва­тель­скую биб­лио­те­ку, для хранения книг от раз­ных вла­дель­цев. За­од­но ук­ра­сим на­ше при­ло­жение, при­спо­со­бив фор­мат URL-ад­ре­сов к по­ис­ко­вым ма­ши­нам.

Спер­ва соз­да­дим но­вую ба­зу дан­ных, чтоб с ней ра­бо­тать:

 CREATE DATABASE library;
 USE library;

За­тем соз­да­дим таб­ли­цы books и users. Не стес­няй­тесь, до­бав­ляй­те в них лю­бые дру­гие по­ля, ес­ли хо­ти­те хра­нить боль­ше дан­ных, чем я:

 CREATE TABLE books (
 id CHAR(36) NOT NULL PRIMARY KEY,
 user_id CHAR(36) NOT NULL,
 title VARCHAR(45) NOT NULL,
 slug VARCHAR(45) NOT NULL,
 author VARCHAR(45) NOT NULL,
 summary TEXT,
 purchased DATE,
 created DATETIME,
 modified DATETIME
 );
 CREATE TABLE users (
 id CHAR(36) NOT NULL PRIMARY KEY,
 name VARCHAR(45) NOT NULL,
 created DATETIME,
 modified DATETIME
 );

Пре­ж­де чем про­дол­жить, вы­полните при­ве­ден­ные вы­ше SQL- за­про­сы в сво­ей ба­зе дан­ных MySQL.

Вве­дение в вы­пе­кание

Итак, таб­ли­цы в ба­зе дан­ных го­то­вы и ждут; по­ка­жем-ка гостям па­ру фо­ку­сов в сти­ле CakePHP. Вме­сто то­го, что­бы вруч­ную соз­да­вать код мо­де­ли [Model], пред­став­лений [Views] и кон­трол­ле­ра [Сontroller] – MVC-ком­плекс, восполь­зу­ем­ся bake, ко­то­рая сгенери­ру­ет код за нас.

Я пред­по­ла­гаю, что вы за­гру­зи­ли по­следний ста­биль­ный ре­лиз CakePHP 1.3 из GitHub (http://github.com/CakePHP/cakephp) или клониро­ва­ли ре­по­зи­то­рий с по­мо­щью Git.

Что­бы ути­ли­та bake ра­бо­та­ла, PHP дол­жен быть досту­пен с команд­ной стро­ки. Для это­го уста­но­ви­те в сис­те­ме php-cli.

Да­лее удоб­но до­ба­вить /cake/console – путь про­ек­та CakePHP – в пе­ре­мен­ную ок­ру­же­ния PATH, что­бы вы­зы­вать ко­ман­ду cake без ука­за­ния пол­но­го пу­ти. Ни­же по­ка­за­но, как это сде­лать – что­бы до­ба­вить ка­та­лог кон­со­ли CakePHP в свой путь, ско­ман­дуй­те

export PATH=”$PATH:/path/to/cakephp/cake/console”

По­сле это­го вы смо­же­те за­пускать ко­ман­ду cake без ука­зания пол­но­го пу­ти до ко­ман­ды. Ес­ли вы планируе­те дол­го­сроч­ную ра­бо­ту с CakePHP, до­бавь­те это в про­филь ва­ше­го поль­зо­ва­те­ля, что­бы путь мог из­ме­нять­ся и cake ста­но­ви­лась доступ­ной при ка­ж­дом за­пуске обо­лоч­ки.

Вы­пе­ка­ем фай­лы про­ек­та

Вруч­ную соз­да­вать все фай­лы, необ­хо­ди­мые для на­шей биб­лио­те­ки, мы опять-та­ки не бу­дем: восполь­зу­ем­ся ути­ли­той bake. Она их соз­даст, а мы на­стро­им под се­бя. Это от­лич­ный спо­соб на­пи­сать и за­пустить при­ло­жение за крат­чай­ший срок.

Пе­рей­ди­те в под­хо­дя­щий ка­та­лог web-сер­ве­ра на сво­ем ком­пь­ю­те­ре – на­при­мер,

cd /var/www/localhost


Вы­пе­ки­те ске­лет про­ек­та сле­дую­щей ко­ман­дой:

cake bake project library

Бу­к­валь­но сей­час со­тво­ри­лось вол­шеб­ст­во. По­верь­те. Но это не со­всем «чер­ный ящик»: мож­но по­смот­реть на соз­дан­ные фай­лы и ра­зо­брать­ся в струк­ту­ре основ­но­го ка­та­ло­га при­ло­жения в CakePHP.

По­это­му улу­чи­те мо­мент, что­бы взгля­нуть соз­дан­ные для вас ути­ли­той bake фай­лы и их струк­ту­ру. Ути­ли­та соз­да­ла ко­пию струк­ту­ры при­ло­жения, ко­то­рую вы ви­ди­те в за­гру­жен­ной (или клониро­ван­ной) ко­пии CakePHP. Бле­стя­ще! Эти фай­лы немно­го от­ли­ча­ют­ся от стан­дарт­но­го на­бо­ра фай­лов при­ло­жения, и это вам по­мо­жет. Ути­ли­та из­менила неко­то­рые пе­ре­мен­ные в web root/index.php, ука­зав в них путь к ка­та­ло­гу CakePHP. А зна­чит, вы мо­же­те раз­во­ра­чи­вать и рас­про­стра­нять при­ло­жения, не ко­пи­руя яд­ро CakePHP на ка­ж­дом ша­гу! Бле­стя­ще вдвойне!

На­стро­им связь с ба­зой дан­ных

Ес­ли вы те­перь по­про­буе­те от­крыть при­ло­жение, то за­ме­ти­те со­об­щения об ошиб­ках и пре­ду­пре­ж­дения, от­ме­чен­ные жел­ты­ми квад­ра­ти­ка­ми в брау­зе­ре. Это не конец све­та, и CakePHP ста­ра­ет­ся дать луч­шие опи­сания и по­лез­ные от­че­ты об ошиб­ках, что­бы вы мог­ли их ис­пра­вить. Ошиб­ки ка­са­ют­ся досту­па к ба­зе дан­ных, так как мы еще не на­строи­ли CakePHP на под­клю­чение к ней. Сде­ла­ем это сей­час. Пе­рей­ди­те в ка­та­лог ва­ших но­вых про­ек­тов ко­ман­дой cd library. Сна­ча­ла за­да­дим кон­фи­гу­ра­цию ба­зы дан­ных, что­бы cake смог­ла най­ти ба­зу дан­ных, с ко­то­рый мы хо­тим ра­бо­тать. Ско­пи­руй­те или пе­ре­мес­ти­те файл config/database.php.default в config/database.php. Из­мените его так, что­бы зна­чения па­ра­мет­ров со­единения по умол­чанию со­от­вет­ст­во­ва­ли па­ра­мет­рам ва­шей ба­зы дан­ных. Тес­то­вое со­еди­не­ние ис­поль­зу­ет­ся для мо­дуль­но­го тес­ти­ро­ва­ния, и по­ка его мож­но сме­ло уда­лить или про­иг­но­ри­ро­вать. Вот при­ мер мо­ей кон­фи­гу­ра­ции по умол­ча­нию:


 var $default = array(
 ‘driver’ =>mysql,
 ‘persistent’ => false,
 ‘host’ => ‘localhost’,
 ‘login’ => ‘dev’,
 ‘password’ => ‘dev’,
 ‘database’ => ‘library’,
 ‘prefix’ => ‘’,
 );

Сно­ва восполь­зу­ем­ся bake – это сэ­ко­но­мит нам ку­чу вре­мени. Тре­мя бы­ст­ры­ми ко­ман­да­ми мы сгенери­ру­ем код для на­ших мо­де­лей, пред­став­лений и кон­трол­ле­ров. Это по­кро­ет все уровни на­шей па­ра­диг­мы MVC. Мож­но это сде­лать и вруч­ную, но бла­го­да­ря bake мож­но очень бы­ст­ро сгенери­ро­вать в CakePHP боль­шой объ­ем ко­да и вы­пол­нять по­вто­ряю­щие­ся за­да­чи, ко­то­рые в про­тив­ном слу­чае по­тре­бо­ва­ли бы го­раз­до боль­ше вре­мени.

Ис­пе­чем все мо­де­ли:

cake bake model all

Испечем все кон­трол­ле­ры:

cake bake controller all

И, на­ко­нец, ис­пе­чем все пред­став­ле­ния:

cake bake view all

Смот­рим, что по­лу­чи­лось

Пре­ж­де чем дви­гать­ся даль­ше, раз­бе­рем­ся, что имен­но соз­да­ли на­ши три ко­ман­ды: сно­ва глянем на сгенери­ро­ван­ный код. Ма­ло то­го, что мень­ше чем за две ми­ну­ты соз­дан ба­зо­вый код мо­де­лей и кон­трол­ле­ра, необ­хо­ди­мый для за­пуска при­ло­жения: еще и оп­ре­де­ле­но, что вы хо­ти­те свя­зать поль­зо­ва­те­лей с книга­ми с по­мо­щью об­ще­при­нят­но­го ис­поль­зо­вания по­ля user_id в таб­ли­це с книга­ми. Это по­зво­ля­ет кон­трол­ле­рам по­лу­чать свя­за­ные дан­ные, на­при­мер, книги, когда оп­ра­ши­ва­ет­ся поль­зо­ва­тель­ская мо­дель, что неве­ро­ят­но по­лез­но и удоб­но, когда бы вам ни по­на­до­би­лось по­лу­чить ин­фор­ма­цию о поль­зо­ва­те­ле и бы­ст­ро и лег­ко ее ото­бра­зить.

На­чаль­ный тест-драйв

Ос­мот­рев ка­та­ло­ги мо­де­лей, кон­трол­ле­ров и пред­став­лений, уст­ро­им на­ше­му де­ти­щу тест-драйв. Ведь по­ка­мест един­ст­вен­ное, где нам при­шлось по­ко­пать­ся – это на­строй­ки ба­зы дан­ных, да и там мы все­го лишь по­ме­ня­ли зна­чения неко­то­рых па­ра­мет­ров.

От­крой­те в брау­зе­ре ка­та­лог, где раз­вер­ну­то при­ло­жение. Вас по­при­вет­ст­ву­ет страница уста­нов­ки CakePHP по умол­чанию; ес­ли есть ка­кие-то пре­ду­пре­ж­дения на­счет ба­зы дан­ных, под­правь­те па­ра­мет­ры в фай­ле config/database.php, пре­ж­де чем про­дол­жить.

По­смот­рим на то, что у нас уже есть, взгля­нув на кон­трол­лер users. От­крой­те путь  /users в сво­ем при­ло­жении. URL-ад­рес бу­дет за­ви­сеть от то­го, как бы­ло раз­вер­ну­то при­ло­жение. Мой та­ков: http://localhost/library/users. Вы уви­ди­те пустой спи­сок, а чуть ниже – неко­то­рые дей­ст­вия.

До­ба­вим книг

Те­перь по­ра брать­ся за де­ло все­рь­ез – до­ба­вим несколь­ко книг, пре­ж­де чем тру­бить от­бой. К сча­стью, весь функ­цио­нал уже го­тов – нуж­но толь­ко слег­ка мо­ди­фи­ци­ро­вать его, про­сто­ты ра­ди.


Прой­ди­те по на­ви­га­ци­он­ным ссыл­кам сле­ва, что­бы до­ба­вить но­вую книгу. Вы уви­ди­те, что ваш поль­зо­ва­тель есть в вы­па­даю­щем спи­ске на фор­ме add book. Эта ин­фор­ма­ция бы­ла по­лу­че­на и применена ав­то­ма­ти­че­­ски, по­то­му что ис­поль­зо­ван­ная на­ми для таб­лиц поль­зо­ва­те­лей и книг струк­ту­ра ба­зы дан­ных от­ве­ча­ет со­гла­шениям CakePHP. Та­ким об­ра­зом, с по­мо­щью пред­ска­зуе­мых за­про­сов CakePHP мо­жет на­хо­дить и ото­бра­жать ин­фор­ма­цию, эко­но­мя ва­ше вре­мя.

Где мы сей­час?

А сей­час мы име­ем пол­но­цен­ное при­ло­жение биб­лио­те­ки; в нем поль­зо­ва­те­ли свя­за­ны с книга­ми, ко­то­ры­ми вла­де­ют, и мож­но до­бав­лять, уда­лять, из­ме­нять и вы­во­дить спи­ски лю­бых за­пи­сей. До­воль­но ми­ло для при­ло­жения, для ко­то­ро­го не бы­ло на­пи­са­но ни строч­ки ко­да, не прав­да ли? И мы не толь­ко на­бра­лись опы­та, но и по­лу­чи­ли код, и мо­жем ме­нять его в со­от­вет­ст­вии с на­ши­ми ну­ж­да­ми!

Вве­дение ко­рот­ких ссы­лок

А те­перь сде­ла­ем нечто изящ­ное. Вы на­вер­ня­ка за­ме­ти­ли, что URL-ад­ре­са, по ко­то­рым вы пе­ре­хо­ди­те, для оп­ре­де­ления за­пи­сей в них ис­поль­зу­ют жут­кие 36‑сим­воль­ные стро­ки. Ну да, это удоб­но, это ра­бо­та­ет, и мы мо­жем раз­вер­нуть при­ло­жение как есть, но го­раз­до луч­ше смот­рят­ся ад­ре­са че­ло­ве­ко-чи­тае­мые; да и по­ис­ко­вым сис­те­мам они по­нра­вят­ся.

От­крой­те кон­трол­лер books в фай­ле library/controllers/books_controller.php и най­ди­те дей­ст­вие для про­смот­ра. Помните, что, го­во­ря дей­ст­вие, я имею в ви­ду пуб­лич­ный ме­тод клас­са кон­т­рол­ле­ра.


Пе­ре­да­дим в ка­че­­ст­ве па­ра­мет­ра не иден­ти­фи­ка­тор ID, а ко­рот­кую ссыл­ку [slug], со­от­вет­ст­вен­но из­ме­нив за­прос find. Для это­го нуж­но из­ме­нить сиг­на­ту­ру ме­то­да про­смот­ра, сле­дую­щим об­ра­зом:

 public function view($slug = null) {
 // Здесь бу­дет код за­ло­жен.
 }

За­тем восполь­зу­ем­ся ме­то­да­ми, пре­достав­ляе­мы­ми CakePHP в мо­де­лях по умол­чанию. Ка­ж­до­му по­лю, оп­ре­де­лен­но­му в мо­де­ли, от­ве­ча­ет свой ме­тод find. Это зна­чит, что мож­но бы­ст­ро и лег­ко на­хо­дить дан­ные в лю­бой мо­де­ли и неза­чем до­бав­лять ме­то­ды, что­бы из­менить спо­соб воз­вра­та ре­зуль­та­тов CakePHP.

По­сколь­ку мы ищем запись по ко­рот­кой ссыл­ке, из­меним ра­бо­ту с иден­ти­фи­ка­то­ром в кон­трол­ле­ре books, что­бы для по­ис­ка и об­ра­бот­ки дан­ных вме­сто иден­ти­фи­ка­то­ра ис­поль­зо­ва­лась ко­рот­кая ссыл­ка.

Про­де­мон­ст­ри­ру­ем од­но из глав­ных пре­иму­ществ ис­поль­зо­вания кар­ка­са PHP вро­де CakePHP для соз­дания при­ло­жений: восполь­зу­ем­ся ин­фор­ма­ци­ей, пе­ре­да­вае­мой поль­зо­ва­те­лем че­рез URL-ад­рес, для вы­полнения за­про­сов к ба­зе дан­ных. На пер­вый взгляд эта идея мо­жет по­ка­зать­ся пло­хой из-за воз­мож­но­сти SQL-инъ­ек­ции. Од­на­ко CakePHP под­дер­жи­ва­ет безо­пас­ность за­про­сов к ба­зе дан­ных во встро­ен­ных ме­то­дах find() – сгенери­ро­ван­ные SQL-за­про­сы яв­ля­ют­ся безо­пас­ны­ми, вер­ны­ми и кор­рект­ны­ми.

Поч­ти го­то­во! Рас­смот­рим осо­бый тип find, ко­то­рый я упо­мя­нул. Так как мы ищем дан­ные по ко­рот­кой ссыл­ке, CakePHP пре­достав­ля­ет на это ме­тод findBySlug. Лег­ко! Те­перь ваш код мож­но за­ме­нить та­ким:


 function view($slug = null) {
 if (!$slug) {
 $this->Session->setFlash(__(‘Invalid book’, true));
 $this->redirect(array(‘action’ => ‘index’));
 }
 $this->set(‘book’, $this->Book->findBySlug($slug));
 }

Те­перь дей­ст­­вие про­смот­ра ра­бо­та­ет с ко­рот­ки­ми ссыл­ка­ми вме­сто иден­ти­фи­ка­то­ров. Да­лее об­но­вим ин­декс­ное пред­став­ление в фай­ле library/views/books/index.ctp, что­бы при пе­ре­хо­де к дей­ст­­вию про­смот­ра бра­лась ко­рот­кая ссыл­ка на книгу, а не ее иден­ти­фи­ка­то­р. Без это­го не обой­тись: ведь мы из­менили ин­фор­ма­цию, требуе­мую для по­ис­ка за­пи­сей, и нуж­но ее пе­ре­дать пред­став­ле­нию, от­ра­зив из­ме­не­ния. Из­ме­ни­те стро­ку

<?php echo $this->Html->link(__(‘View’, true), array(‘action’ => ‘view’, $book[‘Book’][‘id’])); ?>

на сле­дую­щую:

<?php echo $this->Html->link(__(‘View’, true), array(‘action’ => ‘view’, $book[‘Book’][‘slug’])); ?>

Един­ст­вен­ное раз­ли­чие – ин­декс slug в ас­со­циа­тив­ном мас­си­ве $book, ко­то­рый ис­поль­зу­ет­ся пред­став­ле­ни­ем.

Ав­то­ма­ти­зи­ру­ем ссыл­ки!

Те­перь в ад­ре­сах есть ко­рот­кие ссыл­ки. Од­на­ко на на­шей фор­ме add для до­бав­ления книг ко­рот­кая ссыл­ка вво­ди­лась вруч­ную, и негу­ман­но за­став­лять поль­зо­ва­те­ля на­би­рать на­звание книги боль­ше од­но­го раза, хо­тя бы и в дру­гом сти­ле. Бы­ло бы здо­ро­во за­пол­нять это по­ле ав­то­ма­ти­че­­ски: оно про­сто долж­но со­дер­жать пра­виль­ные сло­ва, а те фор­ми­ру­ют­ся по на­званию книги, так что сде­лаем-ка это са­ми до или по­сле со­хранения, из­ба­вив поль­зо­ва­те­лей от лиш­ней мо­ро­ки.

До­ба­вить функ­цио­нал, свя­зан­ный с опе­ра­ци­ей со­хра­не­ния, по­зво­ля­ет реа­ли­за­ция ме­то­да afterSave или beforeSave. Припишите сле­дую­щий код к мо­дели Book в фай­ле library/models/book.php:

 public function beforeSave($op» tions = array()) {
 parent::beforeSave($options);
 $this->data[‘Book’][‘slug’] = Inflector::slug($this->data[‘Book’]
 [‘title’]);
 return true;
 }

Те­перь, раз чер­ная ра­бо­та пе­ре­ки­ну­та на мо­дель, мож­но уда­лить по­ле вво­да ко­рот­кой ссыл­ки из пред­став­ле­ния. Уда­ли­те сле­дую­щую стро­ку из фай­ла library/models/book.php:

echo $this->Form->input(‘slug’);

До­бавь­те в на­ше при­ло­же­ние еще од­ну кни­гу. По­сле ее до­бав­ле­ния вас пе­ре­на­пра­вят на ин­декс­ное пред­став­ле­ние книг, и вы уви­ди­те, что ко­рот­кая ссыл­ка, ко­то­рую рань­ше нуж­но бы­ло вво­дить вруч­ную, те­перь ге­не­ри­ру­ет­ся ав­то­ма­ти­че­ски и ис­поль­зу­ет­ся на стра­ни­це пред­став­ле­ния books.

За­круг­ля­ясь

На вы­полнение всех дей­ст­вий в уро­ке долж­но по­тре­бо­вать­ся око­ло 15 ми­нут, да еще где-то ми­нут 20 нуж­но на чтение уро­ка. На этот раз мы соз­да­ли сис­те­му струк­ту­ри­ро­ван­но­го и ор­ганизо­ван­но­го хранения книг в ба­зе дан­ных, при­вя­зан­но­го к поль­зо­ва­те­лям сис­те­мы. Де­лай мы это на обыч­ном PHP, при­шлось бы до­полнитель­но за­бо­тить­ся о со­еди­не­нии с ба­зой дан­ных, безо­пас­но­сти, пра­виль­ном по­лу­чении ин­фор­ма­ции от поль­зо­ва­те­лей мо­де­ля­ми, раз­бив­ке на стра­ницы и обо всем осталь­ном, что в CakePHP моментально пре­достав­ля­ется вам по умол­чанию.

При­мер ко­да из GitHub (см. ни­же) мож­но рас­ши­рить и модифицировать так, что­бы соз­дать соб­ст­вен­ный про­ект и по­лу­чить хо­ро­шее при­ло­же­ние-ос­но­ву для даль­ней­ше­го изу­че­ния и экспериментов.

Здесь и да­лее

Ко­ды для на­ше­го трой­но­го уро­ка дос­туп­ны на GitHub под мо­ей учет­ной за­пи­сью http://github.com/predominant/cakephp_linux_format. Мо­же­те взять код от­ту­да, ес­ли не по­лу­ча­ет­ся сге­не­ри­ро­вать его ути­ли­той bake или вы про­сто хо­ти­те со­брать и за­пус­тить при­ло­же­ние по­бы­ст­рее – код мож­но ско­пи­ро­вать, опус­тив все эта­пы дан­но­го уро­ка. Под­роб­ная ин­фор­ма­ция и ру­ко­во­дства по CakePHP дос­туп­ны че­рез его офи­ци­аль­ную сеть под­держ­ки:

О лю­бых во­про­сах или пред­ло­же­ни­ях по этой ста­тье дай­те мне знать че­рез мой сайт http://grahamweldon.com или по элек­трон­ной поч­те [graham@grahamweldon.com.

Персональные инструменты
купить
подписаться
Яндекс.Метрика