LXF141:CackePHP2

Материал из Linuxformat.

Перейти к: навигация, поиск
Учебник CakePHP
CakePHP

Содержание

CakePHP: Пи­шем за­груз­чик фай­лов

Часть II За­груз­чик фай­лов, что­бы де­лить­ся фай­ла­ми с кон­крет­ны­ми поль­зо­ва­те­ля­ми, а не со всем Ин­тер­не­том, пи­шет Грэм Уэл­дон.

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

Нам нуж­на воз­мож­ность за­дать вла­дель­ца для ка­ж­до­го фай­ла, а так­же раз­де­лить этот файл с дру­ги­ми поль­зо­ва­те­ля­ми (доступ на чтение). По­это­му оп­ре­де­лим две раз­лич­ных свя­зи ме­ж­ду фай­лом и поль­зо­ва­те­лем. Пре­достав­ление фай­ла в доступ опи­шем свя­зью «Име­ет и при­над­ле­жит мно­гим», или, со­кра­щен­но, ИПM. ИПM ис­поль­зу­ет таб­ли­цу join для свя­зи двух за­пи­сей, и в CakePHP есть стан­дарт­ное со­гла­шение, ко­то­ро­му мы бу­дем сле­до­вать, что­бы кар­кас сде­лал за нас всю гряз­ную ра­бо­ту (со­от­вет­ст­вую­щий код мож­но най­ти на LXFDVD).

В упо­мя­ну­той таб­ли­це join за­да­ют­ся поль­зо­ва­те­ли, ко­то­рым раз­ре­шен дос­туп к за­дан­ным фай­лам. Со­глас­но стан­дар­ту, имя таб­ли­цы join, ис­поль­зуе­мой для свя­зи ИПM, долж­но со­сто­ять из имен свя­зы­вае­мых таб­лиц в ал­фа­вит­ном по­ряд­ке, со­еди­нен­ных сим­во­лом под­чер­ки­ва­ния:

CREATE TABLE `uploads_users` (
 `id` CHAR(36) NOT NULL PRIMARY KEY,
 `upload_id` CHAR(36) NOT NULL,
 `user_id` CHAR(36) NOT NULL
 );

Соз­дай­те свои таб­ли­цы в но­вой ба­зе дан­ных, и зай­мем­ся вы­печ­кой и за­пус­ком про­ек­та.

На старт… вни­ма­ние… пе­чем!

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

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

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

Что­бы соз­дать ске­лет про­ек­та, в кон­со­ли ско­ман­дуй­те:

$ cake bake project fileshare
$ cd fileshare

За­тем на­строй­те со­еди­не­ние с ба­зой дан­ных. Из­ме­ни­те па­ра­мет­ры, при­ве­ден­ные в Лис­тин­ге 2 в фай­ле config/database.php, на под­хо­дя­щие для ва­шей ба­зы дан­ных. Дос­та­точ­но за­дать со­еди­не­ние “default”.

И по­ка мы за­ни­ма­ем­ся вы­печ­кой, взва­лив всю чер­ную ра­бо­ту на CakePHP, за­од­но вы­пе­чем кон­трол­ле­ры, мо­де­ли и пред­став­ле­ния, соз­дав ос­но­ву на­ше­го про­ек­та.

$ cake bake all user
$ cake bake all upload

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

За­пре­мся из­нут­ри

Клас­со­вая борь­ба

В PHP у нас нет про­странств имен, и клас­сам нель­зя да­вать име­на, уже ис­поль­зо­ван­ные в CakePHP. В CakePHP есть класс File, и мы не мог­ли дать имя “File” на­шей мо­де­ли в при­ме­ре – это при­ве­ло бы к кон­флик­ту клас­сов. Вме­сто не­го мы вос­поль­зо­ва­лись име­нем “Upload”. Спи­сок всех клас­сов CakePHP см. в от­кры­том API: http://api.cakephp.org.

