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

LXF138:CakePHP

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

Содержание

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

Хо­ти­те соз­дать на­деж­ное web-при­ло­же­ние, но не­ко­гда во­зить­ся с PHP? Грэм Уэл­дон счи­та­ет, что CakePHP – то, что вам нуж­но.


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

Для ра­бо­ты CakePHP нуж­но со­всем немно­го. По­на­до­бит­ся web-сер­вер ти­па Apache, PHP 4+ (луч­ше 5+), MySQL 4+ и тек­сто­вый ре­дак­тор на ваш вы­бор. На мо­мент напи­сания ста­тьи по­следней вер­си­ей CakePHP бы­ла 1.3.

За­гру­зить по­след­нюю вер­сию мож­но в ви­де ар­хи­ва с сай­та http://github.com/cakephp/cakephp/downloads, или по­лу­чить ее из ре­по­зи­то­рия http://github.com/cakephp/cakephp с по­мо­щью Git.

По­сле за­груз­ки ар­хи­ва с сай­та или из ре­по­зи­то­рия ско­пи­руй­те со­дер­жи­мое па­ке­та cakephp в DocumentRoot web-сер­ве­ра. У вас дол­жен поя­вить­ся ка­та­лог /directory, со­дер­жа­щий под­ка­та­ло­ги /app, /cake, /plugins и /vendors и фай­лы .htaccess, index.php и README.

На­строй­ка ба­зы дан­ных

Сле­дую­щий шаг – на­строй­ка ба­зы дан­ных. Восполь­зу­ем­ся MySQL, так как это са­мая по­пу­ляр­ная из сво­бод­ных СУБД, и для на­ше­го при­ло­жения соз­да­дим сле­дую­щую ба­зу дан­ных:

CREATE DATABASE linux_format_tutorial;
CREATE TABLE `movies` (
`id` CHAR(36) NOT NULL PRIMARY KEY,
`title` VARCHAR(255),
`genre` VARCHAR(45),
`rating` VARCHAR(45),
`format` VARCHAR(45),
`length` VARCHAR(45),
`created` DATETIME,
`modified` DATETIME
);

Конеч­но, это все­го лишь таб­ли­ца, но для хранения ин­фор­ма­ции и ра­бо­ты при­ло­жения ее доста­точ­но.

Об­ра­ти­те внимание, что для иден­ти­фи­ка­то­ра ка­ж­дой запи­си ис­поль­зу­ет­ся по­ле ти­па CHAR(36). CakePHP за­ме­ча­ет это, и при до­бав­лении но­вых запи­сей ав­то­ма­ти­че­ски генери­ру­ет им уникаль­ный универ­саль­ный иден­ти­фи­ка­тор UUID вме­сто чи­сло­во­го зна­чения. Это по­лез­ная при­выч­ка, поскольку она уп­роща­ет дальней­шее слияние дан­ных из раз­лич­ных баз. Та­ков один из под­хо­дов CakePHP, осно­ван­ный на со­гла­шениях и от­ра­жаю­щий прин­цип раз­ра­бот­ки при­ло­жений в CakePHP: «Со­гла­шения важнее кон­фи­гу­ра­ции».

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

Так как для на­званий филь­мов мы вы­бра­ли по­ле title, что со­от­вет­ству­ет од­но­му из из­вест­ных CakePHP «умол­ча­тель­ных» за­го­лов­ков ко­ло­нок, мы уви­дим еще немно­го вол­шеб­ства – CakePHP ав­то­ма­ти­че­ски возьмет на­звания всех запи­сей (при со­став­лении спи­сков и да­лее в та­ком ду­хе) имен­но из это­го столб­ца.

Пе­ред пе­ре­хо­дом к сле­дую­ще­му ша­гу соз­дай­те таб­ли­цу.

Уста­нов­ка со­единения с БД

На­строй­ка ба­зы дан­ных в CakePHP про­ста. Есть файл /app/config/database.php.default – это при­мер фай­ла кон­фи­гу­ра­ции БД. Про­ще все­го ско­пи­ро­вать этот файл в /app/config/database.php. В соз­дан­ной ко­пии из­мените па­ра­мет­ры досту­па к ба­зе дан­ных. Для на­ше­го при­ло­жения нуж­но на­стро­ить толь­ко со­единение $default. Это долж­но вы­гля­деть при­мер­но так:


 var $default = array(
  ‘driver’ =>mysql,
  ‘persistent’ =>false,
  ‘host’ => ‘localhost’,
  ‘port’ => ‘’,
  ‘login’ => ‘имя_поль­зо­ва­те­ля’,
  ‘password’ => ‘па­роль’,
  ‘database’ => ‘linux_format_tutorial’,
  ‘schema’ => ‘’,
  ‘prefix’ => ‘’,
  ‘encoding’ => ‘’
 );

