Дурьдатгал:
Бидний орчуулгын хэсэгт маань Ганбат ах өөрийн хүчээ хавсаргалаа. Таньд энэ хичээл таалагдсан бол Ганбат ахад баярлалаа гэж хэлэхээ мартав. Форм фраймворк бол symfony -ын нилээн тод давуу талын нэг. Формын талаар мэдэх нь та нэг том давааны цаана гарлаа л гэж мэд. За амжилт хүсье.
Орчуулсан Ш.Ганбат
(combat_mn@yahoo.com)
Practical symfony 10 дахь өдөр: Формууд
Өмнөх өдрийн хичээлийг бид Symfony дахь сорилтын фреймворкуудтай танилцах алхмаас гялалзтал эхлүүлсэн. Өнөөдөр бид формын фреймворкуудтай танилцах болно.
Формын фреймворк (The Form Framework)
Сайт бүр энгийн харилцааны формоос эхлэн олон тооны талбарууд бүхий нийлмэл түвэгтэй олон янзын формуудыг агуулсан байдаг. Форм бичнэ гэдэг нь формын HTML кодыг бичих, талбар нэг бүрийн утгыг шалгаж баталгаажуулах, өгөгдлийг боловсруулан баазад хадгалах, алдааны мэдээллүүдийг гаргах, түүнчлэн талбаруудыг дахин дахин бөглөж тэр бүрт формыг дуудах гээд вэб хөгжүүлэгчдийн хувьд өдөр тутам тохиолддог хялбар биш уйтгартай ажлуудын нэг билээ.
Дугуйг дахин дахин эргүүлэх нь мэдээж утгагүй хэрэг. Ийм учраас Symfony нь формын удирдлагыг хялбаршуулах зорилгоор тусгайлсан фреймворкийг бий болгосон байна. Формын фреймворк нь гурван хэсгээс бүрдэнэ:
- validation: Валидэйтор – энэ бол оролтын өгөгдлийг (integer, string, email хаяг, …) шалгах зориулалт бүхий классуудыг агуулсан дэд фреймворк
- widgets: Виджетүүд – энэ бол формын HTML талбаруудыг (input, textarea, select, …) харуулах классууд бүхий дэд фреймворк
- forms: Формууд – энэ бол өөртөө виджетүүд болон валидэйторуудыг нэгтгэсэн, формыг удирдахад туслах тохиромжтой арга хэрэгсэл бүхий классууд. Форм дахь талбар бүр нь өөр өөрийн валидэйтор болон виджеттэй байдаг.
Формууд
Symfony-н формууд нь талбаруудаас бүрдэх класс юм. Талбар бүр нь нэр, валидэйтор, виджеттэй. Энгийн харилцах форм (ContactForm
)-ыг дараах классаар илэрхийлж болно:
class ContactForm extends sfForm { public function configure() { $this->setWidgets(array( 'email' => new sfWidgetFormInputText(), 'message' => new sfWidgetFormTextarea(), )); $this->setValidators(array( 'email' => new sfValidatorEmail(), 'message' => new sfValidatorString(array('max_length' => 255)), )); } }
Формын талбарууд нь setValidators()
ба setWidgets()
методуудын тусламжтайгаар configure()
методод байршдаг.
Формын фреймворк нь олон тооны виджет болон валидэйтортой холбогддог. API-д тэдгээрийн бүгдийнх нь сонголтууд, алдаанууд, алдааны дефаолт мессежүүдийн талаар дэлгэрэнгүй тусгасан.
Валидэйтор, виджетүүдийн нэрс нь маш илэрхий, тухайлбал: email
талбар нь (sfWidgetFormInput
) HTML-рүү <input>
тэг болж хөрвөх бөгөөд , и-мэйл хаяг (sfValidatorEmail
) гэсэн нөхцлөөр, message
талбар нь (sfWidgetFormTextarea
) <textarea>
тэг болох бөгөөд 255 тэмдэгтээс илүүгүй урттай string (sfValidatorString
) гэсэн нөхцлөөр тус тус шалгагдана.
Бүх талбаруудын required
сонголтын дефаолт утга нь true
байдаг тул email
-ийн валидэйтор нь new sfValidatorEmail(array('required' => true))
гэсэнтэй адил юм.
Та mergeForm()
методын тусламжтайгаар, эсвэл embedForm()
метод ашиглан нэг формыг нь нөгөөд нь байрлуулах замаар хоёр формыг нэгтгэх боломжтой:
$this->mergeForm(new AnotherForm()); $this->embedForm('name', new AnotherForm());
Формын Doctrine
Формуудын мэдээлээл нь тогтмол хугацаанд серилэгдэн (serialized) баазад хадгадагдаж байдаг. Symfony таны моделийн талаар бүгдийг мэдэж байдаг бөгөөд, дээрхи мэдээлэл дээр суурилан формуудыг автоматаар үүсгэдэг. Жишээлбэл, 3 дахь өдөр та doctrine:build --all
таскийг дуудахад Symfony нь doctrine:build --forms
таскийг автоматаар дуудсан гэсэн үг:
$ php symfony doctrine:build --forms
doctrine:build --forms
таск нь формын классуудыг үүсгэн lib/form/
директорит хадгалдаг. Үүссэн файлуудын зохион байгуулалт нь lib/model/
-ийнхтэй ойролцоо. Моделийн класс бүр нь формын класстай холбоотой (ж.нь JobeetJob
ба JobeetJobForm
) бөгөөд, суурь классаа өвлөдөг тул анхны хэлбэртээ ямар нэг метод агуулдаггүй, хоосон байдаг:
// lib/form/doctrine/JobeetJobForm.class.php class JobeetJobForm extends BaseJobeetJobForm { public function configure() { } }
lib/form/doctrine/base/
дэд директори дахь файлуудаас Та Symfony-н виджет ба валидэйторуудын олон сайхан жишээг олж үзэх боломжтой.
Та тодорхой моделийн хувьд харгалзах параметрүүдийг symfony
-н Doctrine-д зааж өгснөөр форм үүсгэлтийг хориглох боломжтой:
SomeModel: options: symfony: form: false filter: false
Ажлын байрны формыг тохируулах (Customizing the Job Form)
Ажлын байрны форм нь формуудын ажиллагааг судлах сайхан жишээ юм. Энэхүү тохиргоог алхам алхмаар харцгаая.
Эхлээд layout дахь “Post a job” линкийг бүх өөрчлөлтүүд таны браузерт шууд харагддаг байхаар болгон өөрчилье:
<!-- apps/frontend/templates/layout.php --> <a href="<?php echo url_for('@job_new') ?>">Post a Job</a>
Формын doctrine нь дефаолтдаа хүснэгтийн бүх багануудын талбарыг харуулдаг. Гэв ч ажлын байрны формын хувьд тэдгээрийн зарим хэсгийг эцсийн хэрэглэгч засварлах боломжгүй байх ёстой. Ийм талбаруудыг unset() методоор формоос хасч болно.
// lib/form/doctrine/JobeetJobForm.class.php class JobeetJobForm extends BaseJobeetJobForm { public function configure() { unset( $this['created_at'], $this['updated_at'], $this['expires_at'], $this['is_activated'] ); } }
Талбаруудыг формоос хасахад холбогдох виджет ба валидэйтор нь дагаж устдаг.
Мөн та харуулахыг хүсэхгүй байгаа талбаруудаа формоос хасахын оронд, формд харуулах талбаруудыг useFields()
метод ашиглан тодорхой зааж өгч болно:
// lib/form/doctrine/JobeetJobForm.class.php class JobeetJobForm extends BaseJobeetJobForm { public function configure() { $this->useFields(array('category_id', 'type', 'company', 'logo', 'url', 'position', 'location', 'description', 'how_to_apply', 'token', 'is_public', 'email')); } }
useFields()
метод нь нууц талбарууд нэмэх болон талбаруудын дарааллыг өөрчлөх массив гэсэн хоёр үйлдлийг автоматаар танд зориулж хийдэг.
Талбаруудыг тодорхой зааж өгсөн нөхцөлд суурь формд нэмсэн шинэ талбар таны формд автоматаар гарч ирэхгүй (өгөгдлийн сангийн холбогдох хүснэгтэд шинэ багана нэмсэн моделийн формыг сана).
Зарим тохиолдолд формыг өгөгдлийн баазын схемийн шинж чанарыг шууд өвлөж авснаас илүү нарийвчлалтайгаар тохируулах шаардлага гардаг. Жишээлбэл, email
багана нь баазын схемдээ varchar
, харин бидэнд түүнийг и-мэйл эсэхийг шалгах шаардлагатай. Тэгэхээр дефаолтаар өгөгдсөн sfValidatorString
-ийг sfValidatorEmail
болгон өөрчилье:
// lib/form/doctrine/JobeetJobForm.class.php public function configure() { // ... $this->validatorSchema['email'] = new sfValidatorEmail(); }
Дефаолт валидэйторыг солих нь дандаа шилдэг шийдэл байдаггүй. Учир нь энэ ажиллагааны улмаас өгөгдлийн баазын схемээс уламжилсан баталгаажуулах зарчим нь алдагддаг (new sfValidatorString(array('max_length' => 255))
). Иймд бараг бүх тохиолдолд одоо ашиглагдаж байгаа дээрээ нэмж шинэ валидэйтор sfValidatorAnd
тавьж өгөх нь зохимжтой байдаг.
// lib/form/doctrine/JobeetJobForm.class.php public function configure() { // ... $this->validatorSchema['email'] = new sfValidatorAnd(array( $this->validatorSchema['email'], new sfValidatorEmail(), )); }
sfValidatorAnd
валидэйтор нь өгөгдлийг шалгах валидэйторуудын массивыг өөрийн утгандаа авдаг. Үүний арга заль нь бид одоо хэрэглэгдэж буй валидэйтор руу өгөгдлийг илгээхийн хажуугаар бас нэг шинийг нэмж байгаад оршино.
Түүнчлэн та sfValidatorOr
валидэйторыг ашиглаж болно. Энэ тохиолдолд ядаж аль нэг валидэйторт тэнцсэн нөхцөлд түүний утгыг зөв гэж тооцдог. Иймд мэдээжээр та нарийн логиктой валидэйтор бий болгоё гэвэл sfValidatorAnd
ба sfValidatorOr
валидэйторуудыг нэгтгэн ашиглаж болно.
type
багана нь баазын схемд varchar
хэдий ч, бид түүний утгыг урьчилан тодорхойлсон full time, part time юм уу freelance жагсаалтаар хязгаарлахыг хүсэж байна.
Үүний тулд эхлээд JobeetJobTable
дахь боломжит утгуудыг тодорхойлцгооё:
// lib/model/doctrine/JobeetJobTable.class.php class JobeetJobTable extends Doctrine_Table { static public $types = array( 'full-time' => 'Full time', 'part-time' => 'Part time', 'freelance' => 'Freelance', ); public function getTypes() { return self::$types; } // ... }
Үүний дараа type
талбарт sfWidgetFormChoice
виджетийг хэрэглэцгээе:
$this->widgetSchema['type'] = new sfWidgetFormChoice(array( 'choices' => Doctrine_Core::getTable('JobeetJob')->getTypes(), 'expanded' => true, ));
sfWidgetFormChoice
виджет нь сонголтын хэрэгсэл бөгөөд, зарим тохиргооноосоо хамаарч (expanded
ба multiple
) бусад виджетүүдэд янз бүрээр илэрхийлэгдэж болно:
- Dropdown list (
<select>
):array('multiple' => false, 'expanded' => false)
- Dropdown box (
<select multiple="multiple">
):array('multiple' => true, 'expanded' => false)
- List of radio buttons:
array('multiple' => false, 'expanded' => true)
- List of checkboxes:
array('multiple' => true, 'expanded' => true)
Хэрэв та radio button-уудын аль нэгийг дефаолтаар сонгуулахыг хүсэж байвал (ж.нь full-time
) баазын схем дахь дефаолт утгыг өөрчилж болно.
Хэдийгээр та одоо ямар ч хүн буруу өгөгдөл оруулж чадахгүй гэж бодож байгаа ч хакер curl юмуу Firefox Web Developer Toolbar ашиглан виджетийг хялбархнаар тойрон гарч чадна. Иймд валтдэйторыг сольж сонголтуудыг хязгаарлая:
$this->validatorSchema['type'] = new sfValidatorChoice(array( 'choices' => array_keys(Doctrine_Core::getTable('JobeetJob')->getTypes()), ));
logo
талбарт тухайн ажлын байранд хамаарах байгууллагын логоны файлын нэр хадгалагдах бөгөөд бид виджетийг file input тэг болгон өөрчлөх шаардлагатай.
$this->widgetSchema['logo'] = new sfWidgetFormInputFile(array( 'label' => 'Company logo', ));
Symfony-н форм нь талбар бүрт label-ийг автоматаар үүсгэдэг (<label> тэг) бөгөөд түүнийг setLabels()
метод ашиглан өөрчилж болно:
$this->widgetSchema->setLabels(array( 'category_id' => 'Category', 'is_public' => 'Public?', 'how_to_apply' => 'How to apply?', ));
Бид бас дефаолт валидэйторыг өөрчлөх шаардлагатай:
$this->validatorSchema['logo'] = new sfValidatorFile(array( 'required' => false, 'path' => sfConfig::get('sf_upload_dir').'/jobs', 'mime_types' => 'web_images', ));
sfValidatorFile
нь нэлээд сонирхол төрүүлэхүйц бөгөөд, олон зүйлийг хийдэг:
- Тухайн файл вэбд нийцэх формат (
mime_types
) мөн эсэхийг шалгана - Файлын нэрийг давхцуулалгүйгээр оноож өгнө
- Файлыг зааж өгсөн замаар (given
path
) хадгадна logo
талбарыг үүссэн нэрээр нь шинэчилнэ
Та логонуудыг хадгалах шинэ директори (web/uploads/jobs/
) үүсгээд, бичилт хийх боломжтой эсэхийг нягтла.
Валидэйтор нь баазад зөвхөн файлын нэрийг хадгалдаг тул showSuccess
темплэйтэд хэрэглэгдэж буй логоны замыг өөрчил.
// apps/frontend/modules/job/templates/showSuccess.php <img src="/uploads/jobs/<?php echo $job->getLogo() ?>" alt="<?php echo $job->getCompany() ?> logo" />
Хэрэв модольд generateLogoFilename()
метод тодорхойлогдсон байвал тэр нь валидэйторт дуудагдаж, үүний дүнд логоны файлын дефаолтаар үүссэн нэр өөрчлөгддөг. Метод нь аргументдаа sfValidatedFile
объектыг авдаг.
Дээрхийн адилаар дурын label-ийг өөрчлөх боломжтой тул үүнийг ашиглан та формын талбарууддад тайлбар (help) хийж өгч болно:
$this->widgetSchema->setHelp('is_public', 'Whether the job can also be published on affiliate websites or not.');
Эцэст нь JobeetJobForm
класс дараах байлалтай болно:
// lib/form/doctrine/JobeetJobForm.class.php class JobeetJobForm extends BaseJobeetJobForm { public function configure() { unset( $this['created_at'], $this['updated_at'], $this['expires_at'], $this['is_activated'] ); $this->validatorSchema['email'] = new sfValidatorAnd(array( $this->validatorSchema['email'], new sfValidatorEmail(), )); $this->widgetSchema['type'] = new sfWidgetFormChoice(array( 'choices' => Doctrine_Core::getTable('JobeetJob')->getTypes(), 'expanded' => true, )); $this->validatorSchema['type'] = new sfValidatorChoice(array( 'choices' => array_keys(Doctrine_Core::getTable('JobeetJob')->getTypes()), )); $this->widgetSchema['logo'] = new sfWidgetFormInputFile(array( 'label' => 'Company logo', )); $this->widgetSchema->setLabels(array( 'category_id' => 'Category', 'is_public' => 'Public?', 'how_to_apply' => 'How to apply?', )); $this->validatorSchema['logo'] = new sfValidatorFile(array( 'required' => false, 'path' => sfConfig::get('sf_upload_dir').'/jobs', 'mime_types' => 'web_images', )); $this->widgetSchema->setHelp('is_public', 'Whether the job can also be published on affiliate websites or not.'); } }
Формын темплэйт
Формын классын тохиргоо нэгэнт хийгдсэн болохоор одоо бид түүнийг дэлгэц дээр гаргая. Job формын темплэйт нь танд шинэ ажлын байр үүсгэхэд, эсвэл ажлын байрны мэдээллийг засварлахад хэрэг болно. Нэмж хэлэхэд newSuccess.php
болон editSuccess.php
темплэйтүүд хоорондоо маш төстэй:
<!-- apps/frontend/modules/job/templates/newSuccess.php --> <?php use_stylesheet('job.css') ?> <h1>Post a Job</h1> <?php include_partial('form', array('form' => $form)) ?>
Хэрэв та job
–ын CSS-ийг оруулж амжаагүй байгаа бол яг одоо түүнийг хоёр темплэйтдээ оруулж өгөх (<?php use_stylesheet('job.css') ?>
) цаг нь болсон.
Форм нь өөрөө хэсэгчилсэн (partial) _form
болж үүсдэг. _form
-ын кодыг дараах кодоор соль:
<!-- apps/frontend/modules/job/templates/_form.php --> <?php use_stylesheets_for_form($form) ?> <?php use_javascripts_for_form($form) ?> <?php echo form_tag_for($form, '@job') ?> <table id="job_form"> <tfoot> <tr> <td colspan="2"> <input type="submit" value="Preview your job" /> </td> </tr> </tfoot> <tbody> <?php echo $form ?> </tbody> </table> </form>
use_javascripts_for_form()
болон use_stylesheets_for_form()
хэлперүүд нь формын виджетэд шаардагдах JavaScript болон CSS файлуудыг холбож өгдөг.
Ажлын байрны формуудад JavaScript, CSS хэрэггүй байсан ч тэдгээрийг “юмыг яаж мэдэх вэ” гээд үлдээхэд муу зүйл байхгүй. Энэ нь та хэрэв хэзээ нэгэн цагт формыг өөрчлөхөөр шийдэж, JavaScript юмуу CSS нэмэхээр бол цагийг тань хэмнэх ач тустай.
form_tag_for()хэлпер нь тухайн формын <form>
тэгийг үүсгэдэг ба объект нь шинэ үү үгүй юу гэдгээс үл хамааран HTTP методыг POST
эсвэл PUT
хийх зорилгоор өөрчлөх юмуу route хийдэг. Түүнчлэн тухайн форм ядаж нэг ширхэг file input тэг агуулж байвал хэлпер нь multipart
атрибютад санаа тавьдаг.
Эцэст нь формын виджетийг <?php echo $form ?>
үүсгэнэ.
Формын гадаад төрх ба мэдрэмж (feel)-ийг тохируулах
<?php echo $form ?>
нь дефаолтдаа формын виджетийг хүснэгт хэлбэрээр үүсгэдэг.
Формын гадаад төрхийг өөрчлөх шаардлага танд цөөн биш тохиолдоно. Форм объект нь үүнд зориулсан олон методыг танд санал болгодог:
Метод | Тайлбар |
render() |
Формыг үүсгэнэ (echo $form -той ижил) |
renderHiddenFields() |
Нууц талбар үүсгэнэ (hidden fields) |
hasErrors() |
Формд алдаа байвал true утгыг буцаана |
hasGlobalErrors() |
Формд глобал алдаа байвал true утгыг буцаана |
getGlobalErrors() |
Глобал алдаануудыг массив хэлбэрээр буцаана |
renderGlobalErrors() |
Глобал алдаануудыг харуулна |
Формтой ажиллахдаа түүнийг талбаруудын (field) массив гэж ойлгож болно. Тухайлбал та company
талбар руу $form['company']
гэж хандаж болно. Буцаан илгээгдэх объект нь энэхүү талбарын элемент нэг бүрийг илэрхийлэх методуудыг тодорхойлсон байна:
Метод | Тайлбар |
renderRow() |
Талбарын мөрийг үүсгэнэ |
render() |
Талбарын виджетийг үүсгэнэ |
renderLabel() |
Талбарын label тэгийг үүсгэнэ |
renderError() |
Хэрэв алдаа байвал түүнийг харуулна |
renderHelp() |
Талбарт зорулсан тусламжийн мэдээллийг харуулна |
echo $form
нь дараахтай ижил:
<?php foreach ($form as $widget): ?> <?php echo $widget->renderRow() ?> <?php endforeach ?>
Формын үйлдлүүд
Бидэнд одоо формын класс болон түүнийг харуулах темплэйт байна. Тэгэхээр энэ бүхэн ажиллаж ямар нэг үйлдэл хийх цаг нь болсон гэсэн үг.
Ажлын байрны форм нь job
модулийн таван үйлдлийг удирддаг:
- new: Ажлын байр үүсгэх хоосон формыг харуулна
- edit: Ажлын байрыг засварлах формыг харуулна
- create: Хэрэглэгчийн оруулсан өгөгдөл бүхий шинэ ажлын байрыг үүсгэнэ
- update: Хэрэглэгчийн өөрчилсөн өгөгдлийн дагуу ажлын байрны мэдээллийг шинэчилнэ
- processForm:
create
баupdate
үйлдлүүдээр дуудагддаг (баталгаажуулах, талбар бөглөлтийг хянах, формыг серилж баазад хадгалах үүрэгтэй)
Бүх форм дараах амьдралын мөчлөгийг туулдаг:
Бид 5 хоногийн өмнө job
модулийн Doctrine-ий route-үүдийг үүсгэсэн. Одоо тэдгээрийг формын үйлдлүүдийг удидахад зориулан хялбаршуулъя:
// apps/frontend/modules/job/actions/actions.class.php public function executeNew(sfWebRequest $request) { $this->form = new JobeetJobForm(); } public function executeCreate(sfWebRequest $request) { $this->form = new JobeetJobForm(); $this->processForm($request, $this->form); $this->setTemplate('new'); } public function executeEdit(sfWebRequest $request) { $this->form = new JobeetJobForm($this->getRoute()->getObject()); } public function executeUpdate(sfWebRequest $request) { $this->form = new JobeetJobForm($this->getRoute()->getObject()); $this->processForm($request, $this->form); $this->setTemplate('edit'); } public function executeDelete(sfWebRequest $request) { $request->checkCSRFProtection(); $job = $this->getRoute()->getObject(); $job->delete(); $this->redirect('job/index'); } protected function processForm(sfWebRequest $request, sfForm $form) { $form->bind( $request->getParameter($form->getName()), $request->getFiles($form->getName()) ); if ($form->isValid()) { $job = $form->save(); $this->redirect('job_show', $job); } }
Та /job/new
хуудсыг нээвэл шинэ форм үүсч темплэйт рүү өгөгдөнө (new
үйлдэл).
Хэрэглэгч формыг илгээхэд (create
үйлдэл) форм нь өгөгдлүүдтэй холбогдож (bind()
метод) валидэйторыг дууддаг.
Форм нь холбогдомогцоо өгөгдөл зөв эсэхийг isValid()
методын тусламжтайгаар шалгана: Хэрэв формын өгөдөл зөв бол (returns true
) тухайн ажлын байр баазад хадгалагдаж ($form->save()
) хэрэглэгчийн өмнө сая үүссэн ажлын байрыг харах хуудас нээгдэнэ; Хэрэв өгөгдөл буруу бол newSuccess.php
темплэйт алдааны мессежүүдийн хамт дахин дуудагдана.
setTemplate()
метод нь тухайн үйлдэлд ашиглагдсан темплэйтийг өөрчилдөг. Хэрэв формын өгөгдөл буруу бол create
ба update
үйлдлүүд нь тухайн формыг алдааны мессежүүдийн хамт дахин харуулахдаа new
болон edit
үйлдлүүдэд ашигласан темплэйтийг хэрэглэнэ.
Ажлын байрны мэдээллийг засварлах ажиллагаа нь дээрхтэй бараг ижил. New
ба edit
үйлдлүүдийн хоорондын ганц ялгаа нь формын конструкторт эхний аргументаар засварлагдаж буй Job объект илгээгддэг.
Энэ объект нь темплэйт дахь виджетийн дефаолт утгад хэрэглэгдэнэ (дефаолт утга нь формын Doctrine-д объект хэлбэртэй, ердийн формуудын хувьд энгийн массив хэлбэртэй байна).
Түүнчлэн та анх форм үүсгэхдээ л түүний дефаолт утгыг тодорхойлж өгч болно. Үүнийг нэг бол баазын схемд утгыг шууд зарлах, эсвэл урьчилан засварласан Job объектыг формын конструкторт илгээх аргуудын аль нэгээр хэрэгжүүлэх боломжтой.
executeNew()
методыг өөрчилж, type
баганын дефаолт утгыг full-time
болгоё:
// apps/frontend/modules/job/actions/actions.class.php public function executeNew(sfWebRequest $request) { $job = new JobeetJob(); $job->setType('full-time'); $this->form = new JobeetJobForm($job); }
Форм холбогдсон үед түүний дефаолт утга нь хэрэглэгчийн оруулсан утгаар солигддог. Энэхүү өгөгдөл нь алдаа гарсан нөхцөлд формыг дахин бөглөхөд хэрэглэгдэнэ.
Job формыг токеноор хамгаалах
Ингээд л бүх зүйл сайхан ажиллана. Одоо хэрэглэгч ажлын байранд өөрийн токен (өвөрмөц тэмдэглэгээ)-ийг оруулна. Гэхдээ бид хэрэглэгчийн оруулах токен цорын ганц байж чадах эсэхэд эргэлзэж байгаа учраас түүнийг ажлын байрыг анх оруулахдаа автоматаар үүсгэх нь зохимжтой.
JobeetJob
класс дахь save()
методыг баяжуулж, ажлын байрыг хадгалахын өмнө токенийг үүсгэдэг болгоё:
// lib/model/doctrine/JobeetJob.class.php public function save(Doctrine_Connection $conn = null) { // ... if (!$this->getToken()) { $this->setToken(sha1($this->getEmail().rand(11111, 99999))); } return parent::save($conn); }
Одоо та формоос токений талбарыг хасч болно:
// lib/form/doctrine/JobeetJobForm.class.php class JobeetJobForm extends BaseJobeetJobForm { public function configure() { unset( $this['created_at'], $this['updated_at'], $this['expires_at'], $this['is_activated'], $this['token'] ); // ... } // ... }
Магадгүй та 2 дахь өдрийн хичээлээс ажлын байрны мэдээллийг хэрэглэгч зөвхөн түүний токенийг мэдэж буй тохиолдолд засварлах боломжтой гэсэн байсныг санаж байгаа биз. Гэтэл одоо бол түүний URL-ийг таахад л засварлах боломжтой. Яагаад гэвэл засварлах URL нь job/ID/edit
гэсэн хэлбэртэй, ингэхдээ ID
нь ажлын байрны мэдээллийн анхдагч түлхүүр.
sfDoctrineRouteCollection
route нь дефаолтаараа анхдагч түлхүүр бүхий URL-ийг үүсгэдэг ч түүнийг бид column
хэмжигдэхүүнд дурын цор ганц (unique) талбарыг зааж өгөх замаар өөрчилж болно.
# apps/frontend/config/~routing|Routing~.yml job: class: sfDoctrineRouteCollection options: { model: JobeetJob, column: token } requirements: { token: \w+ }
Symfony-д цор ганц түлхүүрийг \d+
гэж томъёолдог байтал token
параметрт үүнийг \w+
гэсэн байгааг анзаарна уу.
Одоо
ажлын байрны job_show_user
-ээс бусад бүх route токентой болсон. Жишээлбэл, ажлын байрны мэдээлэл засварлах route нь дараах загварт тохирно:
http://www.jobeet.com.localhost/job/TOKEN/edit
Харин одоо бидэнд showSuccess
темплэйт дахь “Edit” линкийг өөрчлөх шаардлагатай:
<!-- apps/frontend/modules/job/templates/showSuccess.php --> <a href="<?php echo url_for('job_edit', $job) ?>">Edit</a>
Урьдчилан харах хуудас
Урьдчилан харах хуудас – энэ бол ажлын байрны мэдээллийг дэлгэц дээр харуулах хуудас юм. Хэрэв хэрэглэгч зөв токен оруулсан бол тэр нь route-ийн тусламжтайгаар URL-д бичигдэнэ.
Токен бүхий URL байгаа нөхцөлд бид дээд хэсэгт нь админ-баарыг нэмж өгнө. showSuccess
темплэйтийн эхэн хэсэгт админ-баарын кодыг нэмж, доод хэсэгт нь байгаа edit
линкийг устгая:
<!-- apps/frontend/modules/job/templates/showSuccess.php --> <?php if ($sf_request->getParameter('token') == $job->getToken()): ?> <?php include_partial('job/admin', array('job' => $job)) ?> <?php endif ?>
Дараа нь _admin
partial-ийг үүсгэе:
<!-- apps/frontend/modules/job/templates/_admin.php --> <div id="job_actions"> <h3>Admin</h3> <ul> <?php if (!$job->getIsActivated()): ?> <li><?php echo link_to('Edit', 'job_edit', $job) ?></li> <li><?php echo link_to('Publish', 'job_edit', $job) ?></li> <?php endif ?> <li><?php echo link_to('Delete', 'job_delete', $job, array('method' => 'delete', 'confirm' => 'Are you sure?')) ?></li> <?php if ($job->getIsActivated()): ?> <li<?php $job->expiresSoon() and print '' ?>> <?php if ($job->isExpired()): ?> Expired <?php else: ?> Expires in <strong><?php echo $job->getDaysBeforeExpires() ?></strong> days <?php endif ?> <?php if ($job->expiresSoon()): ?> - <a href="">Extend</a> for another <?php echo sfConfig::get('app_active_days') ?> days <?php endif ?> </li> <?php else: ?> <li> [Bookmark this <?php echo link_to('URL', 'job_show', $job, true) ?> to manage this job in the future.] </li> <?php endif ?> </ul> </div>
Нэлээд их код бичигдсэн ч дийлэнх нь энгийн, ойлгомжтой байгаа биз.
Темплэйтийг уншихад илүү хялбар болгох үүднээс бид JobeetJob
классд шорткат методуудын холбоосыг (bunch of shortcut methods) нэмж орууллаа.
// lib/model/doctrine/JobeetJob.class.php public function getTypeName() { $types = Doctrine_Core::getTable('JobeetJob')->getTypes(); return $this->getType() ? $types[$this->getType()] : ''; } public function isExpired() { return $this->getDaysBeforeExpires() < 0; } public function expiresSoon() { return $this->getDaysBeforeExpires() < 5; } public function getDaysBeforeExpires() { return ceil(($this->getDateTimeObject('expires_at')->format('U') - time()) / 86400); }
Админ-баар нь ажлын байрны статусаас хамаарч харгалзах өөр өөр үйлдлийг харуулдаг.
Дараагийн бүлэгт та “activated” баарыг харах болно.
Ажлын байрыг идэвхжүүлэх ба нийтлэх
Өмнөх бүлэгт бид Publish линкийг үүсгэсэн. Энэ линк нь publish
үйлдлийг шинээр дуудах ёстой. Үүнд зориулж шинэ route үүсгэхийн оронд бид одоо байгаа job
route-дээ нэмэлт тохиргоо хийе:
# apps/frontend/config/routing.yml job: class: sfDoctrineRouteCollection options: model: JobeetJob column: token object_actions: { publish: put } requirements: token: \w+
object_actions
нь тухайн объектийн нэмэлт үйлдлүүдэд зориулсан массив юм. Одоо бид “Publish” линкийг өөрчилж болно:
<!-- apps/frontend/modules/job/templates/_admin.php --> <li> <?php echo link_to('Publish', 'job_publish', $job, array('method' => 'put')) ?> </li>
Сүүлийн алхам нь publish
үйлдлийг үүсгэх:
// apps/frontend/modules/job/actions/actions.class.php public function executePublish(sfWebRequest $request) { $request->checkCSRFProtection(); $job = $this->getRoute()->getObject(); $job->publish(); $this->getUser()->setFlash('notice', sprintf('Your job is now online for %s days.', sfConfig::get('app_active_days'))); $this->redirect('job_show_user', $job); }
Анхааралтай уншигч “Publish” линк нь HTTP-н put методоор илгээгдэж байгааг анзаарах боломжтой. Put методыг дууриах (симуляци)-ын тулд линк нь товчлуур дарагдмагц автоматаар форм болон хөрвөдөг.
Бидэнд CSRF хамгаалалт идэвхжсэн байгаа тул link_to()
хэлпер нь CSRF токенийг линкдээ оруулснаар request-ийн checkCSRFProtection()
метод нь тухайн өгөгдөл зөв эсэхийг шалгадаг.
executePublish()
метод нь publish()
гэсэн шинэ методыг ашигладаг ба үүнийг дараах байдлаар тодорхойлж болно:
// lib/model/doctrine/JobeetJob.class.php public function publish() { $this->setIsActivated(true); $this->save(); }
Одоо та браузер дээрээ шинээр ажлын байр нийтэлж туршиж болно.
Гэв ч бидэнд сайжруулах зүйл бас байна. Идэвхгүй болсон ажлын байрууд ямар ч нөхцөлд харагдах ёсгүй. Өөрөөр хэлбэл тэд Jobeet-ийн нүүр хуудсанд гарч ирэхгүй байхын зэрэгцээ холбогдох URL-ээр нээгдэхгүй байх ёстой. Бидэнд addActiveJobsQuery()
метод байгаа болохоор Doctrine_Query
-г зөвхөн идэвхтэй ажлын байруудыг харуулдаг байхаар болгож хязгаарлалт хийх боломжтой. Үүний тулд түүнд зөвхөн шинэ нөхцөл нэмэхэд л хангалттай:
// lib/model/doctrine/JobeetJobTable.class.php public function addActiveJobsQuery(Doctrine_Query $q = null) { // ... $q->andWhere($alias . '.is_activated = ?', 1); return $q; }
Ингээд л боллоо. Одоо энэ бүхнийг браузерт туршиж болно. Идэвхгүй болсон бүх ажлын байрууд нүүр хуудаснаас хасагдсан; тэр бүү хэл шууд хандах URL-ийг нь мэдэж байсан ч та тэдгээрийг харж чадахгүй. Зөвхөн та токенийг нь мэдэж байгаа нөхцөлд л тэдгээр мэдээлийг харах боломжтой бөгөөд энэ тохиолдолд ажлын байрны мэдээлэл нь админ-баартайгаар харагдана.
Энэ бол бид өнгөрсөн хугацааны туршид бий болгосон MVC pattern болон refactorization-ий олон давуу талуудын нэг. Шинэ нөхцөл нэмэхийн тулд ердөө ганц методод ганцхан өөрчлөлт хийх л шаардлагатай байлаа.
Бид getWithJobs()
методыг үүсгэхдээ addActiveJobsQuery()
методыг хэрэглэхээ мартсан. Үүнийгээ засварлаад шинэ нөхцөл нэмье:
class JobeetCategoryTable extends Doctrine_Table { public function getWithJobs() { // ... $q->andWhere('j.is_activated = ?', 1); return $q->execute(); }
Маргааш уулзацгаая
Өнөөдрийн хичээлд маш их шинэ мэдээлэл байлаа. Гэвч эдгээр нь Symfony-н формтой ажиллахад маш чухал ач холбогдолтой.
Та нарын зарим нь өнөөдөр бидний мартсан зүйлийг анзаарсан гэдгийг би мэдэж байна… Бид шинэ features-дээ ямар ч сорилт хийгээгүй. Апликейшн хөгжүүлэхэд хамгийн чухал зүйл нь сорилт бичих явдал учраас энэ бүхнийг бид маргааш эхний ээлжинд хийх болно.
« 9 дэх өдөр: Функциональ сорилт 11 дэх өдөр: Формын сорилт »
Татаж авах холбоос: http://hotfile.com/dl/81859491/92f75d1/PracticalsymfonyDay10.docx.html
Jobeet -ийг анхлан сурч байгаа хүмүүст орчуулан хүргэж байгаа нь тун сайшаалтай сайн ажил болжээ. Харин оруулга дээрээ зарим үг хэллэгийг анхаарвал зүгээр санагдана. Жишээ нь дефаолт утга гэдгийг анхны утга энэ тэр гэвэл илүү болох юм болуу гэж бодож байна. Амжилт хүсье.
Бүх үгийг монголчлох биш хамгийн гол нь уншиж байгаа хүнд ойлгомжтойгоор хүргэхийг л бодож байгаа. Дараа дараагийнхаа орчуулгад анхаарнаа.
Buh ugiig mongoloor orchuulj helj ugaasaa odoogoor bolohgyi gol ni utgachilj oruulah heregtei. ta nariin oruulga yag unendee bol mash modon oruulga bolson baina. yavaandaa turshlagajina gej naidaj bna.Orchuulsan humuus ni web programming symfony-oo sain medehgyi bol bas yavahgyi l dee. orchuulga ni
Ямартай ч саналаа бичсэнд баярлалаа. Мэдээж алдаа байлгүй яахав гэхдээ өөрт чинь тэгээд модон бишээр орчуулсан ямар нэгэн юм байгаамуу. Хэн болчоод юу заах гээд байнаа ?
Sain baina uu neg asuudal baina bi projectoo shared host deer tawihdaa web hawtsiig public_html dotor huulj tawiad ajillaj baigaan getel zurag upload hiisen chin sf_projects/minii_project hawtsand shineer web/uploads gej uuseed zurag orchood baihiin public_html dotorh uploads dotor zurag huulagdahgui baina ene asuudliig shiidhed tuslaach humuusee
Thanks
web дотрохоо public_html дотор хийгээд бусдийг нь өөр хавтас үүсгэж хийгээд тэгээд application-нийхаа тохиргоог тэр хавтас руугаа зааж өгнө.
Бүүр болохгүй бол доорх линк-ээс хар.
http://trac.symfony-project.org/wiki/InstallingSymfonyOnSharedHostNoSsh
http://www.symfony-project.org/book/1_0/19-Mastering-Symfony-s-Configuration-Files
Шинээр job нэмэхэд зураг оруулахаар л удаад алга болчоод нэмэгдэхгүй юм. Зураг оруулаагүй бол зүгээр нэмэгдээд байх юм юунийх вэ хэлж өгч туслаач
Илгээгдэж байгаа файлаа POST хийгдэж байгаа дээр нь барьж аваад байгаа үгүйг нь шалга. Эсвэл PHP-ын анхдагч утга болох файлын хэмжээнээс нь том юмуу, уншигдаг хугацаа нь хэт бага байвал тэгээд юу ч гарахгүй цагаардаг санагдана. Файлынхаа maxsize-ыг нь Validator дээрээ мөн заагаад өгчиж болно бас.
За амжилт!
thx bolchloo