У нас есть таб­ли­ца “users”, и уже ра­бо­та­ет до­бав­ление поль­зо­ва­те­ля – об этом по­за­бо­тил­ся CakePHP; от­крой­те при­ло­жение в брау­зе­ре, до­ба­вив к ад­ре­су users. На­при­мер, http://localhost/fileshare/users. Итак, что же де­лать даль­ше? Ха, па­ро­ли хра­нят­ся в от­кры­том ви­де; и нас как-то не про­сят вво­дить ло­гин и па­роль. От­крой­те файл app_controller.php в корне про­ек­та. Это пустой кон­трол­лер, от ко­то­ро­го на­сле­ду­ют функ­цио­нал все осталь­ные кон­трол­ле­ры при­ло­жения. Все, что мы сде­ла­ем здесь, бу­дет доступ­но во всех кон­трол­ле­рах, так что это пре­вос­ход­ное ме­сто, что­бы за­ста­вить поль­зо­ва­те­лей вво­дить ло­гин и па­роль. До­бавь­те ком­по­нен­ты Auth и Session. Те­перь ваш AppController бу­дет вы­гля­деть так:

<?php
 class AppController extends Controller {
 var $components = array(‘Auth’, ‘Session’);
 }
 ?>

По­про­бо­вав об­но­вить спи­сок users, вы по­лу­чи­те со­об­ще­ние об ошиб­ке, сиг­на­ли­зи­рую­щее о том, что дей­ст­вия login не су­ще­ст­ву­ет. Ес­ли по­смот­ри­те пов­ни­ма­тель­нее, то уви­ди­те, что URL то­же из­ме­нил­ся на /users/login. К сча­стью, всю са­мую труд­ную ра­бо­ту за нас уже сде­лал CakePHP, и нам ос­та­лось соз­дать дей­ст­вие (функ­цию) в кон­тол­ле­ре и фор­му для вхо­да в сис­те­му. От­крой­те controllers/users_controller.php и до­бавь­те ту­да дей­ст­вие login:

function login() {
 }

Ошиб­ки тут нет – функ­ция пус­та, и это все, что нам нуж­но для ау­тен­ти­фи­ка­ции в кон­трол­ле­ре.

Что­бы не пе­ре­хит­рить са­мих се­бя, убе­дим­ся, что мы мо­жем за­ре­ги­ст­ри­ро­вать поль­зо­ва­те­ля, ес­ли это еще не сде­ла­но. Мы поч­ти по­кон­чи­ли с ау­тен­ти­фи­ка­ци­ей поль­зо­ва­те­ля, и весь функ­цио­нал стал бы нам не­дос­ту­пен – не сде­лав ис­клю­че­ние для стра­ни­цы ре­ги­ст­ра­ции, мы не смог­ли бы вой­ти в на­шу кле­вую сис­те­му. Соз­дай­те ме­тод beforeFilter в кон­трол­ле­ре users и до­бавь­те ту­да код, пре­ду­пре­ж­даю­щий ком­по­нент Auth, что мы мо­жем за­хо­дить на стра­ни­цу ре­ги­ст­ра­ции, да­же если еще не во­шли в сис­те­му:

function beforeFilter() {
 $this->Auth->allow(‘add’);
 return parent::beforeFilter();
 }

Соз­дай­те пред­став­ле­ние login в но­вом фай­ле views/users/login.ctp, как опи­са­но в Лис­тин­ге 3 LXFDVD.