Те­перь мож­но ­гру­зить страницу при­вет­ствия CakePHP, от­крыв в брау­зе­ре ад­рес, по ко­то­ро­му рас­по­ло­жен сер­вер. Вы уви­ди­те зе­ле­ные ин­ди­ка­то­ры, оз­на­чаю­щие успеш­ную уста­нов­ку CakePHP. Ес­ли в на­строй­ках что-то не так, ин­ди­ка­то­ры бу­дут жел­ты­ми, и поя­вит­ся под­роб­ное со­об­щение об ошиб­ке, ко­то­рое по­мо­жет ре­шить про­бле­му. Для на­ше­го при­ло­жения мож­но иг­но­ри­ро­вать все со­об­щения о за­тра­воч­ном зна­чении [Security Salt] или пре­ду­пре­ж­дения о клю­че шиф­ро­вания [Cipher Key] – ему это­го не на­до.

Возь­мем­ся за код все­рь­ез, соз­дав класс MoviesController в /app/controllers/movies_controller.php.


 class MoviesController extends AppController {
   public $components = array(‘Session’);
 }

Для об­ра­бот­ки со­об­ще­ний об ошиб­ках мы вклю­чи­ли ком­по­нент Session.

Од­но за дру­гим соз­да­дим дей­ствия, предоставляемые поль­зо­ва­те­лям, про­смат­ри­ваю­щим ба­зу дан­ных филь­мов. Дей­ствия – это пуб­лич­но до­ступ­ные функ­ции кон­трол­ле­ра. Для всех опе­ра­ций, вы­пол­няе­мыхнад филь­мом в ба­зе дан­ных, соз­да­дим в кон­трол­ле­ре дей­ствия типа CRUD. CRUD – это со­кра­щение от Create, Read, Update и Delete [Соз­дать, Про­чи­тать, Об­но­вить и Уда­лить]. На­ши дей­ствия по­лу­чат на­звания index, add, edit, view и delete.

Начнем с дей­ствия index – вы­во­д спи­ска всех филь­мов в ба­зе дан­ных. В кон­тро­ле­ре есть объ­ект сущ­но­сти Movie; он пред­став­ля­ет со­бой мо­дель. Он ав­то­ма­ти­че­ски вклю­ча­ет­ся CakePHP и со­от­вет­ству­ет имени кон­трол­ле­ра. Мо­жер вы­звать find() в этой мо­де­ли, и CakePHP пре­об­ра­зу­ет эти вы­зо­вы в за­про­се к ба­зе дан­ных – нам не при­дет­ся пи­сать SQL-за­прос вруч­ную. По­тря­саю­ще! Ниже мы вы­зы­ва­ем ме­тод find() с ар­гу­мен­том all и запи­сы­ва­ем ре­зуль­тат в пред­став­ление для по­сле­дую­ще­го ото­бра­жения.

 class MoviesController extends AppController {
   public $components = array(‘Session’);
   public function index() {
      $movies = $this->Movie->find(‘all’);
      $this->set(‘movies’, $movies);
    }
 }

Вот и все, что нуж­но для дей­ствия index. Понимаю, что вы­гля­дит это бе­зы­скусным, но в том-то и пре­лесть CakePHP – неза­чем все услож­нять.

Соз­да­ем пер­вое пред­став­ление

Дей­ствие го­то­во – соз­дадим пред­став­ление, что­бы мож­но бы­ло про­смат­ри­вать дан­ные и ра­бо­тать с ними. Пред­став­ления в CakePHP – про­стые PHP-фай­лы с рас­ши­рением ctp. Они напи­са­ны на обыч­ном PHP.

Соз­дай­те свое пер­вое пред­став­ление в фай­ле /app/views/mov­ies/index.ctp. Сна­ча­ла соз­дайте ка­та­лог movies в /app/views. До­бавь­те ту­да код из фраг­мен­та 1 на LXFDVD:

Это бу­дет зна­ко­мо всем, кто стал­ки­вал­ся с HTML и PHP. От­ли­чие в том, как вспо­мо­га­тель­ные клас­сы пред­став­ления ис­поль­зу­ют­ся для вы­во­да ин­фор­ма­ции вро­де ссылок. Вспо­мо­га­тель­ный класс HtmlHelper по­зво­ля­ет пе­ре­да­вать мас­си­вы дан­ных в дей­ствия View, Edit и Delete. Они пре­об­ра­зу­ют­ся в ад­ре­са на­по­до­бие http://mysite.com/movies/view/1234 (для ссыл­ки на про­смотр).

Пред­став­ление ите­ри­ру­ет пе­ре­мен­ную $movies, уста­нов­лен­ную ранее кон­трол­ле­ром MoviesController, и вы­во­дит все запи­си в таб­ли­це (в кон­це кон­цов, это таб­лич­ные дан­ные).


Те­перь от­кроем ад­рес /movies/index на ва­шем сер­ве­ре и про­смот­рим дан­ные, вы­ве­ден­ные но­вым пред­став­лением. Ес­ли на сер­ве­ре толь­ко од­но раз­ра­ба­ты­вае­мое при­ло­жение CakePHP, ад­рес бу­дет та­ким: http://mysite.com/movies/index. Или, ес­ли при­ло­жение на­хо­дит­ся в под­ка­та­ло­ге, об­ра­щай­тесь к нему: http://mysite.com/my_directory/movies/index.

На дан­ный мо­мент филь­мов в ба­зе нет. Сроч­но соз­да­дим функ­цио­нал для их до­бав­ления: вре­мя-то идет!

Соз­дание дей­ствия add и про­смотр

Те­перь рас­ши­рим наш кон­трол­лер, до­ба­вив в него функ­цию add. С ее по­мо­щью но­вые филь­мы бу­дут до­бав­лять­ся в ба­зу дан­ных. Нуж­но про­ве­рить, бы­ли ли вве­де­ны в фор­му ка­кие-то дан­ные, и ес­ли да, про­ве­рить ее на на­ли­чие оши­бок и об­ра­бо­тать. Это ка­жет­ся слож­ным, но CakePHP об­лег­ча­ет ре­шение дан­ной за­да­чи. Со­от­вет­ствую­щий фраг­мент ко­да мож­но уви­деть в Листин­ге 2 на LXFDVD.

Пред­став­ление для до­бав­ления филь­мов ис­поль­зу­ет вспо­мо­га­тель­ный класс форм CakePHP, по­зво­ляю­щий лег­ко соз­да­вать фор­мы на все слу­чаи жизни. Здесь мы про­сто оп­ре­де­ля­ем, для ка­кой мо­де­ли соз­да­ет­ся фор­ма (в дан­ном слу­чае, мо­дель Movie) и ка­кие по­ля мы пре­доста­вим поль­зо­ва­те­лям.

Соз­дай­те файл /app/views/movies/add.ctp и по­мести­те ту­да сле­дую­щий код:

 <div class=”movies form”>
 <?php
 echo $this->Form->create(‘Movie’);
 echo $this->Form->inputs(array(‘title’, ‘genre’, ‘rating’,
 ‘format’, ‘length’));
 echo $this->Form->end(‘Add’);
 ?>
 </div>
 <div class=”actions”>
   <h3>Actions</h3>
   <ul>
    <li><?php echo $this->Html->link(List Movies’,
 array(‘action’ => ‘index’));?></li>
   </ul>
 </div>

Са­мо соз­дание фор­мы про­ис­хо­дит в пер­вых трех стро­ках фай­ла. Все осталь­ное – HTML-код для рас­по­ло­жения эле­мен­тов на странице и генера­ции ссыл­ки для воз­вра­та к спи­ску филь­мов.

Те­перь мож­но пе­рей­ти к фор­ме соз­дания филь­мов, от­крыв ад­рес /movies/add или щелк­нув по ссыл­ке «New Movie», ко­то­рую мы до­ба­ви­ли на глав­ную страницу.


Бле­стя­ще! Но мож­но пой­ти даль­ше и до­ба­вить па­ру филь­мов. В при­ме­ре на сле­дую­щем эк­ран­ном сним­ке мы до­бав­ля­ем ин­фор­ма­цию о филь­ме «Че­ло­век-па­ук 3» в фор­ма­те Blu-ray. По­сле до­бав­ления ин­фор­ма­ции об оче­ред­ном филь­ме вы пе­ре­на­прав­ляе­тесь на глав­ную страницу, где в спи­ске филь­мов по­яв­ля­ет­ся но­вая запись.