Об­но­ви­те стра­ни­цу с со­об­ще­ни­ем об ошиб­ке, и пе­редва­ми поя­вит­ся фор­ма для вхо­да в сис­те­му. Об­ра­ти­те вни­ма­ние, что вы смо­же­те зай­ти на стра­ни­цу /users/add, но все ос­таль­ные ссыл­ки бу­дут пе­ре­на­прав­лять­ся на стра­ни­цу /users/login. За­ре­ги­ст­ри­руй­те се­бя как поль­зо­ва­те­ля – это при­го­дит­ся для тес­ти­ро­ва­ния при­ло­же­ния. Про­верь­те со­дер­жи­мое ба­зы дан­ных. Вы уви­ди­те, что па­роль ав­то­ма­ти­че­ски пре­вра­тил­ся в хэш. Чу­дес­но! Так­же сто­ит уда­лить не­ко­то­рые из ав­то­ма­ти­че­ски сге­не­ри­ро­ван­ных по­лей и по­лей вво­да, ко­то­ры­ми мы не бу­дем поль­зо­вать­ся, что­бы у поль­зо­ва­те­лей был дос­туп толь­ко к раз­ре­шен­ным по­лям. Итак, уда­ли­те сле­дую­щее по­ле из пред­став­ле­ний add и edit в фай­лах views/users/add.ctp и views/users/edit.ctp:

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

За­гру­жа­ем фай­лы

Ин­декс users дос­ту­пен, ес­ли до­бав­ле­на ау­тен­ти­фи­ка­ция.

По­ра соз­дать дей­ст­вие для за­груз­ки фай­лов. Сна­ча­ла соз­да­дим под­ка­та­лог uploads в ка­та­ло­ге про­ек­та, где бу­дут хра­нить­ся за­гру­жен­ные фай­лы, и сде­ла­ем его вла­дель­цем поль­зо­ва­те­ля, от име­ни ко­то­ро­го за­пус­ка­ет­ся web-сер­вер. В од­них ди­ст­ри­бу­ти­вах это www-data, в дру­гих – apache или www. Ука­жи­те поль­зо­ва­те­ля для сво­ей сис­те­мы.

$ mkdir uploads
$ chown www-data uploads

А не по­напи­сать ли нам код? Начнем с из­менения страницы за­груз­ки фай­лов, что­бы фай­лы мож­но бы­ло за­гру­жать и безо­пас­но со­хра­нять. Bake стря­па­ет неплохую фор­му, но мы уда­лим из нее несколь­ко ав­то­ма­ти­че­­ски сгенери­ро­ван­ных по­лей и за­меним их по­лем за­груз­ки фай­ла. Столб­цы, ко­то­рые мы оп­ре­де­ли­ли в ба­зе дан­ных, пред­ва­ри­тель­но за­пол­ня­ют­ся ав­то­ма­ти­че­­ски. По­сле за­груз­ки фай­ла мы по­лу­чим всю необ­хо­ди­мую ин­фор­ма­цию о нем. Уда­ли­те по­ля вво­да filename, filesize и filemime из пред­став­ления за­груз­ки фай­лов в фай­ле views/uploads/add.ctp и до­бавь­те по­ле вво­да file. Мы не соз­да­ли стол­бец file в ба­зе дан­ных, по­это­му CakePHP не сде­ла­ет чер­но­вую ра­бо­ту для это­го по­ля, и нуж­но так­же ука­зать, ка­ко­го ти­па долж­но быть по­ле, что­бы оно соз­да­лось пра­виль­но. Сде­ла­ем и еще од­но неболь­шое из­менение – уда­лим по­ле вво­да user_id, соз­дан­ное для нас CakePHP. Вме­сто не­го до­ба­вим в кон­трол­лер код, ав­то­ма­ти­че­ски свя­зы­ваю­щий фай­лы с поль­зо­ва­те­лем, ко­то­рый в дан­ный мо­мент во­шел в сис­те­му. По­смотрим, как те­перь вы­гля­дят поля вво­да на фор­ме.

<?php echo $this->Form->create(‘Upload’, array(‘type’ => ‘file));?>
 <fieldset>
 <legend><?php __(‘Add Upload’); ?></legend>
 <?php
 echo $this->Form->input(‘title’);
 echo $this->Form->input(‘description’);
 echo $this->Form->input(file’, array(‘type’ => ‘file));
 echo $this->Form->input(‘User’);
 ?>
 </fieldset>
 <?php echo $this->Form->end(__(‘Submit’, true));?>

Об­ра­бот­ка за­гру­жен­но­го фай­ла