Уда­ля­ем филь­мы

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

До­бавь­те дей­ст­вие уда­ле­ния в кон­трол­лер Movies:

 class MoviesController extends AppController {
    // .. компонен ты ..
    // .. дейст вие index ..
    // .. дейст вие add ..
    public function delete($id = null) {
        if (!$id) {
            $this­>Session­>setFlash(‘Invalid id for movie’);
            $this­>redirect(array(‘action’ => ‘index’));
        }
        if ($this­>Movie­>delete($id)) {
            $this­>Session­>setFlash(‘Movie deleted’);
        } else {
            $this­>Session­>setFlash(__(‘Movie was not deleted’, true));
          }
         $this­>redirect(array(‘action’ => ‘index’));
     }
 }


Ранее мы уже до­ба­ви­ли ссыл­ки на уда­ление филь­мов на страницу ин­дек­са. А те­перь мож­но запросто уда­лять филь­мы, щелк­нув по этим ссыл­кам! Вы мог­ли за­ме­тить, что фраг­мент ко­да, соз­даю­ще­го ссыл­ку на уда­ление, длиннее, чем для дей­ствий про­смот­ра и ре­дак­ти­ро­вания. Это объ­яс­ня­ет­ся тем, что в дей­ствие уда­ления вклю­чен код JavaScript для по­ка­за пре­ду­пре­ж­дения, ко­то­рый спра­ши­ва­ет поль­зо­ва­те­ля, дей­ст­ви­тель­но ли он хо­чет уда­лить эту запись. Этот ме­ханизм по­зво­лит поль­зо­ва­те­лю вер­нуть­ся на­зад, из­бе­жав слу­чай­но­го уда­ления, так как с дей­стви­ем не свя­за­но ни од­но­го пред­став­ления.

 <?php echo $this->Html->link(‘Delete’, array(‘action’ =>
 ‘delete’, $movie[‘Movie’][‘id’]), null, sprintf(‘Are you sure you
 want to delete %s?’, $movie[‘Movie’][‘title’])); ?>

До­бав­ле­ние филь­ма с дей­ст­ви­ем Add. Да, это про­сто, но вся пре­лесть в ма­лом объ­е­ме тре­буе­мо­го ко­да.

Ре­дак­ти­ру­ем дан­ные

Да­же луч­шим из луч­ших слу­ча­ет­ся оши­бить­ся, и хо­ро­шо бы иметь дей­ствие для ре­дак­ти­ро­вания дан­ных, что­бы при необ­хо­ди­мо­сти ис­прав­лять ошиб­ки или вно­сить в запи­си изменения. Это дей­ствие очень по­хо­же на дей­ствие до­бав­ления; основ­ное от­ли­чие в том, что ра­бо­та про­из­во­дит­ся с ID су­ще­ствую­щей запи­си. На са­мом де­ле они на­столь­ко по­хо­жи, что опыт­ные раз­ра­бот­чи­ки CakePHP объ­е­ди­ня­ют дей­ствия add и edit в од­но. Для эко­но­мии места код вынесен на LXFDVD в Листинг 3; до­бавь­те его в свой кон­трол­лер.

Основ­ные раз­ли­чия ме­ж­ду дей­ствия­ми add и edit в том, что дей­ствию ре­дак­ти­ро­вания пе­ре­да­ет­ся иден­ти­фи­ка­тор запи­си и в нем не вы­зы­ва­ет­ся ме­тод create() объ­ек­та Movie, по той при­чине, что при со­хранении в ба­зе долж­ны уце­леть все имею­щие­ся в запи­си поля.

Пред­став­ление для ре­дак­ти­ро­вания

По­ка все долж­но вы­гля­деть зна­ко­мым. Пред­став­ление edit, ко­то­рое мы на­ме­ре­ны соз­дать, поч­ти иден­тич­но фор­ме до­бав­ления add. По­вто­рюсь, раз­ра­бот­чи­ки, ка­кое-то вре­мя про­ра­бо­тав­шие с CakePHP, объ­е­ди­ня­ют add и edit в од­но пред­став­ление, что­бы не бы­ло по­вто­ров ко­да. Един­ствен­ное от­ли­чие со­сто­ит в по­яв­лении в фор­ме вход­но­го па­ра­мет­ра id и кноп­ки для от­прав­ки фор­мы.