Конеч­но, файл у нас есть, но нуж­но еще и об­ра­бо­тать его долж­ным об­ра­зом, что­бы вы­дать со­об­щение о ошиб­ке, ес­ли файл за­гру­жен некор­рект­но, ли­бо со­хранить его в на­шем ка­та­ло­ге uploads, ес­ли он за­гру­жен кор­рект­но. Для это­го от­кро­ем файл controllers/uploads_controller.php в соз­дан­ном про­ек­те и из­меним функ­цию add(): пусть об­ра­ба­ты­ва­ет файл, ес­ли он есть. В треть­ей стро­ке этой функ­ции про­ис­хо­дит со­хранение дан­ных мо­де­ли. Из­мените опе­ра­тор усло­вия так, что­бы в нем вы­зы­ва­лась функ­ция uploadFile(), ко­то­рую мы на­пи­шем чуть поз­же:

if ($this->uploadFile() && $this->Upload->save($this->data)) {

Про­сто, не прав­да ли? Те­перь соз­да­дим в том же кон­трол­ле­ре функ­цию uploadFile():

function uploadFile() {
 $file = $this->data[‘Upload’][file];
 if ($file[‘error’] === UPLOAD_ERR_OK) {
 $id = String::uuid();
 if (move_uploaded_file($file[‘tmp_name’], APP.’uploads’.
 DS.$id)) {
 $this->data[‘Upload’][‘id’] = $id;
 $this->data[‘Upload’][‘user_id’] = $this->Auth->user(‘id’);
 $this->data[‘Upload’][‘filename’] = $file[‘name’];
 $this->data[‘Upload’][filesize] = $file[‘size’];
 $this->data[‘Upload’][‘filemime’] = $file[‘type’];
 return true;
 }
 }
 return false;
 }

Опять же, все про­сто. Мы за­гру­жа­ем файл, и ес­ли мы мо­жем пе­ре­мес­тить его в нуж­ный ка­та­лог, воз­вра­ща­ем true. В про­цес­се это­го мы вруч­ную генери­ру­ем иден­ти­фи­ка­тор, ко­то­рый станет безо­пас­ным именем со­хра­няе­мо­го фай­ла. Это ис­клю­чит непри­ят­но­сти от поль­зо­ва­те­лей, за­гру­жаю­щих фай­лы со стран­ны­ми и по­тен­ци­аль­но опас­ны­ми для сис­те­мы име­на­ми, ко­то­рые в про­тив­ном слу­чае уго­дят пря­мо в ва­шу фай­ло­вую сис­те­му. Руч­ная генера­ция UUID с по­мо­щью ме­то­да String::uuid() уст­ра­ня­ет эту ды­ру в безо­пас­но­сти и га­ран­ти­ру­ет безо­пас­ную за­груз­ку фай­ла, а ис­ход­ное имя фай­ла хранит­ся в ба­зе дан­ных и от­прав­ля­ет­ся поль­зо­ва­те­лю при ска­чи­вании.

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

Еще од­на кру­тая вещь, ко­то­рую мы здесь сде­ла­ем – свя­жем поль­зо­ва­те­ля с $this->Auth->user(‘id’): это иден­ти­фи­ка­тор поль­зо­ва­те­ля, во­шед­ше­го в дан­ный мо­мент в сис­те­му. Так как ранее мы по­за­бо­ти­лись о безо­пас­но­сти, то зна­ем, что поль­зо­ва­тель дол­жен за­ре­ги­ст­ри­ро­вать­ся, что­бы от­крыть эту страницу, по­это­му его иден­ти­фи­ка­тор не мо­жет быть пустым и всегда кор­рек­тен.

Уда­ля­ем свя­зи

Вы за­ме­ти­те, что мы про­дуб­ли­ро­ва­ли свя­зи для мо­де­лей User и Upload. Возь­мем, на­при­мер, мо­дель User в фай­ле models/user.php; CakePHP соз­дал свя­зи hasMany и hasAndBelongsToMany, обе с ин­дек­сом Upload. Ра­бо­тать это не бу­дет: кон­фликт имен при­ве­дет к то­му, что в пред­став­ле­ни­ях ото­бра­зят­ся не­вер­ные дан­ные. Из­ме­ни­те связь hasAndBelongsToMany в мо­де­ли User на Shared­Upload. Ана­ло­гич­но, в мо­де­ли Upload в фай­ле models/upload.php из­ме­ни­те связь ИПМ на SharedUser:

Реа­ли­зо­вать за­груз­ку фай­лов про­сто.

// User Model
 var $hasAndBelongsToMany = array(
 ‘SharedUpload’ => array(
 ‘className’ => ‘Upload’,
 ...
 // Upload Model
 var $hasAndBelongsToMany = array(
 ‘SharedUser’ => array(
 ‘className’ => ‘User’,
 ..

Что­бы эти из­ме­не­ния свя­зей кор­рект­но об­ра­бо­та­лись в пред­став­ле­ни­ях, из­ме­ни­те ин­декс, на ко­то­рый ссы­ла­ют­ся пред­став­ле­ния в раз­де­ле related в ниж­ней час­ти ин­дек­сов view. В фай­ле views/users/view.ctp из­ме­ни­те две стро­ки

<?php if (!empty($user[‘pload’])):?>
 foreach ($user[‘Upload’] as $upload):

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

<?php if (!empty($user[‘SharedUpload’])):?>
 foreach ($user[‘SharedUpload’] as $upload):

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

Про­смотр и ска­чи­вание фай­лов

Ес­ли вы уже по­иг­ра­ли с на­ви­га­ци­ей по имею­щим­ся пред­став­лениям, вам по­па­да­лась страница пред­став­ления для од­но­го из за­гру­жен­ных фай­лов. На ней по­ка­за­ны все ме­та­дан­ные фай­ла, но сам файл ска­чать по­ка нель­зя. Да­вай­те из­меним кое-что так, что­бы поя­ви­лась воз­мож­ность ска­чи­вания фай­лов, и у нас поя­вил­ся доступ к ним. Пер­вым де­лом до­бавь­те ссыл­ку в файл пред­став­ления views/uploads/view.ctp, в лю­бом мес­те (я ре­шил до­ба­вить ее в са­мый низ):

<dt<?php if ($i % 2 == 0) echo $class;?>><?php __(‘Download’);?></dt>
 <dd<?php if ($i++ % 2 == 0) echo $class;?>>
 <?php echo $this->Html->link(__(‘Download’, true),
 array(‘action’ => ‘download’, $upload[‘Upload’][‘id’])); 
 ?>&nbsp;
 </dd>

С этой ссыл­кой по­ра сно­ва принять­ся за дело и соз­дать дей­ст­вие для кон­трол­ле­ра: пускай оно об­ра­ба­ты­вает ска­чи­вание фай­ла. От­крой­те UploadsController в фай­ле controllers/uploads_controller.php сно­ва и до­бавь­те функ­цию ска­чи­вания. Она иниции­ру­ет ска­чи­вание и воз­вра­ща­ет поль­зо­ва­те­лю файл с ис­ход­ным именем, под ко­то­рым он был за­гру­жен. Код этой функ­ции слиш­ком ве­лик, что­бы по­ме­щать его здесь, и вы най­де­те его на на­шем DVD в Лис­тин­ге 4.

Те­перь щелкните по этой ссыл­ке, и файл начнет за­гру­жать­ся че­рез ваш брау­зер! В этой функ­ции нуж­но кое-что до­де­лать, но по­верь­те, CakePHP уже сде­лал мно­го боль­ше. Сна­ча­ла про­ве­рим, есть ли иден­ти­фи­ка­тор. За­тем по­пы­та­ем­ся най­ти в ба­зе дан­ных запись о за­груз­ке фай­ла с та­ким иден­ти­фи­ка­то­ром, и по­ка мы там, про­ве­рим, что за­груз­ка свя­за­на с поль­зо­ва­те­лем, ко­то­рый в дан­ный мо­мент в сис­те­ме, или что файл был из­на­чаль­но за­гру­жен дан­ным поль­зо­ва­те­лем. И в том, и в дру­гом слу­чае доступ раз­ре­шен. Ес­ли за­про­сы не да­ют ре­зуль­та­та, зна­чит поль­зо­ва­тель пы­та­ет­ся по­лу­чить файл, к ко­то­ро­му у него нет досту­па, и мы пе­ре­на­пра­вим его к спи­ску фай­лов.

По­ка­жем лишь то, что мож­но

Что­бы спи­сок фай­лов имел смысл для всех поль­зо­ва­те­лей, нуж­но так­же из­менить дей­ст­вие index() в кон­трол­ле­ре Uploads, что­бы вы­пол­нять ана­ло­гич­ную фильт­ра­цию и по­ка­зы­вать в спи­ске толь­ко те фай­лы, к ко­то­рым у поль­зо­ва­те­лей есть пра­ва досту­па, ина­че в нем бу­дет мас­са фай­лов, о ко­то­рых им знать из­лиш­не! Из­ме­ни­те дей­ст­вие index та­ким об­ра­зом:

function index() {
 $this->Upload->bindModel(array(‘hasOne’ =>
 array(‘UploadsUser’)), false);
 $this->paginate = array(
 ‘conditions’ => array(
 ‘OR’ => array(
 ‘UploadsUser.user_id’ => $this->Auth->user(‘id’),
 ‘Upload.user_id’ => $this->Auth->user(‘id’),
 ),
 )
 );
 $this->set(‘uploads’, $this->paginate());
 }

На этот раз нам при­шлось до­ба­вить па­ра­метр false к вы­зо­ву bindModel(), что­бы га­ран­ти­ро­вать кор­рект­ное раз­биение на стра­ницы. Функ­ция раз­биения на страницы принима­ет два от­дель­ных ре­зуль­та­та из ба­зы дан­ных. Пер­вый оп­ре­де­ля­ет чис­ло эле­мен­тов в таб­ли­це, со­от­вет­ст­ву­щих за­про­су, а вто­рой фак­ти­че­­ски воз­вра­ща­ет дан­ные. Па­ра­метр false ве­лит CakePHP удер­жать свя­зы­вание в пре­де­лах од­но­го за­про­са. Про­стое пра­ви­ло: ес­ли вы поль­зуе­тесь ме­то­дом bindModel и раз­бив­кой на страницы, в конец ме­то­да до­бавь­те false.

Дей­ст­вие view() от по­доб­ной фильт­ра­ции то­же вы­иг­ры­ва­ет:

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

function view($id = null) {
 if (!$id) {
 $this->Session->setFlash(__(‘Invalid upload’, true));
 $this->redirect(array(‘action’ => ‘index’));
 }
 $this->Upload->bindModel(array(‘hasOne’ =>
 array(‘UploadsUser’)));
 $upload = $this->Upload->find(‘first’, array(
 ‘conditions’ => array(
 ‘Upload.id’ => $id,
 ‘OR’ => array(
 ‘UploadsUser.user_id’ => $this->Auth->user(‘id’),
 ‘Upload.user_id’ => $this->Auth->user(‘id’),
 ),
 )
 ));
 if (!$upload) {
 $this->Session->setFlash(__(‘Invalid upload’, true));
 $this->redirect(array(‘action’ => ‘index’));
 }
 $this->set(‘upload’, $upload);
 }

За­круг­ля­ем­ся

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

public function logout() {
 $this->redirect($this->Auth->logout());
 }

Пред­став­ления не нуж­но, и пе­ре­на­прав­ление про­из­во­дит­ся, как толь­ко поль­зо­ва­тель от­кры­ва­ет URL /users/logout по­сле унич­то­жения сес­сии и вы­хо­да поль­зо­ва­те­ля из сис­те­мы.

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

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

Ис­ход­ные ко­ды уро­ка

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

Личные инструменты
  • Купить электронную версию
  • Подписаться на бумажную версию