Соз­дай­те файл /app/views/movies/edit.ctp и по­мести­те ту­да сле­дую­щий код:

 <div class=”movies form”>
 <?php
 echo $this­>Form­>create(‘Movie’);
 echo $this­>Form­>inputs(array(‘id’, ‘title’, ‘genre’, ‘rating’,
 ‘format’, ‘length’));
 echo $this­>Form­>end(‘Edit’);
 ?>
 </div>
 <div class=”actions”>
    <h3>Actions</h3>
    <ul>
      <li><?php echo $this­>Html­>link(List Movies’,
 array(‘action’ => ‘index’));?></li>
    </ul>
 </div>

Со­хра­ним пред­став­ле­ние

По­ра про­ве­рить, как все ра­бо­та­ет. Как и пре­ж­де, от­крой­те в брау­зе­ре глав­ную страницу и пе­рей­ди­те к странице ре­дак­ти­ро­вания дан­ных для од­но­го из ва­ших филь­мов. На эк­ране поя­вят­ся все по­ля вво­да для запи­си. Об­ра­ти­те внимание, что по­ле id не ото­бра­жа­ет­ся. Это скры­тое по­ле фор­мы, и поль­зо­ва­тель не мо­жет ра­бо­тать с эти­ми дан­ны­ми. На­ше по­следнее дей­ствие и пред­став­ление вы­ве­дут под­роб­ную ин­фор­ма­цию о ка­ж­дом филь­ме, по­ка­зав все дан­ные, не ото­бра­жае­мые на глав­ной странице, та­кие как вре­мя соз­дания и из­менения запи­си.

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

До­бавь­те та­кое дей­ст­вие про­смот­ра в кон­трол­лер Movies:


 class MoviesController extends AppController {
    // .. компонен ты ..
    // .. дейст вие index ..
    // .. дейст вие add ..
    // .. дейст вие delete ..
    // .. дейст вие edit ..
    function view($id = null) {
        if (!$id) {
            $this­>Session­>setFlash(‘Invalid movie’);
            $this­>redirect(array(‘action’ => ‘index’));
        }
        $this­>set(‘movie’, $this­>Movie­>findById($id));
    }
 }

Соз­да­ем под­роб­ное пред­став­ле­ние

На­ше по­следнее пред­став­ление – про­сто таб­ли­ца со всей име­ющейся ин­фор­ма­ци­ей о филь­ме. Соз­дай­те это пред­став­ление в фай­ле /app/views/movies/view.ctp – код при­ве­ден в Листин­ге 4 на LXFDVD.

По­следние дей­ствие, на ко­то­рое мы со­сла­лись с глав­ной стра­ницы, те­перь ра­бо­та­ет! Щелкните по ссыл­ке «view» ря­дом с одним из филь­мов – вы уви­ди­те ре­зуль­тат ра­бо­ты толь­ко что соз­дан­но­го пред­став­ления. Об­ра­ти­те внимание, что вы­во­дит­ся так­же удоб­ный спи­сок под­хо­дя­щих дей­ствий для те­ку­щей запи­си.

Ес­ли из­менить запись или соз­дать но­вую, CakePHP об­но­вит по­ля со вре­менем соз­дания и из­менения. Это часть ав­то­ма­ти­че­ско­го функ­цио­на­ла, пре­достав­ляе­мо­го кар­ка­сом. От­ре­дак­ти­руй­те па­ру запи­сей, что­бы по­смот­реть, как ме­ня­ют­ся их по­ля.

Что даль­ше?

Те­перь у нас есть пол­но­стью ра­бо­таю­щее при­ло­жение ба­зы дан­ных филь­мов, ко­то­рым мож­но поль­зо­вать­ся до­ма или раз­местить в Ин­тернете. Все за 20 ми­нут. Дру­гая боль­шая про­бле­ма, с ко­то­рой вы столк­не­тесь – чем за­нять­ся в вы­сво­бо­див­шее­ся вре­мя, по­ка CakePHP де­ла­ет всю гряз­ную ра­бо­ту. Уда­чи вам, и не за­будь­те рас­ска­зать нам о том, что у вас по­лу­чит­ся, на фо­ру­ме (http://forum.linuxformat.ru) – на­де­юсь, за что бы вы ни взя­лись, вы сэ­ко­но­ми­те мас­су дра­го­цен­но­го вре­ме­ни!

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