symfony-Г ПРАКТИКААР СУРАХ НЬ - tugeene.mn · symfony 1.4 рүү шилжүүлж...

193
SYMFONY-Г ПРАКТИКААР СУРАХ НЬ http://www.symfony-project.org/get/pdf/jobeet-1.4-doctrine-en.pdf -н 1-13-р өдрийн Монгол орчуулга PDF-р нэгтгэн хөрвүүлсэн: http://altan-ochir.wordpress.com/ Version 1.0 2011 он

Upload: nguyenkhanh

Post on 28-Sep-2018

376 views

Category:

Documents


4 download

TRANSCRIPT

SYMFONY-Г ПРАКТИКААР СУРАХ НЬ

http://www.symfony-project.org/get/pdf/jobeet-1.4-doctrine-en.pdf

-н 1-13-р өдрийн Монгол орчуулга

PDF-р нэгтгэн хөрвүүлсэн: http://altan-ochir.wordpress.com/

Version 1.0 2011 он

English source: http://www.symfony-project.org/get/pdf/jobeet-1.4-doctrine-en.pdf

Монгол хэлрүү орчуулсан: Г.Эрхэмбаяр, Ариунсүлд, Ш.Ганбат

http://program.dayar.mn/

http://erheme318.wordpress.com/

[email protected]

http://minii.delhii.net/

Орчуулагч Г.Эрхэмбаярын өмнөх үг

Өнөөдөр 2010 оны 1-р сарын 15-ны өдөр. Сайхан нар гийсэн өдөр байлаа.

Дараа дараагийн бичлэгүүдээрээ Practical Symfony номын 24 хичээлийн эхний хичэлийг орчуулан тавих болно. Энэхүү ном нь PHP Symfony Framework анхлан сурахад зориулагдсан өдөр бүрийн хичээлийг багтаасан.

Энэхүү номыг уншиж дуусгаснаар symfony Framework талаар суурь мэдлэгтэй болох бөгөөд цаашид хөгжихэд ихээхэн тустай болов уу,

Энэ хуудсанд орчуулгын талаар санал хүсэлтийг авна. Дашрамд хэлэхэд би мөн анхлан суралцагч ба энэхүү номыг уншиж дуусгасан болно. Орчуулах ажил маань миний сонирхлын дагуу хийгдэж байгаа ба ямар хурдтай хийгдэх нь би таашгүй ээ. Бусад хүмүүс ч бас энэхүү ажилд оролцоно гэдэгт найдаж байна.

Have fun!

Зохиогчийн тухай:

Фабейн Потенсейр (Fabien Potencier) 1994 онд чарахсан дуутай модем ашиглан интернеттэй холбогддог байсан тэр үед анх вэбийн талаар олж мэдсэн. Маш их хүсэл эрмэлзэлтэй хөгжүүлэгч байх үедээ тэрээр Перл (Perl) дээр вэб сайт хийж эхэлсэн. Харин PHP 5 гарснаас хойш тэрээр санаагаа эрс өөрчлөн PHP руу анхаарлаа хандуулсан бөгөөд өөрийн харилцагчидад зориулж компанийх нь хөгжих гол хөшүүрэг болсон PHP framework-ийг 2004 онд үүсгэн бий болгосон.Фабейн олон амжилттай компаниудад хөгжүүлэгч, менежер хийдэг ба 1998 онд вэб технологи ба интернет маркетингийн чиглэлээр мэргэжлийн үйлчилгээ, зөвлөгөө үзүүлдэг Синсио (Sensio) компанийг 1998 онд үүсгэн байгуулсан. Фабейн нь мөн хэд хэдэн Open -Source төслийн (project–ийн) санаачлагч, зохиолч, блогч, олон улсын зөвлөгөөний илтгэгч мөн түүнчлэн 2 гаймшигтай охины эцэг юм. Түүний вэб сайт: http://fabien.potencier.org/ Твиттер нь: http://www.twitter.com/fabpot Синсео Лаб-ийн тухай Синсео Лаб (Sensio Labs) бол Нээлттэй кодчиллын (Open-Souce) технологи ба интернет маркетинг дээр тулгуурласан үйлчилгээ, зөвлөгөө өгдөг компани юм. 1998 онд Фабиен Потенсейр (Fabien Potencier), Грегори Паскал (Gregory Pascal), Самуэл Потенсейр нарын санаачлагаар байгуулагдсан Сенсио компани нь 1990 оны сүүлээр хүчээ авсан интернетийн ертөнцөд бүрэн цогц вэб урлах үйл хэрэгт гол тоглогчийн байрлалд аваачигдсан. Синсео нь ихэнх тоглогчид бизнесийн салбарт мэргэжлийн төгс аргачлалыг нэвтрүүлэхэд project болгоныг дахин шинээр үүсгэх шаардлагатай хэмээн бодож байсан тэрхүү интернетийн уналтаас ялгаран гарч чадсан. Ихэнх Синсео-гийн хэрэглэгчид нь том хэмжээний корпораци-ууд байдаг ба тэднийг шинийг санаачлах, цаг хугацааг маркетинг руу чиглэсэн бага хэмжээний төслөөс дунд хэмжээний хүртэл өсөн хөгжихэд нь гол хүч нь болж өгсөн. Синсео Лаб нь х оорондоо холбогдосон уламжлалт ба дот-ком аль аль вэб application-г хөгжүүлдэг. Мөн цогц интернет application -ны аудит хийх, зөвлөгөө өгөх, сургалтын чиглэлээр интернет суурилагдсан үйлчилгээг үзүүлдэг. Синсео Лаб нь франц -д болон гадаадын бусад орнуудад төсөл хэрэгжүүлсэн туршлагатай компани юм. Харин гол зүйл нь бол Синсео Лаб нь symfony framework -ийг хөгжүүлдэг ба Open-Source project байхад нь ивээн тэтгэдэг. Энэ нь өөрөөр хэлбэл symfony нь том корпорацийн хэмжээний вэб application дээр ажилласан туршлаган дээр үндэслэгдэж хөгждөг гэсэн үг. Хөгжиж ирсэн 11 жилийн өмнөөс, Синсео нь үргэлж мэргэшсэн хүчирхэг стратеги барин хөгжин ирсэн. Нээлттэй кодчиллын (Open-Souce) технологи болон dynamic scripting хэлүүдийг голчилдог Синсео нь бүх LAMP platforms-г дэмжин ажилладаг. Синсео нь тэдгээрийг хэлүүдийг ашиглах framework-ийн маш сайн туршлагатай ба ихэвчлэн Django, Rails мөн мэдээж symfony дээр application хөгжүүлдэг. Синсео Лаб нь үргэлжид бизнесийн шинэ боломжууд дээр нээлттэй ажилладаг ба хэрэв таньд вэб application хөгжүүлэх, symfony сурах зэрэгт ямар нэгэн тусламж хэрэгтэй бол чөлөөтэй дараах хаягаар Фабейнтэй холбогдоно уу [email protected]. Синсео-ийн зөвлөхүүд, төслийн менежерүүд, вэб дизайнерүүд болон хөгжүүлэгчид таны төслийг А-аас нь Я хүртэл гардан ажиллах болно. Symfony-ийн ямарХувилбар нь?

Энэ ном нь symfony 1.3 болон symfony 1.4 дээр бичигдсэн. Нэг ном 2 өөр төрлийн програм хангамжийн хувилбарт зориулагдсан нь хэвийн зүйл биш. Энэ хэсэгт 2 хувилбарын ялгаа болон алийг нь та өөрийн төсөлдөө авч ашиглаглах нь дээр болохыг тайлбарлах болно. symfony 1.3 баsymfony 1.4 хоёр хувилбар бараг нэгэн цагт (2009 оны сүүлээр) гарсан. Үнэндээ хоёулаа ижилхэн онцлог давуу талуудтай хийгдсэн. Хоёр хувилбарын ялгаа нь зөвхөн хэрхэн өмнөх хувилбаруудаа дэмжиж ажилладаг гэдгээрээ л ялгаатай болно. Symfony 1.3 нь таны хуучин symfony-ийнхувилбар (1.0, 1.1, or 1.2) ашиглаж хийсэн, шинэчлэл хийгдэх шаардлагатай цогц хэмжээний төсөлдөө авч ашиглахад зориулагдан гарсан. Энэ нь өмнөх хувилбаруудтайгаа зохицох давхаргатай ба 1.3 хөгжих явцад аль хэдийн хэрэггүй болсон өмнөх хувилбарын онцлогуудыг өөртөө агуулдаг. Энэ нь юу гэсэн үг вэ гэвэл шинчлэл хийх нь хялбар, энгийн бас хамгаалалттай. Харин хэрэв та шинэ төсөл эхэлж байгаа бол symfony 1.4-ийг ашиглах хэрэгтэй. Энэ хувилбар нь symfony 1.3 –тай ижил онцлогуудтай боловч хэрэггүй болсон өмнөх хувилбарын онцлогууд болон тэдгээртэй зохицох давхрагууд нь устсан болно. Энэ хувилбар нь илүү цэвэр, мөн илүү хурдан юм. Өөр нэг том давуу тал нь бол symfony 1.4 нь илүү удаан хугацаанд дэмжигдэж, ашиглагдах юм. Урт хугацааны дэмжигдэх хувилбар нь үндсэн symfony багаар 3 жил дэмжигдэнэ (2012 оны 11 сар хүртэл). Мэдээж та өөрийн өмнөх байсан төслөө symfony 1.3 болгоод яваандаа аажим аажимаар кодоо шинэчлэх замаар хэрэггүй болсон өмнөх онцлогуудыг устгаж удаан дэмжигдэх symfony 1.4 рүү шилжүүлж болно. symfony 1.3 нь бүтэн жилийн хугацаанд дэмжигдэх тул (2010 оны 11-р сар хүртэл) таньдөмнөх төслөө шилжүүлэхэд хангалттай хугацаа байгаа. Энэ ном өмнөх хэрэггүй болсон онцлогуудыг тайлбарлахгүй боловч, бүх жишээнүүд 2 хувилбар дээр ижилхэн ажиллах болно.

Өдөр 1:Төслийн эхлэл Танилцуулга

Symfony framework нь 4 жил гаруй Нээлттэй Кодчлолын төсөл байгаа бөгөөд олон сайхан онцлог болон номнуудын (document) ачаар одоогоор хамгийн их тархацтай PHP Framework-уудын нэг болсон юм. Энэ ном нь алхам алхамаар тодорхойлолтоос нь хэрэгжүүлэлт хүртэл нь symfony framework –ийг ашиглан вэб орчны програмыг хэрхэн хийхийг тайлбарласан болно. Энэ нь symfony сурахыг хүсч буй эхлэн суралцагчдад зориулагдсан бөгөөд хэрхэн ажилладаг болон хамгийн сайн вэб хөгжүүлэхэд чиглэгдсэн дасгалуудаас тогтоно. Тухайн програм нь өөр нэг блог хөдөлгүүр(engine) байж болохоор загварчлагдсан. Гэвч бид хэрэглэгддэг төсөл дээр symfony-ийг ашигламаар байгаа. Гол зорилго нь symfony-г ашиглан бүрэн хэмжээний цогц програм хангамжийг багахан хэмжээний загвар болон зүтгэлээр хөгжүүлэн бий болгоход оршино. Өөр хийх зүйлүүд маш олон байгаа болохоор төслийнхөө агуулгыг дараа өдөр хүртэл нууц хэвээр үлдээе. Гэсэн ч, Үүнийгээ Jobeet гэж нэрлэцгээе. Энэ номны сэдэв бүр нэгээс хоёр цаг үргэлжлэх ба энэ нь эхлэлээс нь дуустлаа жинхэнэ вэб сайт кодчиллож сурах боломж завшаан болно. Өдөр бүр шинэ онцлогууд програмд нэмэгдэх ба бид symfony вэб хөгжилтөнд маш сайн дадлагжихаас гадна шинэ symfony функц-лалуудтай танилцах том давуу талуудыг энэ төслөөр олж авна.

Энэ Ном бол Өөр

Тэртээх PHP4 үеийн өдрийг санцгаая. Ah, la Belle Epoque2! (http://en.wikipedia.org/wiki/Belle_Époque) PHP бол вэбд зориулагдсан хамгийн сурахад хялбар анхны хэлнүүдийн нэг. Гэвч вэб технологи маш хурдацтай хувирч өөрчлөгдөж байгаа өнөө үед, вэб хөгжүүлэгчид хамгийн сүүлийн үеийн хамгийн сайн дадлага, технологоос хоцрохгүй байх хэрэгцээтэй болдог. Сурах хамгийн сайн арга нь мэдээж блог унших, дурайж сурах (tutorials) мөн ном. Бид PHP, Python, Java, Ruby эсвэл Ruby зориулагдсан маш их ном, сургалтууд байдагч зохиогчид зөвхөн л кодынхоо хэсэгхэнийг л жишээ болгон эхлүүлэн бичсэн байдаг.

Магадгүй та доорхи анхааруулгыг уншаар л байдаг байх. “Жинхэнэ программд баталжуулалт (validation) болон боломжит алдааг хяналтыг ( error handling) нэмэхээ мартаа. Эсвэл

Жишээн дээр хамгаалалт нь орхигдсон байгаа. Эсвэл

“Кодоо заавал тест хийж үзээрэй”. Юу? Эдгээр бол зүгээр л бизнес. Эдгээр орхигдсон зүйлс бол хамгийн чухал кодуудын нэг. Уншигчид юучгүй хоцроно гэсэн үг. Эдгээрийг авч хэлэлцэхгүйгээр жишээнүүд нь маш бага үр дүнтэй. Та тэдгээрийг ямар ч зүйлд ашиглаж чадахгүй. Энэ бол буруу! Яагаад? Учир нь хамгаалалт (security), баталгаажуулалт (validation), алдаа хяналт (error handling) мөн тест (цөөхөн хэдийг дурьдахад), эдгээр л кодыг зөв эсэхэд анхаарна. Харин энэ номонд та дээрх зүйлсүүдийг хэзээ ч олж харахгүй ба бид тестлэж, алдаагаа хянаж, кодоо баталгаажуулах ба програмаа хамгаалалттай хөгжүүлж байгаа гэдэгтээ илтгэлтэй байх болно. Энэ нь л яагаад symfony бол “кодууд” мөн хамгийн сайн дадлага, хэрхэн үйдвэрлэлд зориулсан цогц програмыг хөгжүүлэх талаарх юм. Symfony эдгээр зүйлүүдийг нуршихгүйгээр хялбараар кодчилоход бидэнд хэрэгтэй бүхий л багажаар хангадаг учираас бид эдгээрийг чамин аргаар хялбархнаар хийж чадна. Баталгаажуулалт, алдаа хяналт, хамгаалалт, тест нь symfony-н хамгийн анхны иргэд ба эдгээрийг тайлбарлахад тийм их цаг орохгүй. Энэ бол яагаад framework-ийг “бодит” төсөлд (“real life” project)-д ашиглах зөвхөн нэг л шалтгаана нь. Энэ номонд гарч буй бүх код бодит амьдралд ашиглаж болохоор код юм. Бид кодын зарим хэсгийг болон бүгдийг нь copy and paste хийхийг дэмжиж байна.

Өнөөдөрт Юу вэ?

Өнөөдөр бид PHP код бичихгүй. Хэдийгээр бид ямар ч код бичихгүйгээр шинээр төсөл эхлэхдээ symfony шиг framework ашиглах нь давуу ямар талтай болохыг суралцаж эхлэх болно. Энэ бүлгийн зорилго нь хөгжүүлэх орчинг суулган, вэб враузер дээр программыг ажиллуулж үзэх юм. Эдгээрт дараах зүйлүүд орно: symfony-ыг суулгах, програмыг(application)-г үүсгэх мөн вэб серверийн тохиргоог хийх. Энэ ном нь symfony framework-д чиглэгдсэн учираас, таныг PHP5 болон Объект хандалтад програмчлалын тодорхой хэмжээний мэдлэгтэй гэж үзэж байна.

Шаардлагууд (таны өмнө нь мэдсэн байх)

Symfony-г суулгахаас өмнө та өөрийн компьютерт шаардлагтай бүхий л зүйл суусан болон тохиргоо зөв хийгдсэн эсэхийг шалгаж үзэх хэрэгтэй. Энэ бүлгийг та үнэнчээр цаг зарцуулж, шаардлагатай тохиргоог хийж, шалгах алхамуудыг шат дараалан дагавал та цаашид гарч болох бас нэг өдрийг хэмнэж байгаа гэж үзэж болно.

Гуравдагч хэсэгт програм хангамж (Third-Party Software)

Юуны түрүүнд та таны ажиллах орчин вэб хөгжүүлэхэд нийцэх эсэхийг шалгаж үзэх хэрэгтэй. Хамгийн багадаа таньд вэб сервер( тухайлбал Apache), мэдээллийн хөдөлгүүр (MySQL, PostgreSQL, SQLite, ямар нэгэн PDO/ http://www.php.net/PDO / тохирох мэдээллийн хөдөлгүүр) мөн PHP 5.2.4 –өөс дээшхи хувилбар байх шаардлагатай.

Command Line Interface

Symfony framework нь танд маш их ажлыг автоматаар хийж өгөх command line хэрэгсэлтэй хамт зохиогдсон (багцлагдсан). Хэрэв та Unix төрлийн OS хэрэглэгч бол, та ямар ч асуудалгүй байх болно. Харин хэрэв та Windows систем ашигладаг бол, мөн адил асуудалгүй боловч cmd prompt дээр яламгүй хэдэн мөр бичих шаардлагатай. “Unix shell” коммандууд Windows орчинд ажиллаж боломжтой байдаг. Хэрэв та tar, gzip болон grep хэрэгслүүдийг Windows дээр ашигламаар байвал та Cygwin (http://cygwin.com/) –ийг суулгах боломжтой. Өөр мөн Microsoft-ийн Unix-д зоруиулсан Windows Services-ийг оролдоод үзэх боломжтой.

PHP тохиргоо

PHP тохиргоо нь OS бүрд нэгээс нөгөөд өөр өөр байдаг учираас та symfony-ийг хамгийн багадаа байж болох тохиргоо хийгдсэн эсэхийг шалгаж үзэх хэрэгтэй.

Эхлээд, та phpinfo() юмуу php –v коммандаар хамгийн багадаа PHP 5.2.4 хувилбар суугдсан эсэхийг шалгах хэрэгтэй. Вэб-д болон коммандад хоёр өөр PHP хувилбар суулгасан эсэхээ нягтлаарай. Дараах линк-ээр symfony-ийн тохиргооны скриптийг татаж аваарай. http://sf-to.org/1.4/check.php

Скриптээ вэбийн root хэсгийн аль нэгэн хэсэгт хадгал. Дараах командаар скриптийг ажиллуулна. $ php check_configuration.php

Хэрэв тань ямар нэгэн асуудал гарвал коммандаар гарах хариу нь хэрхэн, яаж засах талаарх зөвлөгөөг өгнө. Та мөн скриптийг Враузераас шалгаж засах боломжтой. Энэ нь php.ini файл нь дээрх 2 орчинд өөр өөр ялгаатай тохиргоотой байж болдог учираас юм. “Шалгасныхаа дараа файлыг устгахаа бүү мартаарай”

Symfony –г суулгах

Төслийн (project) директорыг үүсгэх

Symfony-ийг суулгахаасаа өмнө та Jobeet-тэй холбоотой бүх файлаа хостлох(host) директорыг үүсгэх шаардлагатай.

$ mkdir -p /home/sfprojects/jobeet $ cd /home/sfprojects/jobeet

Windows-д: c:\> mkdir c:\development\sfprojects\jobeet

c:\> cd c:\development\sfprojects\jobeet “Windows-ийн хэрэглэгчиддээ зөвлөж хэлэхэд шинэ төслөө (project) суулгаж, ажиллуулахдаа ямар нэгэн сул мөр агуулаагүй директор замыг сонгох хэрэгтэй. Documents and Settings болон My Documents –аас зайлсхийх хэрэгтэй.” “Хэрэв та вэб root-д symfony-ийнхоо төслийн директорийг үүсгэвэл ямар нэгэн тохиргоо хийх хэрэггүй болно. Мэдээж, production орчинд зориулж та тохиргоогоо вэб тохиргоо хэсэгт тайлбарласанчлан тохиргоог хийхийг таньд зөвлөж байна.”

Symfony –ийн хувилбараа сонгох

Одоо та symfony-оо суулгах хэрэгтэй. Symfony Framework хэд хэдэн хэсэг хувилбартай учираас та symfony-ын вэб хуудасны installation (http://www.symfony-project.org/installation) хуудаснаас өөрийн хүсч буй хувилбараа сонгож суулгах боломжтой. Энэ ном нь таныг symfony 1.3 эсвэл symfony 1.4 хувилбарыг суулгахыг хүсэж байгаа гэж ойлгож байгаа.

Symfony-г суулгах байрлалыг сонгох

Та symfony-г өөрийн машиндаа глобал-аар эсвэл аль нь төсөл (project)-доо хавсаргаж суулгаж болно. Бусад төслүүдээсээ тусдаа биеэ даасан байдлаар үүсгэхийг таньд зөвлөмөөр байна. Мөн таны өмнө нь үүсгэсэн төслийн symfony-ийн хувилбарыг шинэчлэл хийгдэх үед ямар нэгэн байдлаар устгахгүй болохыг хэлмээр байна. Энэ нь юу гэсэн үг вэ гэвэл та шинэчлэл хийх хүртлээ 2 өөр төрлийн symfony-ийн хувилбарыг ашиглах боломжтой юм. Хамгийн сайн дадал нь ихэнх хүмүүс symfony framework—ийнхоо файлыг lib/vendor директори-д хадгалдаг. Тиймээс энэ директороо үүсгэе: $ mkdir -p lib/vendor

Symfony-г суулгах

Архивнаас суулгах

Хамгийн хялбар symfony-ыг суулгах арга нь тө өөрийн сонгосон хувилбарын архивласан файлыг вэб сайтаас татаж авч суулгах. Өөрийн сонгосон хувилбар тухайлбал symfony 1.4-ийн суулгах хуудас рүү ор. “Source Download” хэсгийн доороос та .tgz болон .zip архивуудыг олно. Архивласан файлаа татаж аваад сүүлийн үүсгэсэн lib/vendor директори дотроо задлаад нэрийг symfony болгон өөрчил.

$ cd lib/vendor $ tar zxpf symfony-1.4.0.tgz

$ mv symfony-1.4.0 symfony $ rm symfony-1.4.0.tgz

Windows zip файлаа задлаад нэрийг нь symfony болгон өөрчилсний дараа директори нь доорхтой ижилхэн болно. c:\dev\sfprojects\jobeet\lib\vendor\symfony.

Дэд хувилбараас нь суулгах (recommended)

Хэрэв та дэд хувилбар ашигладаг бол svn:externals шинж чанарыг ашиглаж symfony-ийг lib/vendor/ директорид суулгах нь илүү дээр. $ svn pe svn:externals lib/vendor/ Энэ бүлгийн эцэст өөрийн төслөө Дэд хувилбартаа (Subversion) хэрхэн импорт хийхийг тайлбарласан байгаа. Хэрэв бүх зүйл сайхан болж байвал, энэ комманд нэмэлт Subversion source-ын тохиргоо хийх боломжийг өгч таны дуртай эдиторт ажиллана. Харин Windows-д та TortoiseSVN (http://tortoisesvn.net/)- г ашиглан console хэрэглэх шаардлагагүйгээр бүгдийг хийх боломжтой.

Суулгасанаа баталгаажуулах

Одоо symfony суучихсан учираас, symfony –ын коммандын хэрэгслийг ашиглан бүгд ажиллаж байгаа эсэхийг ямар хувилбар суусан байгааг шалгая.

$ cd ../.. $ php lib/vendor/symfony/data/bin/symfony –V

Windows-д: c:\> cd ..\..

c:\> php lib\vendor\symfony\data\bin\symfony –V

Энэ коммандийн хэрэгсэл танд юу хийж өгч чадах талаар та илүү мэдмээр байвал symfony гэж бичээд боломжит options болон task-уудыг харж болно.

$ php lib/vendor/symfony/data/bin/symfony Windows-д:

c:\> php lib\vendor\symfony\data\bin\symfony

Symfony –ын коммандын хэрэгсэл (command line) нь хөгжүүлэгч нарын хамгийн сайн найз бөгөөд өдөр бүрийн гүйцэтгэх ажлыг тань хялбарчилах cache цэвэрлэх, код боловсруулах зэрэг маш олон хэрэгслүүдийг гүйцэтгэдэг.

Project Setup

Symfony-д ижилхэн өгөгдлийн model-уудад дамжуулагдаар дамжигддаг application-уудыг project болгож груплдэг. Ихэнх төслүүддээ та 2 өөр төрлийн frontend ба

backend гэх application-уудтай байна:

Project үүсгэх

sfprojects/jobeet – хаягнаас symfony-ын generate: project task-ийг ажиллуулж symfony-ийн project-ийг үүсгэе. $ php lib/vendor/symfony/data/bin/symfony generate:project jobeet

On Windows: c:\> php lib\vendor\symfony\data\bin\symfony generate:project jobeet

generate: project task нь symfony project-д шаардлагатай бүхий л default хавтасний бүтцийг үүсгэдэг.

Directory Description apps/ Бүх төслийн тань application-ууд байрлана.

cache/ framework-оор cache-хийгдсэн файлууд config/ төслийн тохиргооны файлууд

lib/ Төслийн library-ууд болон классууд log/ framework—ийн log файлууд

plugins/ суусан plugin-ууд test/ unit болон functional тест файлууд

web/ Вэбийн root директори (доорхийг хар)

Яагаад symfony маш их хэмжээний файлуудыг үүсгэдэг вэ? Full-Stack фрамеворкийг ашиглах нэг давуу тал нь та өөрийн хөгжүүлэх явцаа стандартжуулах юм. Symfony-ийг default бүтцийг ачаар symfony-ийн мэдлэгтэй дурын хөгжүүлэгч өөрийн project-оо засвар хийж, тохируулах боломжтой. Минутын дотор тэр кодоо хувааж, алдаагаа засаж, шинэ боломжуудыг нэмж чаддаг. generate:project task мөн symfony-ийн shortcut-ийг root хавтаст үүсгэдэг бөгөөд task-ийг ажиллуулах явцад бичих шаардлагатай кодчлолыг багасгаж өгдөг. Одооноос эхлээд та symfony-ийг бүтэн замыг бичихгүйгээр shortcut хувилбарыг ашиглах боломжтой.

Application үүсгэх

Одоо generate:app task-ийг ажиллуулж frontend application-ийг үүсгэе! $ php symfony generate:app frontend

------------------------------------------------ -------------------------------------------------- -------------------

Symfony-ийн shortcut нь одоо ажиллах учираа, Unix-ийн хэрэглэгчид ‘php symfony’ гэсэн бичлэгүүдээ ‘./symfony’ болгон засах боломжтой. Windows-д та symfony.bat файлыг өөрийн төслийн директори-д хуулаад ‘php symfony’-ийн оронд дан symfony –г ашиглаж болно. c:\> copy lib\vendor\symfony\data\bin\symfony.bat . ------------------------------------------------ -------------------------------------------------- --------

Application-ны нэр нь аргументаар өгөгдсөнөөр, generate:app task application-нд шаардлагатй default хавтасын бүтцийг apps/frontend директори-д үүсгэдэг.

Directory Description config/ Application-ны тохиргооны файлууд

lib/ Application-ны library болон классууд modules/ application-ны код (MVC)

templates/ глобал темплате файлууд

Хамгаалалт

Ерөнхийдөө generate:app task нь вэб-ын орчинд хамгийн их тархсан 2 төрлийн аюулаас хамгаалагдсан байдаг. Тиймээ, symfony нь бидний өмнөөс автоматаар хамгаалалтыг авдаг. XSS дайралтаас хамгаалж гаралтын хамгаалалт(output escaping) идэвхждэг, CSRF дайралтаас хамгаалж random хамгаалалт хийгддэг. Мэдээж, та дараах сонголтуудын ачаар өөрөө тохируулах боломжтой. • --escaping-strategy: Идэвхжүүлэх эсвэл унтраах output escaping • --csrf-secret: Формын session-ийн токенийг идэвхжүүлэх

Хэрэв та XSS (http://en.wikipedia.org/wiki/Cross-site_scripting )болон CSRF (http://en.wikipedia.org/wiki/CSRF) талаар мэдлэггүй бол, эдгээрийн талаар судлаж, олж мэдэхэд цаг зарцуулаарай. Директори-ийн бүтцийн тохиргоо

Шинээр үүсгэсэн төсөлдөө хандахаасаа өмнө та вэб сервер тань хандахж өөрчлөх боломжтой байх cache болон log директоруудын тохиромжитой түвшиний зөвшөөрөл (permission)-г нь тавьж өгөх шаадлагатай. $ chmod 777 cache/ log/ ------------------------------------------------ -----------------------------------------

SCM хэрэглэгчдэд зориулсан зөвлөгөө

Symfony зөвхөн тухайн төслийн cache/ болон log/ 2 л директорид бичигддэг. Энэ 2ын контент нь таны SCM-с ignore хийгдсэн байх шаардлагатай (хэрэв та Subversion хэрэглэдэг бол тухайлбал svn:ignore гэж бичнэ).

Вэб серверийн тохиргоо: муу арга

Хэрэв та төслөө вэб root-ийнхээ аль нэг хэсэгт үүсгэсэн бол та аль хэдийн враузераараа хандах боломжтой. Мэдээж ингэсэн тохиолдолд ямар нэгэн тохиргоо байхгүй ба та config/database.yml файл руу браузераараа хандах боломжтой болох учираас хэр муу үр дагавар байгааг та ойлгох бизээ. Хэрэв хэрэглэгч таны вэб сайт symfony дээр хийгдсэнийг мэдвэл, тэр таны маш их чухал файлууд руу хандах боломжтой болно гэсэн үг. Хэзээ ч жинхэнэ сервер дээр ингэж суулгаж болохгүй. Та дараагийн хэсгийн уншиж хэрхэн вэб серверт тохируулж тохиргоог хийхийг сурна.

Вэб серверийн тохиргоо: Хамгаалалттай арга

Хамгийн сайн дадал бол зөвхөн вэб браузераар хандаж болох бүхий л файлуудаа жишээ нь: javascript, stylesheets болон зурагнуудаа вэб root директори-тоо байрлуулах арга юм. Defaul- аар нь танд л гэж зөвлөхөд symfony төслийнхөө web дэд директори дотроо хадгалаарай. Хэрэв та энэ директори руугаа орвол та вэб-ийн нэмэгдэл(css болон зурагнууд) болон 2 төрлийн нүүрний удирдлагын файлуудыг (front controller) харна. Front controller бол вэб директори дотор байрлах шаардлагатай зөвхөн php файл. Бусад бүх php файлууд враузераар хандах боломжгүйгээр нуугдсан байна. Энэ нь хамгаалалтын хувьд нилээд сайн болно.

Вэб серверийн тохиргоо:

Одоо Apache-ийн тохиргоог хаанаас ч хандах боломжтой болгох үүднээс өөрчлөе. httpd.conf тохиргооны файлыг нээгээд доорх тохиргоог хамгийн доор нь нэмнэ.

# Be sure to only have this line once in your configuration NameVirtualHost 127.0.0.1:8080

# This is the configuration for your project Listen 127.0.0.1:8080

DocumentRoot "/home/sfprojects/jobeet/web"

DirectoryIndex index.php

AllowOverride All Allow from All

Alias /sf /home/sfprojects/jobeet/lib/vendor/symfony/data/we b/sf

AllowOverride All

Allow from All

------------------------------------------------ ------------------

/sf alias, нь default symfony хуудас болон вэб засварын toolbar (Web Debug Toolbar)-ын зураг болон javascript-ийн файлуудтай холбогдох замыг заадаг. Windows-д Alias мөрийг дараах байдлаар өөрчилөх шаардлагатай. Alias /sf "c:\dev\sfprojects\jobeet\lib\vendor\symfony\ data\web\sf"

/home/sfprojects/jobeet/web гэсэн мөр нь мөн дараах байдлаар өөрчлөгдөнө. c:\dev\sfprojects\jobeet\web

энэ тохиргоо нь Apache listen-ийг таны компютерт порт 8080 болгож, вэб сайт нь дараах URL-аар холбогдоно. http://localhost:8080/ Та 8080 гэснийг дурын дугаараар сольж болох ба админы зөвшөөрөл шаардагддаггүй 1024-өөс дээш тоо байж болно.

Dedicated Домайн нэрийн тохиргоо

Хэрэв та компьютертээ админ эрхээр хандаж байгаа бол шинэ төсөл үүсгэх болгондоо шинээр порт нэмсэний оронд виртаул хост үүсгэсэн нь илүү дээр юм. Порт сонгож, Listen-ийн мөр нэмэхийн оронд та домайн нэрээ сонгон (тухайлбал ардаа .localhost гэж залгасан жихэнэ домайн нэр), ServerName мөрийг нэмэх нь дээр.

# энэ бол таны төслийн тохиргоо

ServerName www.jobeet.com.localhost

www.jobeet.com.localhost гэж Apache-д ашиглагдах домайн нэр local-р зарлагдах хэрэгтэй. Хэрэв та Linux дээр ажилладаг бол, /etc/hosts –д байрлана. Хэрэв та Windows XP дээр ажилладаг бол, энэ файл C:\WINDOWS\system32\drivers\etc\ гэсэн директорид байрлана. Дараах мөрийг нэмнэ үү

127.0.0.1 www.jobeet.com.localhost

Шинэ тохиргоог шалгах

Apache –аа restart хийж, браузераар шинэ файлдаа өмнө нь хийсэн Apache-ийн тохиргооноосоо хамаарч http://localhost:8080/index.php/,Эсвэл http://www.jobeet.com.localhost/index.php/ гэсэн хаягаар хандаж шалгана уу.

------------------------------

Хэрэв та Apache-ийн mod_rewrite модуль суулгасан бол та index.php –ийг URL-ийн хэсгээс устгаж болно. web/.httaccess файлын ачаар ингэх боломжтой байдаг. Та мөн хөгжүүлэх орчинг мөн хандаж харах боломжтой(дараагийн хэсэгт хөгжүүлэх орчингийн талаар илүү үзнэ) ба дараах URL-ийг бичнэ үү. http://www.jobeet.com.localhost/frontend_dev.php / Таны хийсэн sf/alias тохиргоо зөв бол жижиг icon-ыг агуулсан вэб тохиргооны toolbar баруун дээд буланд харагдана.

Хэрэв та windows орчны IIS сервер дээр ажилладаг бол setup нь арай өөр ба холбогдох жишээнээс тохиргоог олох боломжтой.

Орчин (Environment)

Хэрэв та web/ директори- руу орж үзсэн бол та index.php болон frontend_dev.php гэсэн 2 ширхэг php файл байгааг харсан байх. Эдгээр файлуудыг front controllers гэж нэрлэдэг бөгөөд бүх application руу хандсан хүсэлтүүд тэдгээрээр дамжиж явагддаг. Гэвч яагаад бид заавал 2 front controller-уудтай байх хэрэгтэй гэж?

Хоёулаа ижилхэн application-ыг зааж байгаа боловч өөр өөр орчинд зориулагдсан. Хэрэв та шууд серверын орчинг вэб хөгжүүлэгч л биш л бол танд хэд хэдэн орчинд ажиллах шаардлагатай байдаг. • The development environment: Энэ орчин нь вэб хөгжүүлэгч нарт зориулагдсан бөгөөд тест хийх, алдаа (bugs)-ын мэдээлэл зэрэг давуу талуудтай. • The test environment: Энэ орчинг нь автоматаар application-г тест хийхэд

зориулагдсан. • The staging environment: Энэ орчин нь хэрэглэгч application-г шалгахад зориулагдсан. • The production environment: Энэ орчин нь эцсийн хэрэглэгчидэд зориулагдсан. Юу нь орчинг онцгой, цорын ганц болгодог вэ? Тухайлбал хөгжүүлэлтийн орчин (development environment) нь, application-нь алдааг хялбар засахын тулд хүсэлтүүдийн нарийн мэдээлийг лог хийх шаардлагатай, харин өөрчлөлт орсон кодууд зөв ажиллаж байгааг хянахын тулд cache систем идэвхгүй байх шаардлагатай. Тиймээс хөгжүүлэлтийн орчин нь хөгжүүлэгчид зориулж хийгдсэн байх ёстой. Хамгийн сайхан жишээ бол exception гарч ирэх үе юм. Хөгжүүлэгчид алдааг маш хурдан олоход тусалж, symfony браузер дээр сүүлийн хүсэлтүүдийг агуулсан бүх exception-г мэдээлэлтэй нь хамт харуулдаг.

Харин Production environment орчины үед cache –ын давхарга идэвхичцэн байх ёстой байдаг ба мэдээж application бүх нарийн алдааны оронд ердийн алдааны мессежийг харуулдаг. Тиймээс production environment орчин нь ажиллагаа болон хэрэглэгчдэд зориулж сайжруулагддаг.

Хэрэв та front controller файлуудыг нээвэл, контентууд нь хөгжүүлэх үеийн (environment) тохиргооноос бусад нь ижилхэн байгааг олж харна.

// web/index.php require_once(dirname(__FILE__).'/../config/

ProjectConfiguration.class.php'); $configuration =

ProjectConfiguration::getApplicationConfiguration( 'frontend', 'prod', false);

sfContext::createInstance($configuration)->disp atch(); Вэб debug toolbar нь мөн орчны хэрэглээний бас нэгэн онцлог жишээ бөгөөд зөвхөн хөгжүүлэх үеийн орчингийн бүх хуудсанд харагдах бөгөөд таньд tab бүрд өөр өөр маш олон мэдээллийг агуулсан холболтыг харуулдаг. Тухайлбал тухайн үеийн application-ны тохиргоо, хүсэлтүүдийн log-ууд, өгөгдлийн баазад хийгдсэн SQL хүсэлтүүд, санах ойн мэдээлэл, хугацааны мэдээлэл зэрэг орно.

Subversion

Вэб application хөгжүүлэхдээ source version control-ыг ашиглах нь маш сайн дадлага байдаг. Source version control-ыг ашигласнаар бидэнд: • Итгэлтэйгээр ажиллах • өөрчлөлтөнд ямар нэгэн алдаа гарвал өмнөх хувилбараа сэргээх

• нэг төсөлд хэд хэдэн хүн ажиллаж болох • амжилттай хийгддсэн application-руугаа хандах зэрэг боломжуудыг олгодог. Энэ хэсэгт бид Subversion (http://subversion.tigris.org/)-г symfony-той цуг хэрхэн ашиглахыг тайлбарлана. Хэрэв та ямар нэгэн source control tool-ыг ашигладаг бол одоо тайлбарлах гэж байгаа зүйл таньд маш амархан санагдана. Бид таныг Subversion сервертэйгээ via HTTP холболтоор холбогдчихсон байгаа гэж үзлээ. ---------------------

Хэрэв та Subversion сервер байхгүй бол та Google Code (http://code.google.com/hosting/) –ын үнэгүй repository үүсгэж болно. Эсвэл google-д “free subversion repository” гэж бичээд хайхаар маш олон сонголтууд гарч ирнэ. Эхлээд repository сервер дээрээ Jobeet-доо зориулж repository үүсгэе

$ svnadmin create /path/to/jobeet/repository

Өөрийн комьютер дээрээ, үндсэн директорийн бүтцийг үүсгэ. $ svn mkdir -m "created default directory structure"

http://svn.example.com/jobeet/trunk http://svn.example.com/jobeet/tags

http://svn.example.com/jobeet/branches

хоосон trunk/ гэсэн директори байна уу эсэхийг шалга: $ cd /home/sfprojects/jobeet

$ svn co http://svn.example.com/jobeet/trunk/ . Тэгээд, repository-доо cache/ болон log/ -г хийхгүй учираас директоруудын

контентуудыг устга. $ rm -rf cache/* log/*

Одоо веб сервер тань cache болон logs директорууд дээр файл бичиж боломжтой болгох үүднээс тэдгээрийн permission-г нь тавьж өгнө.

$ chmod 777 cache/ log/ Одоо бүх файл болон директоруудаа импорт хий.

$ svn add *

Cache/ болон log/ директори-д ямар нэгэн өөрчлөлт хийхгүй учираас тэдгээрийг татгалзах лист-д оруулах хэрэгтэй.

$ svn propedit svn:ignore cache

SVN-д зориулсан анхны текст эдитор нь ажиллах шаардлагатай. Subversion нь энэ директори дотор бүх контентыг татгалзах ёстой. *

Хадгалаад, гарна. Ингээд дууслаа.

log/ директори-д процессийг давтана. $ svn propedit svn:ignore log

Enter: дарна. *

Эцэст нь, repository өөрчлөлтүүддээ санамж хийж үлдээнэ. $ svn import -m "made the initial import" .

http://svn.example.com/jobeet/trunk

--------------

Windows-ийн хэрэглэгчид TortoiseSVN client(http://tortoisesvn.tigris.org/) - ыг ашиглан subversion repository-оо үүсгэх боломжтой.

Маргааш болтол баяртай.

Өнөөдөртөө ингээд боллоо. Бид symfony-ийн талаар ярьж эхлээгүй байгаа боловч, бид хөгжүүлэх орчингоо бэлдчихлээ, мөн вэб хөгжүүлэх хамгийн сайн дадалын талаар ярилцсан, кодоо бичээд мөн эхэлцэн. Маргааш бид application нь юу хийж чаддагыг харах бөгөөд Jobeet -г гүйцэтгэхэд шаардагдах шаардлагуудыг тодорхойлно.

2 дахь өдөр

28MAY

Project Бид хараахан нэг ч мөр PHP код бичээгүй байгаа боловч өчигдөр бид ажиллах орчноо суулгаж, хоосон project-оо үүсгэсэн ба зарим нэг сайн хамгааллалтыг мөн хийж өгсөн. Та хичээлийн дагуу хийж байгаа бол шинэ application-ны symfony хуудас гарч ирцэн, баяртайгаар дэлгэцээ харж байгаа байх.

Тиймээс илүү ихийг хүсэж байна уу. Та symfonyapplicationхөгжүүлэлтийн бүх нарийн ширийн зүйлүүдийг мэдийг хүсэж байгаа. Тэгвэл, Хамтдаа symfony хөжгүүлэлтийг нирвана руу хамтдаа аялацгаая. Өнөөдөрийн цагаар бид Jobeetproject-д шаардлагатай загварыг тодорхойлно. Project Pitch Өнөөдөр хүн болгон л хямралын талаар ярьж байна. Ажилгүйдэл улам л өсөж байна.

Symfony хөгжүүлэгчдэд энэ нээх хамаатай биш, тиймээс л яагаад та түрүүлж symfony-г сурах хэрэгтэй юм. Гэвч сайнsymfony хөгжүүлэгч олох нь бас яггүй хүнд байгаа. Та хаанаас symphony хөгжүүлэгч олох вэ? Хаана та symfony-ийнхаа чадвараа зарлах вэ? Танд сайн ажлын байрны самбар хэрэгтэй. Мангар-ийн гэж та хэлсэн үү? Дахиад бод. Танд төвлөрсөн ажлын зар, сайн хүмүүс эксперт олох мөн хялбар, хурдан, ажил олоход хөгжилтэй, танд санал болгочихмоор тийм газар зайлшгүй шаардлагатай болно. Хайсны хэрэггүй. Jobeet бол яг тэр юм. Jobeet бол Нээлттэй Кодын ажлын самбарын програм нэг л зүйл, маш сайн хийнэ. Хэрэглэхэд, өөрчлөхөд, өргөтгөхөд, хялбар мөн таны сайтанд хавсарагдна. Олон хэлний хэлнийг дэмждэг ба мэдээж хэрэглэгчийн туршлагыг нэмэгдүүлэхийн тулд хамгийн сүүлийн үеийн Web 2.0 технологийг ашигласан. Мөн feed болон API –ийг үүсгэнэ. Аль хэдийн байсиймүү? Та мэдээж интернетийг ашиглан Jobeet-той ижилхэн маш олон ажлын самбарыг олж болно. Харин Нээлттэй Кодын эхтэй, бидний энд санал болгож байгаа шиг маш өргөн онцлогуудтай-г олох гээд оролддоо. ——————————— Хэрэв та үнэхээр symfony-ийн ажил болон symfony хөгжүүлэгчийг хөслөх гэж байгаа бол та http://symfonians.net/вэбсайт руу орж болно. Project—ийн Хэрэглэгчийн Төрөл Код руугаа толгойгоороо шумбаж эхлэхийн өмнө project-оо багахан тодорхойлъё. Дараах хэсгүүд бол бид нарын эхнийproject-ын хувилбарт хэрэгжүүлэх онцлогууд юм. Jobeet вэбсайт дөрвөн төрлийн хэрэглэгчтэй байна. • admin: Вэб сайтын эзэмшигч, хамгийн өндөр эрх мэдэлтэй байна • user: Вэб сайтад зочилж ажил хайгч • poster: Вэб сайтад зочилж ажлын байр оруулагч • affiliate: Өөрийн сайтдаа дахин ажил хэвлэгч Project хоёр application-с бүрдэнэ. Хэрэглэгч вэбсайттай харилцах хэсэг frontend ( доор орших хүүрнэл F1-с F7), админы вэб сайтаа удирдах хэсэг backend (хүүрнэл B1 -с B3). Backendapplication бол хамгаалалттай ба нэвтрэх эрхээр дамжигдана. Story F1: Нүүр хуудснаасхэрэглэгч хамгийн сүүлийн хүчин төгөлдөр ажлуудыг харна. Хэрэглэгч Jobeet вэбсайт-д зочилсноор идэвхтэй ажлын байрны жагсаалтыг харна. Ажлууд нь категороор болон хэвлэгдсэн он сараар эрэмблэгдэнэ ( шинэ нь эхэнд). Ажил бүрд зөвхөн ажлын байрлал, албан тушаал, компани нь л харагдана. Категори жагсаалтын хувьд эхний 10 ажлыг харуулах ба бүх ажлыг харуулахад холбох линктэй байна (Story F2). Нүүр хуудсанаас хэрэглэгч ажлын жагсаалтыг сайжруулах (Story F3), эсвэл шинэ ажил оруулж (Story F5) болно.

Story F2: Хэрэглэгч өгөгдсөн категорит хамрагдах бүх ажлыг харах боломжтой Хэрэглэгч категорийн нэр дээр юмуу “more jobs” холбоос дээр дарангуут тухайн категорит хамрагдах бүх ажил он сараар нь шүүж харагдана. Жагсаалт нь нэг хуудсанд 20 ажлаар хуудаслагдана.

Story F3: Хэрэглэгч түлхүүр үгийн дагуу ажлын жагсаалтуудыг боловсруулан харах боломжтой. Хэрэглэгч зарим түлхүүр үг ашиглан хайлтаа өөртөө тохируулж боловсруулах бүрэн боломжтой. Түлхүүр үгүүд нь байрлал(location),албан тушаал (position), категори (category) болон компани талбараас олдох боломжтой үг байна. Story F4: Хэрэглэгч ажлын холбоос дээр дарж дэлгэрэнгүй мэдээллийг харах боломжтой Хэрэглэгч жагсаалтаас сонгон дэлгэрэнгүй мэдээллийг харах боломжтой. Story F5: Хэрэглэгч ажлын байр оруулах Хэрэглэгч ажлын байр оруулах боломжтой. Ажлын байрны мэдээлэл хэд хэдэн хэсэг мэдээллээс тогтоно. • Компани • Төрөл(Бүтэн цагийн, цагийн ажил, орон тооны бус)

• Лого (заавал биш) • URL (заавал биш) • Албан тушаал • Байршил • Категори (хэрэглэгч боломжит жагсаалтуудас сонгох боломжтой) • Ажлын тодорхойлолт (URL болон Эмайл хаяг автоматаар холбогдоно) • Хэрхэн хүсэлтээ илгээх (URL болон Эмайл хаяг автоматаар холбогдоно) • Олон нийт (ажил нь салбар сайтаас мөн оруулах боломжтой байна) • Имэйл(Ажил олгогчын Имэйл) Ажлын байр оруулахын тулд гишүүнээр элссэн байх шаардлагагүй. Үйл явц нь хоёрхон алхамаас тогтсон маш тодорхой байна. Нэгдүгээрт: хэрэглэгч ажлын байраа тодорхойлох бүхий л шаардлагатай мэдээлийг форм дээр бөглөх, тэгээд мэдээллийг шалган сүүлийн шатанд дахин нэг харна. Хэрэглэгч нэвтрэх эрхгүй байсан ч ажлын мэдээлэл нарийн URL-ий ачаар дахин өөрчлөлт хийх боломжтой (хэрэглэгч ажилаа үүсгэхэд олгогдох токен-оор хамгаалагдсан). Ажил тус бүр 30 өдрийн турш онлайн байна (энэ нь админаар тодрхойлогдоно - Story B2-г хар). Хэрэглэгч ажлын байраа дахин 30 хоногоор сунгаж болох боловч энэ нь зөвхөн хугацаа дуусахаас өмнөх 5 хоногийн дотор хийх боломжтой байна.

Story F6: Хэрэглэгч салбар гишүүнээр элсэх боломжтой Хэрэглэгч гишүүн болох болон, Jobeet API ашиглахын тулд хүсэлт илгээх хэрэгтэй болно. Хүсэлт илгээхийн тулд дараах мэдээллийг явуулах шаардлагатай. • Нэр • Имэйл • Вэбсайтны URL Салбар гишүүн (affliate) –ны эрх админаар идэвхжүүлэгдэнэ(Story B3). Идэвхижсэний дараа, гишүүн API-тай хэрэглэгдэх токеныг Имэйлээр хүлээн авна. Хүсэлт илгээхдээ гишүүн боломжтой категоруудын дэд хэсгээс ажлыг сонгон авах боломжтой. Story F7: Гишүүн сүүлийн идэвхтэй ажлуудын жагсаалтыг гаргаж авна

Гишүүн токеноороо API дуудаж хамгийн сүүлийн ажлын жагсаалтуудыг гаргаж авах боломжтой. Энэ жагсаалт нь XML, JSON эсвэл YAML форматаар гарах боломжтой байна. Жагсаалт нь ажилд боломжтой олон нийтийн мэдээллийг агуулсан байна. Гишүүн нь харах ажлын тоогоо хязгаарлах боломжтой ба мөн тодорхой нэг категорит зориулан хүсэлтээ боловсруулах боломжтой байна. Story B1: Админ нь вэбсайтаа тохируулна Админ нь вэб сайт дахь категоруудыг засварлах боломжтой. Story B2: Админ нь ажлуудыг зохицуулна Админ оруулсан ажлуудыг засварлах ба устгах боломжтой. Story B3: Админ гишүүдийг зохицуулна Админ гишүүн үүсгэж, засварлах боломжтой байна. Мөн гишүүнийг идэвхжүүлэх, идэвхгүй болгох эрхтэй. Админ шинэ гишүүнийг идэвхжүүлэхэд систем гишүүнд зориулж цорын ганц давтагдашгүй токеныг үүсгэнэ. Маргааш болтол баяртай Ямар ч вэб хөгжүүлэлтэнд эхний өдөр хэзээ ч кодчилол хийгдэхгүй. Шаардлагуудыг түрүүлж тодорхойлох шаардлагатай ба гараар дезайн боловсруулж ажилладаг. Өнөөдрийн хийсэн ажил бол энэ юм.

3 дахь өдөр

The Data Model Текст editor-оо нээгээд PHP код бичих гээд загнаад байгаа та нарыг өнөөдрийн хичээл зарим хөгжүүлэлтийг

хийлгэж өгсөнөөр та нарыг баярлуулах болно. Бид Jobeet-ийн data model (өгөгдлийн загвар) тодорхойлж, ORM

(Object Relation Mapping) ашиглаж өгөгдлийн баазтай холбогдон, application-ныхаа анхны модуль-ийг үүсгэх

болно. Харин symfony бидний өмнөөс маш ихийг хийж өгөх бөгөөд, бид хэт их PHP код бичихгүйгээр бүрэн

функлагдсан вэб модультай болох болно.

The Relational Model (Холбоотой загвар)

Өчигдөр бичсэн бидний хэрэглэгчийн загвар нь project-ийн гол объектыг тодорхойлно: ажилын байрууд,

гишүүд мөн ангилалууд. Дараах Entity Relationship Diagram-ыг тодорхойллоо.

Загвар дээр тодорхойлогдсон баганууд дээр нэмэж тайлбарлахад бид created_at гэсэн талбарыг зарим

хүснэгтэд нэмсэн. Symfony нь тэдгээр талбаруудыг ялгаж, танин, шинээр өгөгдөл үүсэх үед

системийн цагийг автоматаар олгодог. Энэ мөн updated_at талбарт мөн ижилхэн: Тэдгээрийн утгууд

нь, өгөгдөл шинэчлэгдэх үед системийн цагаар шинэчлэгддэг.

The Schema (Схем)

Ажлын байр, гишүүн, категорыг хадгалахад мэдээж бидэнд Relational өгөгдлийн бааз шаардлагатай.

Харин symfony бол Объект Хандалтад framework болохоор бид объектыг ашиглана. Жишээ нь:

өгөгдлийн баазаас өгөгдлүүдийг цуглуулахдаа SQL хүсэлт бичихийн оронд бид объектыг ашиглан

тухайн үйлдлийг гүйцэтгэх болно.

Relational(уялдаа, холбоотой) өгөгдлийн баазын мэдээлэл объект загвараар тодорхойлогдсон байх

ёстой. Энэ нь ORM хэрэгслээр хийгдэнэ. Азаар symfony тэдгээрийн 2 болох Propel болон Doctrine-той

хамт хийгдсэн.

ORM нь хүснэгтийн тодорхойлолт болон тэдгээрийн уялдаа холбоог харуулсан Class үүсгэхийн тулд

тэдгээрийг мэдэх шаардлагатай. Энэ тодорхойлох schema –г үүсгэх 2 байгаа. Өмнөх өгөгдлийн

базаасаа шинэчлэх, эсвэл гараар үүсгэх.

Өгөгдлийн бааз хараахан байхгүй, мөн Jobeet –ын өгөгдлийн баазыг үүсгэх шаардлагатай учираас,

config/doctrine/schema.yml гэсэн хоосон файлыг засварлаж schema файлыг гараар үүсгэе.

# config/doctrine/schema.yml

JobeetCategory:

actAs: { Timestampable: ~ }

columns:

name: { type: string(255), notnull: true, unique: true }

JobeetJob:

actAs: { Timestampable: ~ }

columns:

category_id: { type: integer, notnull: true }

type: { type: string(255) }

company: { type: string(255), notnull: true }

logo: { type: string(255) }

url: { type: string(255) }

position: { type: string(255), notnull: true }

location: { type: string(255), notnull: true }

description: { type: string(4000), notnull: true }

how_to_apply: { type: string(4000), notnull: true }

token: { type: string(255), notnull: true, unique: true }

is_public: { type: boolean, notnull: true, default: 1 }

is_activated: { type: boolean, notnull: true, default: 0 }

email: { type: string(255), notnull: true }

expires_at: { type: timestamp, notnull: true }

relations:

JobeetCategory: { onDelete: CASCADE, local: category_id, foreign: id,

foreignAlias: JobeetJobs }

JobeetAffiliate:

actAs: { Timestampable: ~ }

columns:

url: { type: string(255), notnull: true }

email: { type: string(255), notnull: true, unique: true }

token: { type: string(255), notnull: true }

is_active: { type: boolean, notnull: true, default: 0 }

relations:

JobeetCategories:

class: JobeetCategory

refClass: JobeetCategoryAffiliate

local: affiliate_id

foreign: category_id

foreignAlias: JobeetAffiliates

JobeetCategoryAffiliate:

columns:

category_id: { type: integer, primary: true }

affiliate_id: { type: integer, primary: true }

relations:

JobeetCategory: { onDelete: CASCADE, local: category_id, foreign: id }

JobeetAffiliate: { onDelete: CASCADE, local: affiliate_id, foreign: id

}

Хэрэв та бичигдсэн SQL хүсэлтээр хүснэгт үүсгэхээр шийдсэн бол doctrine:build -schema коммандаар

schema.yml тохиргооны файлыг ажиллуулан хүснэгтүүд үүсгэх боломжтой.

$ php symfony doctrine:build-schema

Дээрх команд таныг databases.yml дээр өгөгдлийн баазын т охиргоог шаардана. Дараах алхамаар бид

хэрхэн өгөгдлийн баазыг тохируулахыг харуулна. Хэрэв та дээрх командыг ажиллуулах гэж үзвэл

schema нь ямар өгөгдлийн баазтайг мэдэхгүй улмаас ажиллахгүй.

Schema бол YAML формат дээрх entity relationship diagram-ын шууд тусгал юм.

YAML Формат

Албан ёсны YAML(http://yaml.org/) форматын вэб сайтын дагуу бол YAML бол бүх програмын хэлэнд

зориулсан хүний хялбар өгөгдлийн бүтэцлэгдсэн стандарт.

Өөрөө хэлбэл, YAML бол өгөгдлийг тодорхойлоход энгийн хэл (strings, integers, dates,

arrays, and hashes).).

YAML-д бүтэц нь догол мөрөөр харагддаг, таслалаар тусгаарлагдаж дараалсан, түлхүүр үг/ утга нь цуг

хашилт дотор тусгаарлагдаж байрладаг. YAML нь мөн ижил төрлийн бүтцийг цөөхөн мөрөөр

тодорхойлж болох богино бичилттэй: массив нь [] –д , мөр нь {} дотор тодорхойлогдоно.

Хэрэв та YAML форматыг сайн мэдэхгүй бол, одоо symphony framework -той хамт сурч эхлэх болно.

Учир нь symphony өөрийн тохиргооны файлдаа YAML -ыг өргөнөөр хэрэглэдэг. YAML -ыг сурах нэг

сайн арга нь Компонентын сурах авлагаас нь унших юм (http://components.symfony-project.org/yaml/

documentation).

YAML форматыг засварлах явцад таны зайлшгүй мэдэх шаардлагатай нэг зү йл бол: догол мөр

хоорондын зай нь нэг, юмуу хоёр хоосон зайгаар хэмжигдэнэ, таб зай авалтаар биш.

schema.yml файл бүх хүснэгт, тэдгээрийн багануудын тодорхойлолтыг агуулсан байна. Багана бүр

дараах мэдээллээр тодорхойлогдоно.:

• type: Баганы төрөл (boolean, integer, float, decimal, string, array,

object, blob, clob, timestamp, time, date, enum, gzip)

• notnull: хэрэв багана нь заавал утгатай байх шаардлагатай бол утгыг true болго.

• unique: багананд цор ганц индех үүсгэхийг хүсвэл утгыг true болго.

OnDelete атрибут нь foreign key-ийн ON DELETE шинжийг тодорхойлно. Doctrine CASCADE, SET NULL,

болон RESTRICT мөн дэмждэг. Тухайлбал, хэрэв ажлын байрны мэдээлэл устгагдсан бол түүнтэй

хамааралтай jobeet_category_affiliate-ын утгууд мөн автоматаар устана.

Өгөгдлийн бааз

Symfony framework бүх PDO дэмждэг өгөгдлийн баазуудыг дэмждэг (MySQL, PostgreSQL, SQLite,Oracle,

MSSQL, …). PDO (http://www.php.net/PDO) бол PHP-тэй хамт байдаг өгөгдлийн баазын abstraction layer

(давхарга).

Энэ хичээлээр MySQL-ыг авч үзье.

$ mysqladmin -uroot -p create jobeet

Enter password: mYsEcret ## The password will echo as ********

Хэрэв та хүсвэл өөр өгөгдлийн бааз ашиглах бүрэн боломжтой. Бидний хэрэглэх ORM -д бичигдэх SQL

–ыг өөрийн болгож бичихэд тийм хэцүү биш байх болно.

Бид symfony –д Jobeet project-д энэ өгөгдлийн баазыг ашигла гэдгийг хэлж өгөх хэрэгтэй.

$ php symfony configure:database

“mysql:host=localhost;dbname=jobeet&rd quo; root mYsEcret

configure:database команд нь 3 аргумент авна. PDO DSN (http://www.php.net/manual/en/pdo.drivers.ph p) ,

хэрэглэгчийн нэр мөн өгөгдлийн баазтай холбогдох нууц үг. Хэрэв та хөгжүүлэх серверийн өгөгдлийн

баазтайгаа холбогдохдоо нууц үг шаардлагагүй бол 3 дахь аргументын хэсгийн бичихгүй байж болно.

configure:database команд нь өгөгдлийн баазын тохиргоо config/databases.yml тохиргооны файлд

хадгална. Командыг ажилуулахын оронд мөн гараар энэ файлыг засварлах боломжтой.

Баазын нууц үгийг коммандын хэрэгслэ эр бичих нь тохиромжтой боловч нууцлалгүй арга юм. Таны

орчинд хэн хандаж байгаагаас хамаараад, config/databases.yml файлыг засварлаж нууц үгээ

өөрчилсөн нь илүү дээр болов уу. Мэдээж, нууц үгээ сайн хадгал, тохиргооны файл-ын холбогдох

mode нь хориглосон (resricted) байх хэрэгтэй.

ORM

Өгөгдлийн баазыг тодорхойлох schema.yml файлын ачаар бид өгөгдлийн баазын хүснэгт үүсгэхэд

шаардлагатай байдаг SQL хүсэлтийг боловсруулах зарим Doctrine built -in (байгуулах) командыг

ашиглах боломжтой болдог.

SQL хүсэлт болосвруулахын (ажиллуулах) –ын тулд хамгийн түрүүнд schema файлаараа model -оо

үүсгэх ёстой.

$ php symfony doctrine:build –model

Одоо чиний model-ууд SQL хүсэлтийг оруулах болон боловсруулахад боломжтой боллоо.

$ php symfony doctrine:build –sql

doctrine:build –sql ком� �нд бидний өмнө тохиргоо хийсэн өгөгдлийн баазад зориулсан SQL

хүсэлтийг data/sql/ хав� �асд боловсруулдаг.

# snippet from data/sql/schema.sql

CREATE TABLE jobeet_category (id BIGINT AUTO_INCREMENT, name VARCHAR(255)

NOT NULL COMMENT ‘test’, created_at DATETIME, updated_at DATETIME, slug

VARCHAR(255), UNIQUE INDEX sluggable_idx (slug), PRIMARY KEY(id))

ENGINE = INNODB;

Өгөгдлийн бааздаа яг хүснэтүүд үүсгэхэд та doctrine:insert-sql командыг ажиллуулах шаардлагатай.

$ php symfony doctrine:insert-sql

Дээрх команд нь хүснэгтийг үүсгэхээс өмнө өмнөхийг нь устгах учираас таныг батлах үйлдлийг

хийхийг шаарддаг. Та мөн –no-confirmation гэсэн сонголтыг нэмж асуултыг өнгөрөөж болдог. Энэ мөн

та non-interactive (харилцаа, холбоогүй) batch-д командыг—ийг ажиллуулахад илүү хэрэглэгддэг.

$ php symfony doctrine:insert-sql –no-confirmation

Бусад командын хэрэглүүрийг бодоход symfony -ийн команд нь аргументууд болон сонголтууд авах

боломжтой байдаг. Команд (task) бүр тусламжийн мэдээллэлтэйгээр хийгд сэн ба help гэсэн командыг

ажиллуулсанаар дэлгэцэнд хэвлэгдэнэ.

$ php symfony help doctrine:insert-sql

Тусламжийн мэдээлэл нь бүх боломжит аргумент болон сонголтуудыг жагсаан харуулах ба тус бүрийн

анхны авч болох утгууд болон хэрэг болох хэд хэдэн жишээтэйгээр мэдээллийг харуулдаг.

ORM мөн хүснэгтийн бүтцийн зургийг объект болгосон PHP классуудыг мөн боловсруулдаг.

$ php symfony doctrine:build –model

doctrine:build –model команд өгөгдлийн баазтай холбогддог PHP файлуудыг lib/model/ хавтас дотор

үүсгэдэг.

Хавтас дотор орж үзвэл та Doctrine хүснэгт бүрт 3 -н классыг үүсгэснийг олж харах болно. Jobeet_job

хүснэгтийн хувьд:

• JobeetJob: Класын объект нь jobeet_job хүснэгтийн нэг баганы (record) –ыг илэрхийлнэ. Класс Default

(анхны) утгандаа хоосон байна.

• BaseJobeetJob: JobeetJob класс эх класс. doctrine:build –model, командыг ажиллуулах бүрд энэ класс

дахин тодорхойлогддог, тиймээс бүх өөрчлөлт, хувиргалтууд JobeetJob класс дээр хийгдэг ёстой

байдаг.

• JobeetJobTable: Класс нь ихэвчлэн JobeetJob-ийн объектуудын цуглуулга (collection)-г буцаадаг

функцуудыг (methods) тодорхойлдог. Анхны утгандаа класс хоосон байна.

Өгөгдлийн баганануудын утгууд нь model объектын зарим холбогч (get*() функцууд) ба утга олгогч

(set*() функцууд) –даар холбогдож ашиглагддаг.

$job = new JobeetJob();

$job->setPosition(‘Web developer’);

$job->save();

echo $job->getPosition();

$job->delete();

Та мөн объектуудыг хамтад нь холбох foreign key-уудыг мөн тодорхойлж өгч болно.

$category = new JobeetCategory();

$category->setName(‘Programming&rsq uo;);

$job = new JobeetJob();

$job->setCategory($category);

doctrine:build –all команд нь бидний энэ бүлэг (хэсэг) -ээр ажиллуулсан командууын хялбар хувилбар

бөгөөд нэмэлт хэдэн зүйлүүдтэй. Тиймээс энэ командыг ажиллуулан Jobeet model классын форм

болон баталгаажуулагчид (validators)-ыг боловсруулъя.

$ php symfony doctrine:build –all –no-confirmation

Энэ өдрийн төгсгөл та action –ын баталгаажуултыг харах ба форм-ын хэсэг нь илүү дэлгэрэнгүйгээр

10 дахь өдөрт тайлбарласан байгаа.

Анхны өгөгдөл

Өгөгдлийн бааздаа бид хүснэгтүүд үүсгэсэн байгаа боловч ямар ч өгөгдөлгүй оруулаагүй. Ямар ч вэб

програм (application) –д 3 төрлийн өгөгдөл байдаг.

• Анхны өгөгдөл: Анхны өгөгдөл нь application ажлахын тулд байх шаардлагатай байдаг. Жишээ нь:

Jobeet –д анхны хэдэн ангилалууд шаардлагатай. Хэрэв байхгүй бол, хэн ч ажлын байр оруулж

чадахгүй. Мөн бидэнд админы (backend) хэсэг рүү нэвтэрч орохын тулд админ хэрэглэгч мөн

шаардлагатай.

• Тестийн өгөгдөл: Тестийн өгөгдөл нь application-ыг тестэлж үзэхэд хэрэгтэй. Хөгжүүлэгчийн зүгээс та

хэрэгчийн тодорхойлох хэсэгт гарсанчлан Jobeet програм үнэн зөв ажиллаж байгаа эсэхийг шалгах

тест бичиж өгнө. Хамгийн сайн арга бол автомат тест бичих. Тиймээс тестээ шалгах бүрдээ таньд үнэн

зөв шалгахад шаардлагатай өгөгдлүүд орсон өгөгдлийн бааз байх шаардлагатай.

• Хэрэглэгчийн өгөгдөл: Хэрэглэгчийн өгөгдөл нь хэрэглэгчээс үүсдэг програмын жирийн

ажиллагаанд зоруулсан өгөгдөл.

Symfony өгөгдлийн баазад хүснэгт үүсгэх бүрд бүх өгөгдлүүд устдаг. Анхдагч өгөгдлүүдтэйгээр

өгөгдлийн бааз үүсгэхийн тулд бид PHP код бичиж өгөх эсвэл mysql програмаас зарим SQL хүсэлтийг

ажиллуулах боломжтой. Хийх зүйл нь илэрхий , symfony илүү боломжтой: data/fixtures/ хавтасд YAML

файл үүсгээд doctrine:data-load командаар өгөгдлийн бааз руу уншуулна.

Эхлээд, дараах fixture файлыг үүгэнэ.

# data/fixtures/categories.yml

JobeetCategory:

design:

name: Design

programming:

name: Programming

manager:

name: Manager

administrator:

name: Administrator

# data/fixtures/jobs.yml

JobeetJob:

job_sensio_labs:

JobeetCategory: programming

type: full-time

company: Sensio Labs

logo: sensio-labs.gif

url: http://www.sensiolabs.com/

position: Web Developer

location: Paris, France

description: |

You’ve already developed websites with symfony and you want to work

with Open-Source technologies. You have a minimum of 3 years

experience in web development with PHP or Java and you wish to

participate to development of Web 2.0 sites using the best

frameworks available.

how_to_apply: |

Send your resume to fabien.potencier [at] sensio.com

is_public: true

is_activated: true

token: job_sensio_labs

email: [email protected]

expires_at: ’2010-10-10′

job_extreme_sensio:

JobeetCategory: design

type: part-time

company: Extreme Sensio

logo: extreme-sensio.gif

url: http://www.extreme-sensio.com/

position: Web Designer

location: Paris, France

description: |

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do

eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut

enim ad minim veniam, quis nostrud exercitation ullamco laboris

nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor

in reprehenderit in.

Voluptate velit esse cillum dolore eu fugiat nulla pariatur.

Excepteur sint occaecat cupidatat non proident, sunt in culpa

qui officia deserunt mollit anim id est laborum.

how_to_apply: |

Send your resume to fabien.potencier [at] sensio.com

is_public: true

is_activated: true

token: job_extreme_sensio

email: [email protected]

expires_at: ’2010-10-10′

job fixture файл 2 зургийг агуулдаг. Энэ зургуудыг дараах линкүүдээс татаж аваад web/ uploads/jobs/

хавтас дотор хий.

(http://www.symfony-project.org/get/jobeet/s ensio-labs.gif,

http://www.symfony-project.org/get/jobeet/e xtreme-sensio.gif)

fixture файл нь YAML дээр бичигдсэн ба model-ын объектуудыг тодорхойлдог, цорын ганц нэртэйгээр

ордог (тухайлбал job_sensio_labs ,job_extreme_sensio гэсэн 2 ажлын байрыг тодорхойлсон.) Энэ нь

primary key-уудыг (ихэвчлэн auto-increment-ээр хангагдсан тодорхойлох боломжгүй) тодорхойлж

ашиглахгүйгээр холбоосд ашиглах боломжтой байдаг. Тухайлбал, job_sensio_labs гэсэн ажлын

байрын ангилал нь programming, Programming ангилал руу холбогдоно.

YAML файлд тэмдэгт нь мөр таслалт агуулсан бол (job fixture –ын description багана-д байгаатай

адилхан), (|) босоо зураасыг ашиглан тэмдэгтүүд нь хэд хэдэн мөр байгааг илэрхийлж өгч болно.

Fixture файл нэг эсвэл хэд хэдэн model-ийн объектыг багтааж болох боловч, Jobeet fixture-д зориулан

бид нэг файлыг нэг model-д зориулан бичихээр болсон.

Propel дээр аль файл эхэнд дуудагдаж ажиллахаас шалтгаалж fixture-ын нэрүүд нь өмнөө тоотой байх

шаардлагатай байдаг. Doctrine-д уншигдах бүх fixture -д тийм байх шаардлагагүй ба foreign key -үүдийг

тодорхойлсноор зөв байрлалаар хадгалагддаг.

Fixture файлд та бүх багануудыг тодорхойлж өгөх албагүй. Өгөөгүй бол, symfony автоматаар

өгөгдлийн баазын schema-д тодорхойлогдсончсон default утгыг оноодог. Symfony өгөгдлийг бааз руу

уншуулахдаа Doctrine-ыг ашиглавал бүх байгуулагч үйлдлүүд (автоматаар тохирдог created_at,

updated_at шиг) ба таны model класс-д өөрийн үүсгэж болох үйлдлүүд идэвхждэг.

Анхны өгөгдлийг бааз руу уншуулах нь маш амархан doctrine:data -load командыг ажиллуулахад л

болно.

$ php symfony doctrine:data-load

doctrine:build –all –and-load команд нь doctrine:build –all командын түүнийг дагах doctrine:data -load

командуудын хялбар хувилбар нь.

doctrine:build –all –and-load командыг ажиллуулж бүх зүйл schema -с боловсруулагдсан эсэхийг шалга.

Ингэхэд таньд form, filter, model –ууд үүсгэн баазыг устган дахин шинээр бүх хүснэгтийг үүсгэнэ.

$ php symfony doctrine:build –all –and-load

Browser- дээр харах

Бид маш их командын хэрэгслийг ашиглалаа, тийм ч сайхан санагдаагүй байх ялангуяа вэб project -д .

Бидэнд одоо өгөгдлийн баазтай Вэб хуудас үүсгэхэд шаардлагатай бүхий л бэлэн болсон.

За тэгвэл, ажлын байрны жагсаалтыг хэрхэн харуулах, хэрхэн засварлах, устгах зэргийг харцгаая.

Эхний өдөр заасанчлан symphony project бол application -уудаар үүсдэг. Application бүр цаашилж

модулиудад хуваагддаг. Модуль бол application (жишээлбэл API модуль)-ны онцлогыг төлөөлсөн

өөрөө агуулсан PHP кодууд, эсвэл хэрэглэгч model объект дээр хийгдэх боломж, ашиглалтууд (job

модуль жишээ нь).

Symfony өгөгдсөн model-оор автоматаар модуль үүсгэх өөрийн үндсэн онцлог хэрэгсэлтэй:

$ php symfony doctrine:generate-module –with-show

–non-verbose-templates frontend job JobeetJob

doctrine:generate-module JobeetJob model-д зориулсан frontend application- дотор job модулийг

үүсгэнэ. Ихэнх symphony-ын командын адилаар файлууд, болон хавтасууд apps/frontend/modules/job/

хавтас дотор үүснэ.

Хавтас Тайлбар

actions/ Модулийн action-гууд

templates/ Модулийн template-үүд

actions/actions.class.php файл job модулийн бүх боломжит action-г тодорхойлно.

Action Нэр Тайлбар

index Хүснэгтийн өгөгдлүүдийг харуулна

show Өгөгдсөн өгөгдлийн талбарууд болон утгуудыг харуулна

new Шинэ өгөгдөл үүсгэх Форм харуулна

create ШИнэ өгөгдөл үүсгэнэ

edit Өмнөх өгөгдлийн засварлах формыг харуулна

update хэрэглэгчийн илгээх утгуудаар өгөгдлийг шинэчлэнэ

delete хүснэгтээс өгөгдсөн өгөгдлийг устгана

Одоо та job модулийг browser дээрээ харж болно:

http://jobeet.localhost/frontend_dev.php/jo b

Хэрэв та ажлын байрыг засварлах гэж үзвэл, Category id унадаг цэсээс бүх боломжит ангилалуудын

жагсаалтыг харна. Сонголт бүрийн утгууд нь __toString() функцаас ирж байгаа.

Docrine үндсэн __toString() функцийг тодорхой багануудын нэрээр жишээ нь title, name, subject гэх

мэтээр үүсгэх гэж оролддог. Хэрэв та өөрийн __toString() функцийг ү үсгэхийг хүсвэл доорхийн

адилаар үүсгэх боломжтой. JobeetCategory model -ийн __toString() функцийг jobeet_category

хүснэгтийн name баганаар байдгаар гэж үзье

// lib/model/doctrine/JobeetJob.class.php

class JobeetJob extends BaseJobeetJob

{

public function __toString()

{

return sprintf(‘%s at %s (%s)’, $this->getPosition(),

$this->getCompany(), $this->getLocation());

}

// lib/model/doctrine/JobeetAffiliate.class.php

class JobeetAffiliate extends BaseJobeetAffiliate

{

public function __toString()

{

return $this->getUrl();

}

}

Одоо та ажлын байрууд үүсгэж, засварлах боломжтой боллоо. Заавал оруулах шаардлагатай

талбаруудыг хоосон эсвэл date—д буруу утга оруулж үзээрэй. Тэгвэл та symfony үүссэн баазын

schema-аар үндсэн баталгаажуулалтыг(validation) үүсгэдгийг харна.

Маргааш болтол баяртай.

Өнөөдөртөө ингээд боллоо. Танилцуулгын эхэнд таньд сануулсанчлан өнөөдөр бид дөнгөж жоохон

PHP код бичсэн боловч бид өөрчилж, сайжруулахад бэлэн болсон job model -ийн модуль –тай болсон.

Ямар ч PHP код байхгүй гэдэг нь өөр хэлбэл ямар ч алдаагүй гэдгийг санаарай.

Хэрэв та одоо сэргэг, хангалттай энергитэй байгаа бол, модульд үүссэн код болон model -ийг харан

хэрхэн ажиллаж байгааг ойлгохыг хичээгээрэй. Үгүй бол, санаа зоволтгүй ээ, сайхан амраарай,

маргааш бид хамгийн их вэб framework-д хэрэглэгдэж байгаа paradigm MVC загварчлалын талаар

ярилцана.

Санамж

YML format-аар бичихдээ хоорондын зайг нь сайн харах хэрэгтэй шүү. Дагалдах schema.yml, jobs.yml,

categories.yml файлуудыг

http://rapidshare.com/files/40227502 0/jobeet_yml-uud.rar

холбоосоор татаж авч болно.

4 дөх өдөр

4AUG

The Controller and the View

Өчигдөр бид symfony өгөгдлийн баазыг хэрхэн энгийнээрdatabase engine хоорондын ялгааг abstract хийдэг, харилцан холбоотой элемент (relational element) –ыг объект хандалтад класс болгохыг судалдсан. Мөн бид Doctrine-оор өгөгдлийн баазын схем (schema) –г тодорхойлох, хүснэгт үүсгэх, мөн баазаас өгөгдлийг цуглуулахыг авч үзсэн.

Өнөөдөр бид өчигдрийн үүсгэсэн үндсэн job модуль-г өөрчлөхболно. Job модуль аль хэдийн бидэн хэрэгтэй Jobeet –д байх бүх кодуудыг агуулсан байгаа.

• Бүх ажлыг жагсаах хуудас

• Шинэ ажил үүсгэх хуудас

• Өмнөх ажилыг засварлах хуудас

• Ажлыг устгах хуудас

Код ашиглахад бэлэн байгаа хэдий ч бид Jobeet-ын шаардлагад тохируулахын тулд template-үүдийг дахин байгуулна.

Энэ бүх асуудлаас гарах сайхан шийдэл бас байнаа. Вэбийн хөгжилд өнөө үед кодоо зохицуулах хамгийн түгээмэл шийдэл бол

The MVC Architecture

Хэрэв та ямар нэгэн framework ашиглахгүй PHP вэбсайт хөгжүүлж байсан бол HTML хуудас бүрт нэг PHP файл гэсэн дүрмээр ажиллаж байсан байх. Тэдгээр PHP файлууд нь нэг ижил төрлийн бүтцийг агуулдаг: үүсгэх, ерөнхий тохиргоо, хүсэлтийн хуудастай холбоотой бизнес логик, баазаас өгөгдөл цуглуулах мөн эцэст хуудсыг үүсгэх HTML хуудас гэх зэрэг.

Та магадгүй HTML хуудсаас template-ын логик-ыг тусд ашиглаж байсан байх. Мөн та баазын abstraction layer—ыг тусд нь бизнес логик-с ангид авч ашиглаж байсан байж магадгүй. Гэсэн ч та ихэвчлэн эмхтгэхэд нилээн төвөгтэй маш их кодтой л үлддэг байсан.

Хэдийгээр хийхэд нилээн хурдан боловч, хөгжүүлэх тусам өөрчлөлт хийхэд төвөгтэй болж, таниас бараг өөр хүн хэрхэн хийгдэж, ажиллаж байгааг бараг ойлгохгүй болдог.

MVCзагварчлалын хэв маяг юм.

Товчхондоо, MVCзагварчлалын хэв маяг нь кодыг тань байх ёстой зарчмых нь дагуу зохицуулахыг тодорхойлдог. Энэ хэв маяг нь кодуудыг 3 давхаргад (layer) –т хуваан авч үздэг.

• The Model давхарга бизнес логикийг тодорхойлдог (өгөгдлийн бааз мөн энэ давхаргад хамаарна). Та symfony бүх класс болонModel-той холбоотой бүх файлуудыг lib/model/ хавтасд хадгалдгыг аль хэдийн мэдсэн байх.

• The View хэрэглэгч ямар зүйлтэй харицаж байгаа байдал(template engine энэ давхаргын нэг хэсэгт орно). Symfony-д голдуу View давхарга нь PHP template-ээр үүсдэг. Тэд өөр өөр templates/ хавтасд хадгалагддаг. Өнөөдрийн хичээлээр үүнийг харна.

• The Controller бол хэрэглэгчээс хүссэн өгөгдлийг Modelхэсгээс View давхарга руу дамжуулах Model-ыг дуудах багахан код. Эхний өдөр symfony-ыг суулгах үед бүх хүсэлт front controller-р зохицуулагддыг харсан (index.php ба

frontend_dev.php). Эдгээр контроллорууд нь яг жинхэнэ ажиллахaction-уудыг төлөөлдөг. Өчигдөг харсанчлан тэдгээр action-гууд логикоор module-

Өнөөдөр бид 2 дахь өдөр тодорхойлогдсон гараар гаргасан загварын дагуу нүүр хуудас болон job хуудсыг өөрчлөх болно. Бид мөн тэдгээрийг динамик болгоно. Тэдгээрийн хажуугаар бидsymfony-ийн хавсын бүтцийн дагуу, кодуудыг давхаргуудаар тусгаарлах зэрэг маш их чимхлүүр ажил хийнэ.

уудад бүлэглэгдэн байрладаг.

The Layout

Хэрэв та гараар гаргасан загварыг сайн харсан бол ихэнх хуудас бүр ижилхэн харагдаж байгааг ажигласан байх. HTMLэсвэл PHP код гэдгээс хамааран код дахин давтах нь муу арга гэдгийг та мэдэж байгаа байх. Тиймээс бид харагдах элементүүдийг дахин код давтагдахгүйгээр харуулах арга замыг олох хэрэгтэй болно.

Энэ асуудлыг шийдэх нэг арга бол header болон footer-ыг тусд нь үүсгээд include хийж template бүрт дуудаж өгөх.

Гэвч энд header болон footer файлууд нь яг үнэн HTML –г агуулахгүй. Энэнээс өөр дээр арга байх ёстой. Өмнө байсан зүйлийг дахин үүсгэхийн орон бид энэ асуудлыг шийдэх өөр нэг загварчлалын хэв маягийг хэрэглэнэ. Decorator загварчлалын хэв маяг (design pattern).http://en.wikipedia.org/wiki/Decorator_pattern

Decorator design pattern нь өөр аргаар энэ асуудлыг шийднэ:global template-ээр content нь өгөгдсөний дараа template нь чимэглэгдэнэ. Үүнийг symfony –д Layout гэж нэрлэнэ.

Application-ны default layout нь layout.php гэж дуудагддаг бөгөөдapps/frontend/templates/ гэсэн хавтасд байрлана. Энэ хавтас нь бүх глобал template-үүдийг агуулдаг.

Дараах кодоор default symfony-ийн layout-ыг өөрчил.

<!– apps/frontend/templates/layout.php –> <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>

<html xmlns=”http://www.w3.org/1999/xhtml” xml:lang=”en” lang=”en”> <head> <title>Jobeet – Your best job board</title> <link rel=”shortcut icon” href=”/favicon.ico” /> <?php include_javascripts() ?> <?php include_stylesheets() ?> </head> <body> <div> <div> <div> <h1><a href=”<?php echo url_for(‘job/index’) ?>”> <img src=”http://www.symfony-project.org/images/logo.jpg” alt=”Jobeet Job Board” /> </a></h1> <div> <div> <h2>Ask for people</h2> <div> <a href=”<?php echo url_for(‘job/index’) ?>”>Post a Job</a> </div> </div> <div> <h2>Ask for a job</h2> <form action=”" method=”get”> <input id=”search_keywords” /> <input value=”search” /> <div> Enter some keywords (city, country, position, …) </div> </form> </div> </div> </div> </div> <div> <?php if ($sf_user->hasFlash(‘notice’)): ?> <div> <?php echo $sf_user->getFlash(‘notice’) ?> </div>

<?php endif; ?> <?php if ($sf_user->hasFlash(‘error’)): ?> <div> <?php echo $sf_user->getFlash(‘error’) ?> </div> <?php endif; ?> <div> <?php echo $sf_content ?> </div> </div> <div> <div> <span> <img src=”http://www.symfony-project.org/images/jobeet-mini.png” /> powered by <a href=”http://www.symfony-project.org/”> <img src=”http://www.symfony-project.org/images/symfony.gif”

alt=”symfony framework” /> </a> </span> <ul> <li><a href=”">About Jobeet</a></li> <li><a href=”">Full feed</a></li> <li><a href=”">Jobeet API</a></li> <li><a href=”">Affiliates</a></li> </ul> </div> </div> </div></body></html>

Symfony-ын template нь жирийн PHP файл. Layout template-д та PHP функц дуудалт болон PHP хувьсагчыг харсан байх.~$sf_content~ бол хамгийн сонирхолтой хувьсагч: Энэ нь framework-оос өөрөөс нь тодорхойлогдсон ба action-аар боловсруулагдсан HTML-ийг агуулдаг.

Хэрэв та Брауз хийгээд job модулийг харвал(http://jobeet.localhost/frontend_dev.php/job), бүх action layout-аар хүрээлэгдсэн (чимэглэгдсэн) байгааг олж харна.

The Stylesheets, Images, and JavaScripts

Энэ хичээл нь загварчлалых биш болохоор бид аль хэдийнjobeet-д ашиглагдах нэмэлтүүдийг бэлтгэсэн байгаа: шахсан зураг http://www.symfony-project.org/get/jobeet/images.zip

, stylesheet-үүдийг эндээс

Layout –д бид favicon-ыг include хийсэн байгаа. Та Jobeet-д зориулсныг

татаж аваад web/images/, web/css/ хавтасд хадгал.

эндээс

Default –аараа generate:project команд нь project-ийн нэмэлтүүдэд зориулж 3 –н хавтсыг үүсгэдэг: зураг-дweb/images/, stylesheets-д web/css/, javascript-үүдэд web/js/хавтсыг.

Энэ нь symfony-с тодорхойлогдох бас нэг давуу тал бөгөөд мэдээж та өөрийн хүссэнээр тэдгээрийг web/ хавтасын хаа нэгтээ хадгалж бас болно.

Овсгоотой уншигч main.css файл default layout-ийн хаана нь ч дурьдагдаагүй болохыг ажигласан байх. Энэ гарцаагүй HTML-ээр харагдана. Гэвч энэ алга байна. Яаж ийм байж боломжтой вэ?

Stylesheet файлууд Layout-ын <head> tag-н доторхinclude_stylesheets() функцээр дуудагдан гарна.include_stylesheets() функцыг helper гэж нэрлэдэг. Helper болsymfony –д тодорхойлогддог параметер авч HTML код буцаадаг функц юм.

татаж аваад web/ гэсэн хавтасд байрлуул.

Ихэвчлэн helper-үүд template-үүдэд хэрэглэгдэх кодуудыг багцалж байдаг учираас цаг хэмнэгч болдог.include_stylesheets() helper stylesheet-үүдийн <link> tag-ийг үүсгэдэг.

Харин helper аль stylesheet-үүд include хийгдэх ёстойг яаж мэдэх вэ?

View давхарга нь application-ны тохиргооны файл болохview.yml гэсэн файлыг edit хийж тохируулж өгч болдог. Дараах код нь generate:appкомандаар үүссэн default нь:

# apps/frontend/config/view.yml

default:

http_metas:

content-type: text/html

metas:

#title: symfony project

#description: symfony project

#keywords: symfony, project

#language: en

#robots: index, follow

stylesheets: [main.css]

javascripts: []

has_layout: true

layout: layout

View.yml файл нь application-ны бүх template-ийн анхны утгуудыг тохируулдаг. Тухайлбал, stylesheet файлуудын массив оролтыгapplication-ны бүх хуудасд тодорхойлохыг include_stylesheets() helper-ээр тодорхойлно.

View.yml тохиргооны файлын default хамаатай файл нь main.css,/css/main.css биш юм. Хэдийгээр хоёулаа ижилхэн боловчsymfony угтвар(prefix) нь /css/ замтай холбоотой байдаг.

Хэрэв олон файл тодорхойлогдсон бол symfony тэдгээрийг тодорхойлолтых нь дарааллаар include хийдэг.

stylesheets: [main.css, jobs.css, job.css]

Та мөн .css гэсэн дагаврыг авч хаян медиа attribute –г өөрчлөх боломжтой.

stylesheets: [main.css, jobs.css, job.css, print: { media: print }]

Энэ тохиргоо нь дараах байдлаар харагдана гэсэн үг.

<link rel=”stylesheet” media=”screen”

href=”/css/main.css” />

<link rel=”stylesheet” media=”screen”

href=”/css/jobs.css” />

<link rel=”stylesheet” media=”screen”

href=”/css/job.css” />

<link rel=”stylesheet” media=”print”

href=”/css/print.css” />

view.yml тохиргооны файл нь application-нд хэрэглэгдэх defaultlayout-ыг мөн тодорхойлдог. Default үедээ нэр нь layout байдаг ба энэ нь symfony бүх хуудсуудыг layout.php файлаар хүрээлж чимнэ гэсэн үг. Мөн та has_layout оролтыг false болгосноор хүрээлж чимэх процессыг идэвхгүй болгож болно.

Дээрх ажиллах ёстой дагуу ажиллах боловч jobs.css файл нь зөвхөн нүүр хуудсанд мөн job.css файл нь зөвхөн job хуудсанд хэрэг болно. Энэ тохиолдолд view.yml тохиргооны файл нь модуль бүрт тохируулж өөрчлөгдөх боломжтой. Application-ныview.yml-ын stylesheet-ын хэсэгт зөвхөн main.css –ыг агуулахаар өөрчил.

# apps/frontend/config/view.yml

stylesheets: [main.css]

job модулын view-г өөрчлөхийн тулдapps/frontend/modules/job/config/ хавтасд view.yml файлыг үүсгэнэ:

# apps/frontend/modules/job/config/view.yml

indexSuccess:

stylesheets: [jobs.css]

showSuccess:

stylesheets: [job.css]

indexSuccess болон showSuccess (index болон show action-уудаар үүсэх template-ын нэрс, өнөөдөр бид үзнэ ,) хэсгийн доор та application-ны view.yml-ны default хэсэгт орох ямар ч оролтыг өөрчлөх боломжтой. Бүх онцлох оролтууд application-ны тохиргоонд холбогдон ажилладаг. Та мөн модулын бүх action-нд тохиргоо хийх бол all гэсэн онцгой хэсгийг ашиглах боломжтой.

Symfony-ын тохиргооны үндсэн зарчмууд

Их олон тохиргооны файлуудад ижилхэн тохиргоо өөр өөр level-д тохируулагдаж болдог.

• The default configuration: framework-д байрлана.

• The global configuration: project-д ( config/ хавтасд)

• The local configuration: application-д (apps/APP/config/ хавтасд)

• The local configuration

<?php use_stylesheet(‘jobs.css’) ?>

: модульд зориулагдсан нь ( apps/APP/modules/MODULE/

config/)

Ажиллах үед тохиргооны систем өөр өөр файлуудын тэдгээрт байгаа бүх утгуудыг холбон cache- хийж ажиллагааг сайжруулдаг.

Гол бас зарчим бол хэрэв файл-ын тохиргоо нь via байдлаар тохируулагддаг бол PHP кодоор ижилхэн гүйцэтгэгдэж болдог. Тухайлбал job модульд view.yml файл үүсгэхийн орондuse_stylesheet() helper-ыг ашиглан stylesheet-ыг template-д ашиглаж болно:

<?php use_stylesheet(‘main.css’) ?>

Та мөн энэ helper-ыг ашиглан layout-д stylesheet-ыг глобал-аарinclude хийх боломжтой.

Аль аргыг ашиглах нь тухайн байдлаас л хамаарна. View.ymlфайл нь Template-д боломжгүй тохиргоог модулын бүх Action-д зориулж тодорхойлогдох боломжтой бөгөөд тохиргоо нь статик хэлбэртэй байна. Харин нөгөө талаас use_stylesheet() ашиглах нь илүү уян хатан бөгөөд мөн түүнчлэн stylesheet-үүн тохируулалт болон HTML кодууд нэгэн доор байрлана. Jobeet-д бид use_stylesheet() helper-ыг ашиглана. Тиймээс та үүсгэсэнView.yml-ыг устгаад job template-ыг use_stylesheet()-ээр дуудахаар өөрчилнө үү:

<!– apps/frontend/modules/job/templates/indexSuccess.php –>

<!– apps/frontend/modules/job/templates/showSuccess.php –>

<?php use_stylesheet(‘job.css’) ?>

Ижилхэнээр javascript-ын мөн view.yml тохиргооны файлдjavascripts оролт болон template хэсэгт use_javascript() helper-ыг ашиглан javascript-ыг include хийх боломжтой.

The Job Homepage

3 дахь өдөр харсанчлан job-ын нүүр хуудас нь job модулын indexaction-аар үүсдэг. Index action нь хуудсын Controller хэсэг бөгөөд template-тэй холбогддог, IndexSucces.php бол View-ын хэсэг.

apps/

frontend/

modules/

job/

actions/

actions.class.php

templates/

indexSuccess.php

The Action

Action бүр класын method (функц)-ыг төлөөлдөг. Job нүүр хуудасны хувьд класс нь jobActions (модулын нэр залгаад Actions) ба method нь executeIndex() (execute залгаад action-ны нэр). Энд өгөгдлийн баазаас бүх ажлын байрны жагсаалтыг гаргаж ирнэ.

// apps/frontend/modules/job/actions/actions.class.php

class jobActions extends sfActions

{

public function executeIndex(sfWebRequest $request)

{

$this->jobeet_job_list = Doctrine::getTable(‘JobeetJob’)

->createQuery(‘a’)

->execute();

}

// …

}

Кодыг нарийвчилж үзвэл: executeIndex() функц (Controller) бүх ажлын байрны мэдээллийг авах хүсэлтийг үүсгэхийн тулд JobeetJob хүснэгтийг дуудна. Энэ jobeet_job_list руу объектыг дамжуулах JobeetJob объектын Doctrine_Collection –г буцаана.

Бүх гарах объектууд автоматаар template (view) рүү дамжигдана. Controller-оос View рүү өгөгдөл дамжуулахыг харахын тулд шинийг үүсгэж үзэцгээе:

public function executeFooBar(sfWebRequest $request)

{

$this->foo = ‘bar’;

$this->bar = array(‘bar’, ‘baz’);

}

Энэ код нь $foo ба $bar хувьсагчдыг template-с холбогдохуйц болгоно.

<?php use_stylesheet(‘jobs.css’) ?> <h1>Job List</h1> <table> <thead> <tr>

The Template

Ерөнхийдөө template-ын нэр action-ны нэртэй холбогдсон байна(action-ны нэр залгаад Success).

indexSuccess.php template нь бүх ажлын байрны HTMLхүснэгтийг үүсгэнэ. Дараах бидний одоо ашиглах код:

<!– apps/frontend/modules/job/templates/indexSuccess.php –>

<th>Id</th> <th>Category</th> <th>Type</th> <!– more columns here –> <th>Created at</th> <th>Updated at</th> </tr> </thead> <tbody> <?php foreach ($jobeet_job_list as $jobeet_job): ?> <tr> <td> <a href=”<?php echo url_for(‘job/show?id=’.$jobeet_job->getId()) ?>”> <?php echo $jobeet_job->getId() ?> </a> </td> <td><?php echo $jobeet_job->getCategoryId() ?></td> <td><?php echo $jobeet_job->getType() ?></td> <!– more columns here –> <td><?php echo $jobeet_job->getCreatedAt() ?></td> <td><?php echo $jobeet_job->getUpdatedAt() ?></td> </tr> <?php endforeach; ?> </tbody> </table> <a href=”<?php echo url_for(‘job/new’) ?>”>New</a>

Template кодонд foreach нь job объектын жагсаалт ба job бүрт давтагдан багана бүрийн утгыг гаргана. Баганы утгыг авах нь тун энгийн бөгөөд get-ээр эхлээд camelCase-д баганы нэрийг залгаж (жишээ нь getCreatedAt method бол created_at баганых)холбогдох method-ыг дуудна.

Дээрх кодоо цэвэрлээд боломжтой багануудын утгуудыг харуулъя.

<!– apps/frontend/modules/job/templates/indexSuccess.php –>

<?php use_stylesheet(‘jobs.css’) ?> <div> <table> <?php foreach ($jobeet_job_list as $i => $job): ?> <tr> <td><?php echo $job->getLocation() ?></td>

<td> <a href=”<?php echo url_for(‘job/show?id=’.$job->getId()) ?>”> <?php echo $job->getPosition() ?> </a> </td> <td><?php echo $job->getCompany() ?></td> </tr> <?php endforeach; ?> </table> </div>

Template –д байгаа url_for функц бол symfony-ын helper бөгөөд маргааш бид үүнийг ярих болно.

The Job Page Template

Одоо job хуудсын template-ыг өөрчилцгөөе. showSuccess.phpфайлыг нээгээд дараах кодоор контентыг засварлана уу.

<!– apps/frontend/modules/job/templates/showSuccess.php –>

<?php use_stylesheet(‘job.css’) ?> <?php use_helper(‘Text’) ?> <div> <h1><?php echo $job->getCompany() ?></h1> <h2><?php echo $job->getLocation() ?></h2> <h3> <?php echo $job->getPosition() ?> <small> – <?php echo $job->getType() ?></small> </h3> <?php if ($job->getLogo()): ?> <div> <a href=”<?php echo $job->getUrl() ?>”> <img src=”http://www.symfony-project.org/uploads/jobs/<?php echo $job->getLogo() ?>” alt=”<?php echo $job->getCompany() ?> logo” /> </a> </div> <?php endif; ?> <div> <?php echo simple_format_text($job->getDescription()) ?> </div> <h4>How to apply?</h4> <p><?php echo $job->getHowToApply() ?></p> <div> <small>posted on <?php echo $job->getDateTimeObject(‘created_at’)->format(‘m/d/Y’) ?></small> </div> <div style=”padding: 20px 0″> <a href=”<?php echo url_for(‘job/edit?id=’.$job->getId()) ?>”> Edit </a> </div> </div>

Энэ template-д action-аас дамжигдах $job хувьсагч нь job-ын мэдээллийг харуулна. Бид template рүү дамжигдах $jobeet_job-ыг $job болгож өөрчилсөн болохоор, show action-д та мөн энэ өөрчлөлтыг хийх хэрэгтэй ( Энд хувьсагч 2 удаа давтагдсан байгааг анхаараарай).

// apps/frontend/modules/job/actions/actions.class.php

public function executeShow(sfWebRequest $request)

{

$this->job = Doctrine::getTable(‘JobeetJob’)->

find($request->getParameter(‘id’));

$this->forward404Unless($this->job);

}

Date баганын утга PHP-ын DateTime объект болсоныг анзаарсан байх. Бид created_at баганыг timestamp-аар тодорхойлсон болохоор, та getDateTimeObject method-ыг ашиглан баганын утгыг DateTime объект руу хөрвүүлэх боломжтой ба мөн format method-г ашиглан эхний аргументэд фоматын загварыг өгч дуудаж ашиглах боломжтой.

$job->getDateTimeObject(‘created_at’)->format(‘m/d/Y’);

Job description нь simple_format_text() helper-ыг хэрэглэн дамжих утгыг засварлаж жишээ нь <br /> -ыг ашиглан HTML руу форматлаж байна. Энэ helper нь Text Group-д багтах бөгөөдdefault үед дуудагдаагүй бид use_helper helper-ыг ашиглан дуудаж өгсөн болно.

Slots

Яг одоо бүх хуудасны гарчигууд layout-ны <title> тэг-ээр тодорхойлогдож байгаа.

<title>Jobeet – Your best job board</title>

Харин job хуудсын хувьд бид илүү хэрэгтэй мэдээлэл болох компани нэр, ажлын байр зэргийг гаргамаар байна.

Symfony-д дэлгэцэд харагдах layout нь template –ээс хамаарч байгаа үед та slot-ыг тодорхойлох шаардлагатай:

Slot-ыг layout-д нэмсэнээр гарчигийг динамик болгож байна.

// apps/frontend/templates/layout.php

<title><?php include_slot(‘title’) ?></title>

Slot бүр нэртэйгээр (title) тодорхойлогдох ба include_slot() helper-ыг ашиглан дэлгэцэнд гарна.

Одоо, showSuccess.php template-ын эхэнд slot() helper-ыг тодорхойлж job хуудасны slot- ыг тодорхойлъё:

// apps/frontend/modules/job/templates/showSuccess.php

<?php slot(

‘title’,

sprintf(‘%s is looking for a %s’, $job->getCompany(),

$job->getPosition()))

?>

Хэрэв гарчиг нь бүрэн гүйцэт бол slot helper-ыг блок кодоор мөн ашиглаж болдог.

// apps/frontend/modules/job/templates/showSuccess.php

<?php slot(‘title’) ?>

<?php echo sprintf(‘%s is looking for a %s’, $job->getCompany(),

$job->getPosition()) ?>

<?php end_slot(); ?>

Нүүр хуудас зэрэг зарим хуудасны хувьд бид ерөнхий гарчиг оноох шаардлагатай. Ижил гарчиг template бүрт давтан өгөхийн оронд бид default гарчгийг layout-д тодорхойлж өгч болно.

// apps/frontend/templates/layout.php

<title>

<?php include_slot(‘title’, ‘Jobeet – Your best job board’) ?>

</title>

Include_slot() method-ын 2 дахь аргумент нь slotтодорхойлогдоогүй үед дуудагдах default утга. Хэрэв default утга нь урт эсвэл зарим HTML tag агуулсан бол дараах байдлаар тодорхойлж мөн болно:

// apps/frontend/templates/layout.php

<title>

<?php if (!include_slot(‘title’)): ?>

Jobeet – Your best job board

<?php endif; ?>

</title>

Slot тодорхойлогдсон бол include_slot() helper true утгыг буцаана. Тиймээс template-д та гарчгын slot-ын утгыг тодорхойлсон бол тэр нь хэрэглэгдэнэ, үгүй бол default гарчиг нь хэрэглэгдэнэ.

Бид include_ -аар эхэлсэн хэд хэдэн helper-ыг авч үзлээ. Эдгээрhelper-үүд HTML код буцаах ба ихэнх үед get_ helper агуулгыг буцааж байна.

<?php include_slot(‘title’) ?>

<?php echo get_slot(‘title’) ?>

<?php include_stylesheets() ?>

<?php echo get_stylesheets() ?>

The Job Page Action

Job хуудас show action-аар үүсэж, job модулын executeShow()method-д тодорхойлогдоно.

class jobActions extends sfActions

{

public function executeShow(sfWebRequest $request)

{

$this->job = Doctrine::getTable(‘JobeetJob’)->

find($request->getParameter(‘id’));

$this->forward404Unless($this->job);

}

// …

}

Index action дээрх шиг, JobeetJob table класс job-ыг гаргахад хэрэглэгдэх ба энэ удаад find() method-г хэрэглэнэ. Энэ method-ын параметер нь job-ын цор ганц (unique) ялгагч primary keyбайна. Дараагын хэсэгт яагаад $request->getParameter(‘id’)гэсэн мөр job primary key-ыг буцаадгыг тайлбарлана.

Хэрэв job өгөгдлийн баазад байхгүй бол бид хэрэглэгчдэдforward404Unless() method-ын 404 хуудсыг хэвлэнэ. Эхний утгыг Boolean-аар авах ба үнэн биш бол хийгдэх үйлдлийг зогсооно.Forward method Action-ны үйлдлийг шууд тэр дор нь зогсоогоодsfError404Exception –г шиднэ. Араас нь ямар нэгэн утга буцаах шаардлагагүй.

Хэрэглэгчдэд харагдах exception бүр prod болон dev орчиноос хамаараад өөр өөрөөр хэвлэгдэнэ.

Jobeet вэбсайтаа production server-рүү deploy хийхээс өмнө таdefault 404 хуудсыг хэрхэн өөрчлөхыг сурч авна.

“forward” method-ын бүлэг

forward404Unless үнэндээ дараахтай тэнцүү:

$this->forward404If(!$this->job);

Энэ нь мөн дараахтай тэнцүү:

if (!$this->job)

{

$this->forward404();

}

forward404() method бол $this->forward(‘default’, ’404′); -ынshortcut н юм.

Forward() method ижил application-ны өөр Action руу заадаг: өмнөх жишээн дээр default модулын 404 action руу заасан.

The Request and the Response (хүсэлт ба хариу)

Хэрэв та /job юмуу /job/show/id/1 гэсэн хаягаар хандвал сервэртэй харьцах харилцааг үүсгэнэ. Хандалт нь хүсэлтийгилгээж сервер хариугбуцааж илгээнэ.

Бид symfony хүсэлтийг sfWebRequest объектод агуулдгийг өмнө нь харсан (executeShow method –ыг хар). Мөн symfony объект хандалтад framework болохоор хариу (response) мөнsfWebResponse классын объект. Та хариу (response) объекттойaction дээр $this->getResponse() гэж дуудан холбогдох боломжтой.

Эдгээр объектууд PHP функцууд болон PHP глобал хувьсагчууд харьцах маш олон боломжит method-г агуулдаг.

Яагаад symfony өмнөх PHP функционалуудыг бүрхдэг вэ? Нэгдүгээрт

Symfony-ын method-ууд PHP ижил method- оос хамаагүй хүчирхэг. Мөн хэрэв та application-г тест хийвэл хүсэлт ба хариу(request Ба response) объекттой ажиллахад глобал хувьсагч эсвэл хэтэрхий түвэгтэй PHP функцууд болох header()функцуудыг бодвол илүү энгийн байдаг.

The Request (Хүсэлт)

sfWebRequest класс ~$_SERVER~, ~$_COOKIE~, ~$_GET~, ~$_POST~, болон

~$_FILES~ PHP глобал array-уудыг агуулдаг:

Method-ын нэр PHP

getUri() $_SERVER['REQUEST_URI']

–ын тэнцүү утга

getMethod() $_SERVER['REQUEST_METHOD']

getReferer() $_SERVER['HTTP_REFERER']

getHost() $_SERVER['HTTP_HOST']

getLanguages() $_SERVER['HTTP_ACCEPT_LANGUAGE']

Method-ын нэр PHP -ын тэнцүү утга

getCharsets() $_SERVER['HTTP_ACCEPT_CHARSET']

isXmlHttpRequest() $_SERVER['X_REQUESTED_WITH'] == ‘XMLHttpRequest’

getHttpHeader() $_SERVER

getCookie() $_COOKIE

isSecure() $_SERVER['HTTPS']

getFiles() $_FILES

getGetParameter() $_GET

getPostParameter() $_POST

getUrlParameter() $_SERVER['PATH_INFO']

getRemoteAddress() $_SERVER['REMOTE_ADDR']

Бид өмнө нь getParameter() method –г ашиглаж хүсэлтийн параметртэй холбогдож байсан. Энэ $_GET эсвэл $_POST эсвэл PATH_INFO глобал хувьсагчуудын утгыг буцаадаг.

Хэрэв та яг аль хувьсагчаас утга ирж байгаас мэдэхийг хүсвэл та getGetParameter(), getPostParameter(), болон getUrlParameter() method-уудыг ашиглах хэрэгтэй.

ХЭрэв та action-г тодорхой нэг HTTP method-р хязгаарлагдмал байлгахыг хүсвэл тухайлбал хэрэв та форм-аас ирсэн утгаPOST-р илгээгдсэнийг мэдэхийг хүсвэл, та isMethod() method-ыг ашиглаж болно: $this->forwardUnless($request->isMethod(‘POST’));.

The Response (Хариу)

sfWebResponse класс header() болон serawcookie() PHP method-уудыг агуулдаг.

Method-ын нэр PHP

setStatusCode() header()

–ын тэнцүү утга

setCookie() setrawcookie()

setHttpHeader() header()

setContentType() header()

addVaryHttpHeader() header()

addCacheControlHttpHeader() header()

Мэдээж, sfWebResponse класс мөн response-ын агуулгыг оноож өгч болдог (senContent болон браузер руу хариуг буцаах send()).

Өнөөдрийн эхний хэсэгт бид stylesheet болон JavaScript –үүдийгview.yml болон template-д хэрхэн зохицуулж өгөхийг харсан. Эцэст нь хоёулаа response-ын объектын addStylesheet() болонaddJavascript() method-уудыг ашигладаг.

The sfAction/ http://www.symfony-project.org/api/1_4/sfAction/ , sfRequest/ http://www.symfony-project.org/api/1_4/sfRequest/

sfResponse/

,болон

http://www.symfony-project.org/api/1_4/sfResponse/классууд өөр олон method-уудыг тодорхойлдог. API-ын хавтас-д зочилж бүх symfony классуудыг мэдэж авахдаа бүү эргэлз.

Маргааш болтол баяртай.

Өнөөдөр бид symfony-д ашиглагддаг зарим загварчлалын хэв шинжийг авч үзлээ. Одоо project –ын бүтэц илүү ойлгомжтой болсон гэдэгт найдаж байна. Бид мөн layout –д гаргах template-үүд болон template файлуудыг авч үзсэн. Бид мөн slot-ууд болонaction-уудын ачаар тэдгээрийг багахан динамик болгосон.

Маргааш бид өнөөдөр ашигласан url_for() helper-ын талаар илүү сурна мөн дэд framework болох routing-ын талаар үзнэ.

5 дахь өдөр

26AUG

DAY5 The Routing Хэрэв та 4 дэхь өдрийг дуусгацан бол та MVC загварчлалын талаар нилээд мэдлэгтэй болсон бөгөөд кодчлолын ухагдахууныг илүү мэдэрч байгаа байх. Дахин багахан цагийг өнгрөөснөөр та дахин эргэж харахгүй болно. Өчигдөр дадлагаар бид Jobeet хуудсуудыг өөрчилж, мөн layout, helper, slot зэрэг хэд хэдэн symfony-ын ойлголтуудтай танилцсан. Өнөөдөр бид гайхамшигт symfony routing framework-той танилцана. URLs Хэрэв та Jobeet-ын нүүр хуудсан дээр даралт хийвэл url нь дараах байдлаар харагдана: /job/show/id/1.. Хэрэв та өмнө ньPHP дээр вэбсайт хөгжүүлж байсан бол та /job.php?id=1URL-тэй байгаад дассан байх. Яаж symfony ингэж ажиллуулж байна вэ?Яаж symfonyURL дээрх утгаар action-г тодорхойлж байна вэ? Яагаад job-ын id нь $request->getParameter(‘id’) –аар авагддаг вэ? Өнөөдөр бид эдгээр асуултуудад

хариулт авах болно. Эхлээд Url яг юу болох тухай ярилцацгаая. Вэб-д URL бол вэб-ийн нөөцийн цорын ганц ялгагч. Та URL-аар явахад браузераасURL-аас ялгагдах нөөцийг авахыг асууна. Тиймээс URL вэб сайт хэрэглэгч хоёрын хоорондох интерфэйс болохоор өөртөө нөөцийн тухай зарим олгомжгүй мэдээллийг хавсаргадаг. “Уламжлалт” URL нөөцийн тухай мэдээллийг агуулдаггүй, тэдapplication-ны дотоод бүтцийг илэрхийлдэг. Хэрэглэгчдэд тухайн вэб сайт PHP хэл дээр хийгдсэн мөн ажлын байр бүр баазад өөрийн гэсэн ялгагчтай эсэх нь хамаагүй байдаг. Хамгаалалтын хувьд application-ны дотоод бүтцийг ил гаргах нь муу үр дүнтэй байдаг: Хэрэглэгч холбогдох шаардлагүй нөөцийн URL-ыг таах гэж оролдвол яах

вэ? Мэдээж, хөгжүүлэгч тэдгээрийг тохиромжтой хэлбэрээр нууцлах ёстой ба нарийн мэдээллийг нуух нь гарцаагүй. URL symfony-д маш чухал бөгөөд тэдгээрийн менежментэд зориулсан өөрийн гэсэн бүхэл бүтэн framework-оос бүрдэнэ:routingframework.Routing дотоод URI-ууд болонгадаад URL-уудыг зохицуулдаг. Хүсэлт ирэхэд routingURL-ыг задлан ялгаж дотоод URI-руу хөрвүүлдэг. Та showSuccess.php template-ээс job хуудсындотоод URI-г харсан байх. ‘job/show?id=’.$job->getId() url_for helper дотоод URI-ыг зохимжтой URL рүү хөрвүүлдэг. /job/show/id/1 ДОтоод URI хэд хэдэн хэсгээс тогтдог: job бол модуль, show бол action мөнquery –ын action руу дамжуулах параметрууд. Дотоод URI-ын ерөнхий хэлбэр нь: MODULE/ACTION?key=value&key_1=value_1&… Symfony routing нь 2 замт процесс учираас та дотоод хэрэгжилтийг өөрчлөхгүйгээр URL-ыг өөрчлөх боломжтой байдаг. Routing тохиргоо Дотоод URI болон гадаад URL-ын хоорондын зурагжилт ньrouting тохиргооны файлд тодорхойлогддог. # apps/frontend/config/routing.yml homepage: url: / param: { module: default, action: index } default_index: url: /:module param: { action: index } default: url: /:module/:action/* routing.yml файл route(зам, чиглэл)-үүдийг тодорхойлдог. Route- нь нэр (homepage) , хэв загвар (/:module/:action/*),зарим параметртэй (param түлхүүр үгний доор байрших) байдаг. Хүсэлт ирэхэд routing өгөгдсөн URL –ыг хэв загвараас хайж тохируулахыг оролддог. Хамгийн түрүүнд тохирсон хэв загвар нь биелэгддэг болохоор routing.yml- д дэс дараалал нь маш чухал байдаг. Хэрхэн ажилдгыг илүү ойлгохын тулд зарим нэг жишээнээс үзэцгээе. Та /job гэсэн URL –тэй Jobeet нүүр хуудсыг дуудахад хамгийн эхний тохирох хэв загвар нь default_index байна. Хэв загварт, (:)хоёр цэгээр эхэлсэн үг болгон хувьсагч, тиймээс :/module гэсэн загвар нь / тэгээд ямар нэгэн зүйл гэсэнтэй тохирно. Бидний жишээнд moduleхувьсагч jobгэсэн утгатай байна. Энэ утга ньaction хэсгээс $request->getParameter(‘module’) гэж дуудагдана. Энэ route(хэв загвар)actionхувьсагчын default утгыг мөн тодорхойлно. Тиймээс энэ загварт тохирох бүх URL-уудын хувьд хүсэлт бүр index гэх утгатай action параметр-тэй байна гэсэн үг. Хэрэв та /job/show/id/1гэсэн хүсэлт илгээвэл, symfony /:module/

:action/*гэх хамгийн сүүлийн загвартай тохируулна. Загварт од (*)нь ташуу зураасаар (/) –аар тусгаарлагдах олон хувьсагчын утгуудын нэгдэлтэй тохирно: Хүсэлтын параметр Утга module job action show id 1 module ба action хувьсагчууд symfony-д дуудагдахдаа аль action-г гүйцэтгэхийг тодорхойлдог болохоор онцгой төрөлд багтдаг. /job/show/id/1URL template хэсгээс дараах url_for helper-ээр дуудагдажүүсдэг: url_for(‘job/show?id=’.$job->getId()) Та мөн @-ээр эхлүүлж загварын нэрийг мөн ашиглаж болно: url_for(‘@default?module=job&action=show&id=’.$job->getId()) Дээрх хоёр дуудалт хоёул ижил боловч сүүлийнх хамгийн сайн тохирохыг нь олохын тулд бүх загваруудыг ялгах шаардлагагүй учир илүү хурдан ба гүйцэтгэл нь хамаагүй бага байна (module ба action –ын нэр нь дотоод URI-д өгөгдөөгүй). Route Customizations Яг одоо та / URL-р браузерт хүсэлт илгээвэл default баярын мэнд гэсэн symfony-ын хуудас гарч ирнэ. Энэ нь URL ньhomepage загвартай тохирсон гэсэн үг. Гэсэн ч Jobeet нүүр хуудас гарч ирдэгээр өөрчилж болно. Өөрчлөхийн тулдhomepage загварын module хувьсагчыг job болгон өөрчилнө. # apps/frontend/config/routing.yml homepage: url: / param: { module: job, action: index } Одоо бид Jobeet лого-ны холбоосыг homepage загвар руу заахаар болгоё. <!– apps/frontend/templates/layout.php –> <h1> <a href=”<?php echo url_for(‘@homepage’) ?>”> <img src=”http://www.symfony-project.org/images/logo.jpg” alt=”Jobeet Job Board” /> </a> </h1> Маш амархан байлаа. Routing тохиргооны файлд өөрчлөлт оруулсны дараа өөрчлөлт нь зөвхөнDevelopment орчны үед л шууд идэвхжих бөгөөд хэрэв та production орчны үед ажиллуулахыг хүсвэл cache:clear командаар cache-г цэвэрлэх хэрэгтэй. Илүү өөрийн болгохын тулд job хуудсын URL-ыг илүү утгатай болгон өөрчилье. /job/sensio-labs/paris-france/1/web-developer

Jobeet-ын талаар юуч мэдэхгүй , хуудсыг хараагүй байсан ч та URL-с Sensio Labs –ыхан Францын Парис-д Вэб хөгжүүлэгч хайж байгааг мэдэх боломжтой байна. Цэвэрхэн URL хэрэглэгчдэд мэдээлэл өгөх учираас маш чухал. Мөн энэ нь та email- д copy and paste хийхэд эсвэл хайлтын системд илүү өртөхын тулд илүү хэрэгтэй байдаг. Дараах загвар тэр URL-д тохирно. /job/:company/:location/:id/:position Routing.yml файлыг Edit хийж файлын эхэнд job_show_user загварыг нэм. job_show_user: url: /job/:company/:location/:id/:position param: { module: job, action: show } Хэрэв та одоо нүүр хуудсыг refresh хийж сэргээвэл, job-ын холбоос өөрчлөгдөөгүй байгаа. Яагаад гэвэл route боловсруулагдахын тулд, та шаардлагатай бүх хувьсагчаар хангах хэрэгтэй болно. Тиймээс одооindexSuccess.php файл дахь url_for()helper-ыг өөрчлөх хэрэгтэй. url_for(‘job/show?id=’.$job->getId().’&company=’.$job->getCompany(). ‘&location=’.$job->getLocation().’&position=’.$job->getPosition()) Дотоод URI мөн массиваар илэрхийлэгдэж болдог. url_for(array( ‘module’ => ‘job’, ‘action’ => ‘show’, ‘id’ => $job->getId(), ‘company’ => $job->getCompany(), ‘location’ => $job->getLocation(), ‘position’ => $job->getPosition(), )) Requirements(Шаардлагууд) Хичээлийн эхний өдөр бид алдааны баталгаажуулалт ба боловсруулалт нь сайн зүйлийн талаар ярьцгаасан. Route систем нь баталгаажуулалттайгаар хийгдсэнээрээ давуу талтай. Route (Загвар) хувьсагчбүр route-ын тодорхойлолтынrequirementsгэсэн түлхүүр үгэнд ашиглагдах илэрхийллийн дагуу баталгаажуулагддаг: job_show_user: url: /job/:company/:location/:id/:position param: { module: job, action: show } requirements: id: \d+ Дээрх requirements оролт нь id –г заавал тоон утгатай байх ёстойг илэрхийлнэ. Хэрэв үгүй бол route тохирохгүй. Route Class

Routing.yml –д тодорхойлогдох route бүр sfRoute/http://www.symfony-project.org/api/1_4/sfRoute/классын объект болон хөрвүүлэгддэг. Энэ класс нь route-ын тодорхойлолтонд class оролтыг оруулж өгсөнөөр өөрчлөгдөж болдог. Хэрэв та HTTP протокол-ын талаар ойлголттой бол, та GET, POST, ~HEAD|HEAD (HTTP Method)~, DELETE, PUTгэх зэрэг хэдэн “аргууд” байдгыг мэднэ. Эхний 3-г нь бүх браузерууд дэмждэг ба харин нөгөө 2-ыг нь дэмждэггүй. Route-ыг тодорхой хэдэн аргуудаар хязгаарлахыг хүсвэл таroute –ын class-г sfRequestRoute/http://www.symfony-project.org/api/1_4/sfRequestRoute/ болгон өөрчилж мөн requirements-дээр sf_method хувьсагчыг нэмж өгч болно: job_show_user: url: /job/:company/:location/:id/:position class: sfRequestRoute param: { module: job, action: show } requirements: id: \d+ sf_method: [get] route-д зөвхөн зарим HTTP аргуудыг тохирдог болгох нь action- хэсгээсsfWebRequest::isMethod() –г ашиглахтай бүрэн ижил биш юм. Энэ нь яагаад гэвэл routing нь арга нь таарахгүй байгаа route-ээс цааш мөн үргэлжлүүлж хайдаг учираас тэр юм. Object Route Class Job-ын шинэ дотоод URI нь нилээн урт ба бичихэд ядаргаатай байна (url_for(‘job/show?id=’.$job->getId().’&company=’.$job->getCompany().’&location=’.$job->getLocation().’&position=’.$job- >getPosition())),гэвч бид өмнөх хэсгээс сурсанчлан route классыг өөрчлөх боломжтой. job_show_user route-ын хувьдsfDoctrineRoute/http://www.symfony-project.org/api/1_4/sfDoctrineRoute /-г ашиглах нь Doctrine объект эсвэл Doctrine объектын цуглуулгыг төлөөлж сайжруулагдсан класс учираас илүү дээр: job_show_user: url: /job/:company/:location/:id/:position class: sfDoctrineRoute options: { model: JobeetJob, type: object } param: { module: job, action: show } requirements: id: \d+ sf_method: [get] options оролт нь route-ын төлөвыг өөрийн хүссэнээр болгодог. modelсонголт нь route –тэй холбоотой Doctrine model класс (JobeetJob)–ыг тодорхойлдог, мөн type нь энэ route нэг объект-г илэрхийлж байна (та мөн цуглуулга объектыг төлөөлөх routelist–ыг ашиглах боломжтой).

Одоо job_show_user route JobeetJob-той холбоотойгоо мэдэх бөгөөд бид url_for() дуудалтыг хялбаруулж дуудна: url_for(array(‘sf_route’ => ‘job_show_user’, ‘sf_subject’ => $job)) эсвэл: url_for(‘job_show_user’, $job) Эхний жишээ нь та ганц оъектоос илүүтэйгээр олон аргумент дамжуулах үед илүү хэрэгцээтэй байдаг. Дээрх route дэхь бүх хувьсагч JobeetJob класс дахь тухайн хамаарахaccessor-уудтай учираас хэвийн ажиллана (тухайлбал, companyrouteхувьсагч getCompany() утгаар загварлагдана). Хэрэв та хөрвүүлэгдэх URL-ыг харвал, яг бидний хүссэн хэлбэрээр биш байгааг харна. http://jobeet.localhost/frontend_dev.php/job/Sensio+Labs/Paris%2C+France/1/ Web+Developer Бидэнд бүх ASCII бүх тэмдэгт бүрийг – ээр засах “slugify” багана хэрэгтэй. JobeetJob файлыг нээгээд класс-д дараах method-ыг нэм. // lib/model/doctrine/JobeetJob.class.php public function getCompanySlug() { return Jobeet::slugify($this->getCompany()); } public function getPositionSlug() { return Jobeet::slugify($this->getPosition()); } public function getLocationSlug() { return Jobeet::slugify($this->getLocation()); } Тэгээд, lib/Jobeet.class.phpфайлыг үүсгээддотор нь slugify method-г нэм. // lib/Jobeet.class.php class Jobeet { static public function slugify($text) { // replace all non letters or digits by - $text = preg_replace(‘/\W+/’, ‘-’, $text); // trim and lowercase $text = strtolower(trim($text, ‘-’)); return $text; } }

Энэ хичээлийн турш бид <?php гэсэн нээлтийн мөрийг кодын жишээ-нд үзүүлээгүй ба зөвхөн цэвэр PHP код болон хоорондын зай, мөн догол мөрүүдийг үзүүлсэн. Та шинэ PHP файл үүсгэх болгондоо үүнийг санан нэмж өгөх хэрэгтэй. Харин template файлуудад бол хэрэггүй гэдгийг санах хэрэгтэй. Бид getCompanySlug(), getPositionSlug(),getLocationSlug() гэх гурван “virtual” accessor-уудыг тодорхойллоо. Эдгээрүүд одооslugify()method (функц) -ыг дуудсаны дараа хамаатай баганын утгыг буцаана. Одоо, та job_show_user route дахь жинхэнэ баганын нэрүүдийг дээрх “virtual” – утгуудаар солих боломжтой: job_show_user: url: /job/:company_slug/:location_slug/:id/:position_slug class: sfDoctrineRoute options: { model: JobeetJob, type: object } param: { module: job, action: show } requirements: id: \d+ sf_method: [get] Одоо та хүссэж байсан URL-тай боллоо. http://jobeet.localhost/frontend_dev.php/job/sensio-labs/paris-france/1/web-developer Гэвч энэ нь түүхийн зөвхөн тал нь. Route объект дээр тулгуурлан URL-ыг боловсруулж чадна, харин өгөгдсөн URL-ын дагуу мөн объектыг олж бас чадна. Хамаарах объект нь route объектын getObject()method-оор дуудагдаж болдог. Ирэх хүсэлтийг хөрвүүлвэл action-д ашиглагдах route-д тохирох обектыг өөртөө агуулсан байдаг. Тиймээс, executeShow()method-ыгөөрчилж Jobeet объектыг дуудах route объектыг ашиглая. class jobActions extends sfActions { public function executeShow(sfWebRequest $request) { $this->job = $this->getRoute()->getObject(); $this->forward404Unless($this->job); } // … } Хэрэв та мэдэхгүй id-гаар job-г дуудахыг оролдвол 404 алдааны хуудсыг харна. Харин алдааны мэдээлэл нь өөрчлөгдсөн байна.

Энэ нь getRoute()method-ээс тань руу автоматаар 404 алдааг шидэж байгаа учираас тэр юм. Тиймээс бид executeShowmethod-ыг бүр хялбаршуулж болно. class jobActions extends sfActions { public function executeShow(sfWebRequest $request)

{ $this->job = $this->getRoute()->getObject(); } // … } Хэрэв та route 404 алдааг харуулахыг хүсэхгүй бол routingoption-д allow_empty –г тодорхойлж өгөх боломжтой. Route-тэй хамааралтай объект нь удаан дуудагддаг. Хэрэв таgetRoute() method –ыг дуудсан бол энэ зөвхөн өгөгдлийн баазаас утгыг дууддаг. Action болон template дэхь routing Template-д url_for() helper дотоод URI –г гадаад URL рүү хөрвүүлдэг. Бусад зарим symfony helper мөн дотоод URI-ыг аргументаараа авдаг жишээ нь a tag-ыг боловсруулдагlink_to()helper : <?php echo link_to($job->getPosition(), ‘job_show_user’, $job) ?> Энэ нь дараах HTML кодыг боловсруулдаг: <a href=”/job/sensio-labs/paris-france/1/web-developer”>Web Developer</a> url_for() болонlink_to()хоёул бүрэн URL-ыг боловсруулах боломжтой. url_for(‘job_show_user’, $job, true); link_to($job->getPosition(), ‘job_show_user’, $job, true); Хэрэв та action-аас URL-ыг боловсруулахыг хүсвэл generateUrl()method-ыг ашиглах боломжтой. $this->redirect(‘job_show_user’, $job); “redirect” method-ын төрөл зүйл Өчигдрийн хичэлээр бид “forward” method-ын тухай ярьцгаасан. Тэдгээрmethod-ууд нь тухайн хүсэлтийг браузераар тойрч аялалгүйгээр өөр actionруу forward хийдэг. “redirect” method-ууд хэрэглэгчийг өөр URL рүү redirect(чиглүүлдэг) хийдэг. Яг forward шиг, та мөн redirect()эсвэл redirectIf()болон redirectUnless() shortcut method-уудыг ашиглах боломжтой. Collection Route Class Job модулын хувьд бид show action-ын route-г өөрийн болгож өөрчилсөн, гэвч бусад method-уудын URL –ууд default (index, new,edit, create, update, delete)route-ээрээ байгаа: default: url: /:module/:action/* default route бол дөнгөж эхлэн код бичиж байгаа хүмүүст хэтэрхий ихroute бичихгүйгээр ашиглах хамгийн сайн арга. Гэвч route “catch-all”(бусдаасаа ялгагдах) –аар байх үед тусгай тохиргоо тохиргоо хийлгээгүйгээр ашиглагдах боломжтой байдаг. Бүх jobaction-ууд JobeetJobmodel класс-тай холбоотой бол бидsfDoctrineRoute route-г show action-д тодорхойлсон шиг нэг бүрт нь хялбараар тодорхойлж өгч болно. Харин job модуль model –д боломжтой классик 7 action-уудыг тодохойлох бол, бид

мөнsfDoctrineRouteCollection / http://www.symfony-project.org/api/1_4/sfDoctrineRouteCollection / классыг ашиглаж болно. routing.yml файлыг нээгээд доорх шиг болгон өөрчил. # apps/frontend/config/routing.yml job: class: sfDoctrineRouteCollection options: { model: JobeetJob } job_show_user: url: /job/:company_slug/:location_slug/:id/:position_slug class: sfDoctrineRoute options: { model: JobeetJob, type: object } param: { module: job, action: show } requirements: id: \d+ sf_method: [get] # default rules homepage: url: / param: { module: job, action: index } default_index: url: /:module param: { action: index } default: url: /:module/:action/* дээрх jobroute бол дараах sfDoctrineRoute 7 route-үүдыг боловсруулах кодын shortcut нь: job: url: /job.:sf_format class: sfDoctrineRoute options: { model: JobeetJob, type: list } param: { module: job, action: index, sf_format: html } requirements: { sf_method: get } job_new: url: /job/new.:sf_format class: sfDoctrineRoute options: { model: JobeetJob, type: object } param: { module: job, action: new, sf_format: html } requirements: { sf_method: get } job_create: url: /job.:sf_format class: sfDoctrineRoute

options: { model: JobeetJob, type: object } param: { module: job, action: create, sf_format: html } requirements: { sf_method: post } job_edit: url: /job/:id/edit.:sf_format class: sfDoctrineRoute options: { model: JobeetJob, type: object } param: { module: job, action: edit, sf_format: html } requirements: { sf_method: get } job_update: url: /job/:id.:sf_format class: sfDoctrineRoute options: { model: JobeetJob, type: object } param: { module: job, action: update, sf_format: html } requirements: { sf_method: put } job_delete: url: /job/:id.:sf_format class: sfDoctrineRoute options: { model: JobeetJob, type: object } param: { module: job, action: delete, sf_format: html } requirements: { sf_method: delete } job_show: url: /job/:id.:sf_format class: sfDoctrineRoute options: { model: JobeetJob, type: object } param: { module: job, action: show, sf_format: html } requirements: { sf_method: get } sfDoctrineRouteCollection –аар боловсруулагдах зарим route нь ижил URLбайдаг. Route бүр өөр өөр HTTP аргуудын шаардлагуудтай болохоор тэдгээрийг ашиглах бүрэн боломжтой. job_delete баjob_updateroute-үүд браузер дэмждэггүй HTTPаргачлалыг(DELETE ба PUT). шаарддаг. Symfony тэдгээрийг ялгадаг учираас хэвийн ажиллана. _form.php template –ыг нээ жишээ харж болно: // apps/frontend/modules/job/templates/_form.php <form action=”…” …> <?php if (!$form->getObject()->isNew()): ?> <input type=”hidden” name=”sf_method” value=”PUT” /> <?php endif; ?> <?php echo link_to( ‘Delete’, ‘job/delete?id=’.$form->getObject()->getId(),

array(‘method’ => ‘delete’, ‘confirm’ => ‘Are you sure?’) ) ?> Бүх symfony helper-үүд таны хүссэн HTTP аргыг тусгайsf_methodпараметрыг дамжуулснаар ялган таньдаг. Symfony sf_ гэсэн угтвараар эхэлсэн өөр онцгой параметрүүдтэй тухайлбал sf_method. Дээрх route-үүдээс та өөрsf_format-ыг харж болно. Ирэх өдрүүдэд үүнийг тайлбарлана. Route Debugging Та route-үүдийн цуглуулгыг хэрэглэж байгаа бол заримдаа route-үүдийн жагсаалтыг боловсруулах нь илүү хэрэгцээтэй байдаг. app:routes команд нь өгөгдсөн application-ны бүхroute-үүдийг гаргадаг: $ php symfony app:routes frontend Та мөн route-ын нэрийг нэмэлт аргументаар өгснөөр тухайн route-ын алдааны хэрэгцээт мэдээллийг мөн авах боломжтой. $ php symfony app:routes frontend job_edit Default Routes Бүх URL бүр route тодорхойлж өгөх нь сайн. Jobeetapplication-д тодорхойлогдох бүх шаардлагатай route-үүд jobroute-д тодорхойлогдож байгаа учираас routing.yml тохиргооны файлаас defaultroute-үүдыг устгах юмуу санамж болго. # apps/frontend/config/routing.yml #default_index: # url: /:module # param: { action: index } # #default: # url: /:module/:action/* Jobeet application урьдых шиг хэвийн ажиллах ёстой. Маргааш болтол баяртай Өнөөдөрт маш олон шинэ мэдээлэл багтлаа. Та symfony –ынrouting framework-ыг хэрхэн яаж ашиглах талаар мөн хэрхэн тусгайлсан зориулалтаар өөрийн URL-г ашиглах талаар сурлаа. Маргааш бид шинэ ойлголттой танилцахгүй ба харин илүүтэйгээр өдий хүртэл юу мэдэж авсан талаараа гүнзгий судлахад илүү цаг зарцуулна.

6 дахь өдөр More with the Model

More with the Model

Өчигдөр гайхалтай байсан. URL-ийг яаж цэвэрхэн болгох болон symphony framework-ийн автоматар үүсгэдэг олон зүйлийн талаар үзсэн. Өнөөдөр бид Jobeet вэбсайтаа кодоор өөрчлөх тухай үзнэ. Үүний тулд эхний 5 өдөр тайлбарласан дадлагын ажлуудтай үзэж танилцсан байх шаардлагатай.

The Doctrine Query Object

Хоёрдахь өдрийн хичээлээс үзсэн байх шаардлагатай зүйлс: “Jobeet вэбсайт нэвтэрсэн хэрэглэгчид идэвхитэй ажлын байрны жагсаалтыг харуулна”. Гэвч одоо идэвхитэй идэвхигүй бүх ажлын байрны жагсаалтыг харуулж байна. // apps/frontend/modules/job/actions/actions.class.php class jobActions extends sfActions { public function executeIndex(sfWebRequest $request) { $this->jobeet_jobs = Doctrine::getTable(‘JobeetJob’) ->createQuery(‘a’) ->execute(); } // … } $q = Doctrine_Query::create() ->from(‘JobeetJob j’) ->where(‘j.created_at > ?’, date(‘Y-m-d H:i:s’, time() – 86400 * 30)); $this->jobeet_jobs = $q->execute(); }

Хэдийгээр та SQL илэрхийлэл гараар бичээгүй боловч Doctrine нь Database engine болон SQL илэрхийллийн тохиргоог ялган хэрэгжүүлж байгааг 3 дахь өдөр үзсэн. Гэвч зарим тохиолдолд SQL-ийг Doctrine-аар үүсгэх нь илүү дээр байдаг.

Debugging Doctrine generated SQL

Жишээлбэл: query хүлээгдэж буй үед debug нь ажиллахгүй хүлээдэг. Dev орчинд symphony-ийн эдгээр query-нүүд log/ хавтсанд байрладаг.Энд frontend_dev.log нэртэй ганц лог файл бүх програм (application) болон орчин (environment)-ийн боловсруулалтыг зохицуулж байдаг. # log/frontend_dev.log Dec 04 13:58:33 symfony [info] {sfDoctrineLogger} executeQuery : SELECT j.id AS j__id, j.category_id AS j__category_id, j.type AS j__type, j.company AS j__company, j.logo AS j__logo, j.url AS j__url, j.position AS j__position, j.location AS j__location, j.description AS j__description, j.how_to_apply AS j__how_to_apply, j.token AS j__token, j.is_public AS j__is_public, j.is_activated AS j__is_activated, j.email AS j__email, j.expires_at AS j__expires_at, j.created_at AS j__created_at, j.updated_at AS j__updated_at FROM jobeet_job j WHERE j.created_at > ? (2008-11-08 01:13:35 Doctrine-д created_at багана байсныг анзаарсан байх (WHERE j.created_at > ?).

Query-д орсон ? тэмдэгт мөр нь Doctrine-д илэрхийлэл үүсгэхэд тусладаг. Яг үнэндээ ?-ын утга нь (‘2008-11-08 01:13:35’ гэсэн жишээнд) query гүйцэтгэл болон database engine-ийг ажиллуулна. Бэлтгэсэн илэрхийллийг хэрэглэснээр SQL injection1 дайралтаас хамгаална. Энэ сайн боловч хэрэглэгч браузер солиход бага зэрэг асуудал тулгардаг. IDE-д log файл нь чамд тестийг өөрчлөхөд байнга шаардагдана. Symfony-ийн web debug toolbar нь хэрэгцээт, боломжит бүх зүйлийг браузерт нь гаргана.

Object Serialization

Хэдийгээр дан кодоор (автоматаар үүсгэлгүй) ажиллуулж болох боловч энэ нь 2 дахь өдөр тодорхойлсон эрхийн зарим асуудал дээр бүрэн болж чадахгүй. “Хэрэглэгч эрхээ дахин сэргээх болон оруулсан ажлын байрны мэдээллээ 30 хоног сунгах боломжтой…” Гэвч үүнийг created_at –ын утга мэдээлэл оруулсан өдрийг агуулж байгаа тул найдаж болох ба бид өөрийн санаанд нийцүүлэн өөрчлөх боломжгүй. Хэрэв та бидний 3 дахь өдөр тодорхойлсон database schema-г санаж байгаа бол бид expires_at багана тодорхойлсон. Одоогоор түүний утга байнга хоосон байгаа ба утгыг ашиглахгүй байна. Гэвч ажлын байр үүсгэхэд энэ нь автоматаар үүсгэснээс хойш 30 дахь өдрийг авна. Та өгөгдлийг Doctrine-ны тусламжтайгаар автоматаар үүсгэсэн байсан бол save()-аар өгөгдлийг шинэчилж болно

// lib/model/doctrine/JobeetJob.class.php class JobeetJob extends BaseJobeetJob { public function save(Doctrine_Connection $conn = null) { if ($this->isNew() && !$this->getExpiresAt()) { $now = $this->getCreatedAt() ? $this->getDateTimeObject(‘created_at’)->format(‘U’) : time(); $this->setExpiresAt(date(‘Y-m-d H:i:s’, $now + 86400 * 30)); } return parent::save($conn); } // … 1 http://en.wikipedia.org/wiki/Sql_injection

} isNew() method нь объект тодорхойлогдоогүй үед true (үнэн) утга буцаах ба бусад үед false (худал) утга буцаана. Одоо created_at-ийн утгыг expires_at-ийн утгаар сольж ашиглая. public function executeIndex(sfWebRequest $request) { $q = Doctrine_Query::create() ->from(‘JobeetJob j’) ->where(‘j.expires_at > ?’, date(‘Y-m-d H:i:s’, time())); $this->jobeet_jobs = $q->execute(); } Бид query-ийг ажил сонгохоор хязгаарлан expires_at-ийг огноонд ашиглав. More with Fixtures Jobeet үндсэн хуудсыг вэб хөтлөгч өгөгдлийн санд өөрчлөлт хийж чадахгүй бөгөөд зөвхөн өгөгдлийн сан дахь өгөгдлүүдийг л нийтэлнэ. Дараахи кодоор хугацаа дууссан ажлын байрны мэдээллүүдийг сольё. # data/fixtures/jobs.yml JobeetJob: # other jobs expired_job: JobeetCategory: programming company: Sensio Labs position: Web Developer location: Paris, France description: Lorem ipsum dolor sit amet, consectetur adipisicing elit.

how_to_apply: Send your resume to lorem.ipsum [at] dolor.sit is_public: true is_activated: true created_at: ’2005-12-01 00:00:00′ token: job_expired email: [email protected] Кодыг хуулахдаа догол мөрүүдийг алдалгүй (зөвхөн хоосон зай дэмжих ба кодын мөрийн эх, мөрийн эхнээс авсан зайг алдалгүй) болгоомжтой хуулаарай. Үүнээс өмнө expired_job мөр нь зөвхөн хоёр хоосон зай л авсан байна. Fixture файлын мэдээллийг засварлаж, зөв тодорхойлбол created_at-ын утгыг Doctrine автоматаар дүүргэнэ. Бидний тодорхойлсон нь анхдагч default утга. Fixture-ыг дахин уншиж, вэб браузерийг дахин ачаалснаар (refresh) хуучин ажлын байрны мэдээллүүдийг харахгүйг баталгаажуулна. $ php symfony doctrine:data-load Доорхи query нь created_at-д байгаа save() method-ор expires_at баганыг автоматаар дүүргэнэ. SELECT `position`, `created_at`, `expires_at` FROM `jobeet_job`; Custom Configuration JobeetJob::save() method-д ажлын байрны мэдээллийн хаагдах өдөр нь хатуу зоогдож өгсөн байдаг. Үүнээс гадна 30 хоног сунгах боломжтой байна. Symfony framework нь програмд зориулан тодорхойлсон app.yml тохиргооны файлтай байна. Үүний тусламжтайгаар хүссэн тохиргоонуудаа зааж өгөх боломжтой. # apps/frontend/config/app.yml all: active_days: 30 Програмд энэ тохиргоонууд нь sfConfig классаар гүйцэтгэгддэг. sfConfig::get(‘app_active_days’) sfConfig класс нь бидний хойно үзэх symphony-ийн тохиргооны хандах эрхийг агуулдаг тул тохиргоо нь app_ гэж эхэлсэн байдаг. Дараахи кодоор save() функцыг шинэчилье. public function save(Doctrine_Connection $conn = null) { if ($this->isNew() && !$this->getExpiresAt()) { $now = $this->getCreatedAt() ? $this->getDateTimeObject(‘created_at’)->format(‘U’) : time(); $this->setExpiresAt(date(‘Y-m-d H:i:s’, $now + 86400 * sfConfig::get(‘app_active_days’))); } return parent::save($conn); }

app.yml тохиргооны файл нь таны програмын global settings|Global Settings буюу тохиргоог төвлөрүүлэх шилдэг арга. Эцэст нь хэлэхэд төслийн турш хэрэглэх тохиргоонууд хэрэгтэй бол app.yml файлын symphony project-ийн config хавтсанд үүсгэх хэрэгтэй. Refactoring

Action код нь энэ шинэ method-оор зөвхөн идэвхитэй ажлын байрны жагсаалтыг харуулна. public function executeIndex(sfWebRequest $request) { $this->jobeet_jobs = Doctrine_Core::getTable(‘JobeetJob’)->getActiveJobs(); } Энэ refactoring нь өмнөх кодуудаас хэд хэдэн илүү үр дүнг өгнө. • Идэвхитэй ажлын байрны мэдээлэл нь Model logic-оор бүрэн дүрслэгдсэн • Controller дахь кодууд нь уншигдахуйц, уншиж ойлгоход хялбар байна. • getActiveJobs() method нь дахин ашиглагдахуйц (Өөр action-үүдэд) • model code-ийг тестлэж болохуйц болсон Ажлын байрны мэдээллийг expires_at баганаар эрэмбэлье: public function getActiveJobs() { $q = $this->createQuery(‘j’) ->where(‘j.expires_at > ?’, date(‘Y-m-d H:i:s’, time())) ->orderBy(‘j.expires_at DESC’); return $q->execute();

Хэдийгээр бидний бичсэн код сайн ажиллаж байгаа боловч энэ нь хараахан хангалтта биш. Та асуудлыг шийдвэрлэхэд бэлэн үү? Doctrine_Query код нь action (Controller layer)-д хамаарахгүй Model layer-т хамаарна. MVC моделийн хувьд Model нь бүх бизнес логикийг тодорхойлдог ба Controller нь зөвхөн Model-ийг дуудаж түүний өгөгдлийг авна. Кодын хувьд ажлын байрны цуглуулга буцаах ба JobeetJobTable класст getActiveJobs() method үүсгэе. // lib/model/doctrine/JobeetJobTable.class.php class JobeetJobTable extends Doctrine_Table { public function getActiveJobs() { $q = $this->createQuery(‘j’) ->where(‘j.expires_at > ?’, date(‘Y-m-d H:i:s’, time())); return $q->execute(); } }

} The orderBy methods нь ORDER BY–ийг SQL-д үүсгэдэг (addOrderBy()-ийг мөн адил үүсгэнэ).

Categories on the Homepage 2 дахь өдөр үзсэн зүйлсээс: “Ажлын байрны мэдээлэл нь Категори болон нийтлэгдсэн огноогоороо(шинэ нь эхэндээ) эрэмбэлэгдэнэ”. Одоог хүртэл ажлын байрны категорийг тодорхойлж өгөөгүй. Дээрхи шаардлагаар ажлын байр нь категориор эрэмбэлэгдэн харагдах хэрэгтэй. Эхлээд бүх категорид ядаж нэг нэг идэвхитэй ажлын байрны мэдээлэл оруулъя. JobeetCategoryTable классыг нээж getWithJobs() method-ийг нэмье. // lib/model/doctrine/JobeetCategoryTable.class.php class JobeetCategoryTable extends Doctrine_Table { public function getWithJobs() { $q = $this->createQuery(‘c’) ->leftJoin(‘c.JobeetJobs j’) ->where(‘j.expires_at > ?’, date(‘Y-m-d H:i:s’, time())); return $q->execute(); } } Index action-ийг дээрхи кодоос үүдэн өөрчилье. // apps/frontend/modules/job/actions/actions.class.php public function executeIndex(sfWebRequest $request) { $this->categories = Doctrine_Core::getTable(‘JobeetCategory’)->getWithJobs(); } Бүх идэвхитэй ажлыг дэлгэцэнд харуулахын тулд template-д өөрчлөлт оруулна: // apps/frontend/modules/job/templates/indexSuccess.php <?php use_stylesheet(‘jobs.css’) ?> <div id=”jobs”> <?php foreach ($categories as $category): ?> <div> <div> <div> <a href=”">Feed</a> </div> <h1><?php echo $category ?></h1>

</div> <table> <?php foreach ($category->getActiveJobs() as $i => $job): ?> <tr> <td> <?php echo $job->getLocation() ?> </td> <td> <?php echo link_to($job->getPosition(), ‘job_show_user’,$job) ?> </td> <td> <?php echo $job->getCompany() ?> </td> </tr> <?php endforeach; ?> </table> </div> <?php endforeach; ?> </div> Категорийн нэрийг template-д харуулахын тулд echo $category-ийг ашиглав. Энэ сонин сонсогдож байна уу? $category объектоор echo яаж категорийн нэрийг харуулж байна вэ? Хариулт нь 3 дахь өдөр тодорхойлсон бүх model класст зориулсан __toString() method. Үүний тулд getActiveJob() method-ийг jobeetCategory класст нэмнэ. // lib/model/doctrine/JobeetCategory.class.php public function getActiveJobs() { $q = Doctrine_Query::create() ->from(‘JobeetJob j’) ->where(‘j.category_id = ?’, $this->getId()); return Doctrine_Core::getTable(‘JobeetJob’)->getActiveJobs($q); } JobeetCategory::getActiveJobs() method нь Doctrine_Core::getTable(‘JobeetJob’)-> getActiveJobs() method-ийг идэвхитэй ажлын байранд категори нэмэхэд ашиглана. Doctrine_Core::getTable(‘JobeetJob’)->getActiveJobs()-ийг дуудсанаар категориор тодорхойлогдсон элдэв хязгаарлалтуудыг хийх боломжтой болно. Бид категори объект дамжуулахын оронд Doctrine_Query объект ашигласан нь энэ нөхцлийг бүрдүүлж өгсөн. getActiveJob()-д энэ Doctrine_Query объектыг query-ийнх нь хамт нэгтгэнэ. Doctrine_Query нь объект тул энэ нь амархан. // lib/model/doctrine/JobeetJobTable.class.php

public function getActiveJobs(Doctrine_Query $q = null) { if (is_null($q)) { $q = Doctrine_Query::create() ->from(‘JobeetJob j’); } $q->andWhere(‘j.expires_at > ?’, date(‘Y-m-d H:i:s’, time())) ->addOrderBy(‘j.expires_at DESC’); return $q->execute(); } Limit the Results “Категори бүрийн эхний 10 ажлын байрны жагсаалтыг харуулах ба категорийн бүх ажлын байрны жагсаалтын харуулах холбоостой байна.” Үүнийг getActiveJobs() method-оор хялбархан шийдэж болно: // lib/model/doctrine/JobeetCategory.class.php public function getActiveJobs($max = 10) { $q = Doctrine_Query::create() ->from(‘JobeetJob j’) ->where(‘j.category_id = ?’, $this->getId()) ->limit($max); return Doctrine_Core::getTable(‘JobeetJob’)->getActiveJobs($q); } Тохирох LIMIT нөхцөл нь Model-д засах боломжгүй (hard-coded) байдаг боловч түүний утгыг өөрчлөх боломжтой байдаг. Нэг хуудсанд харагдах ажлын байрны жагсаалтыг app.yml файлд зааж өгч болно: <!– apps/frontend/modules/job/templates/indexSuccess.php –> <?php foreach ($category->getActiveJobs(sfConfig::get(‘app_max_jobs_on_homepage’)) as $i => $job): ?> app.yml-д үүнээс гадна шинэ тохиргоо нэмж болно: all: active_days: 30 max_jobs_on_homepage: 10

Dynamic Fixtures Та max_jobs_on_homepage тохиргоогүйгээр өөрчлөлтийг харж чадахгүй. Иймээс бид ажлын байрны жагсаалтад fixture нэмэх хэрэгтэй. Ингэхийн тулд та

COPY and PASTE маягаар үүнийг шийдэж болох боловч үүнээс хялбар арга байна. Fixture файлуудыг давхардуулан ашиглах нь муу. Symfony үүнийг шийдвэрлэсэн! Symfony-ийн YAML нь файлуудаас өмнө ачаалдаг ба PHP кодуудыг дэмждэг. jobs.yml fixture файлыг засварлаж дараахи кодуудыг төгсгөлд нь нэм: # Starts at the beginning of the line (no whitespace before) <?php for ($i = 100; $i <= 130; $i++): ?> job_<?php echo $i ?>: JobeetCategory: programming company: Company <?php echo $i.”\n” ?> position: Web Developer location: Paris, France description: Lorem ipsum dolor sit amet, consectetur adipisicing elit. how_to_apply: Send your resume to lorem.ipsum [at] company_<?php echo $i ?>.sit is_public: true is_activated: true token: job_<?php echo $i.”\n” ?> Practical symphony Day6. More with the Model [email protected] Хуудас 9 email: [email protected] <?php endfor ?> Анхааруулахад YAML parser нь тав гэх мэт догол мөрийг дэмждэггүй. Зөвхөн хоосон зай (white space)-г дэмжнэ. PHP кодыг YAML файлд бичихдээ: • <?php ?> statements үргэлж мөрийн эхэнд байх болон өгөгдлийг өргөтгөх. • Хэрэв <?php ?> statement мөрийн төгсгөлд байвал, (“\n”)-аар шинэ мөр гэж зааж өгөх хэрэгтэй. Та doctrine:data-load нь Programming категорийн 10 ажлын байрыг л үндсэн хуудсан харуулж байгааг үзэж болно. Доорхи зурганд нэг хуудсанд харуулах ажлын байрны жагсаалтыг 5-аар хязгаарласныг харж болно.

Secure the Job Page Ажлын байрын идэвхитэй хугацаа дууссанаар хандах URL-ыг яг мэдэж байсан ч хандах боломжгүй болдог. Идэвхигүй болсон (expired) ажлын байрны URL-ыг мэдэхийг оролдъё (Үндсэн id нь өгөгдлийн сангаас –SELECT id, token FROM jobeet_job WHERE expires_at<NOW()): /frontend_dev.php/job/sensio-labs/paris-france/ID/web-developer-expired Идэвхигүй ажлын жагсаалтыг харахаас өмнө бид хэрэглэгчид харагдах 404 хуудсыг (Page not found) харуулах ёстой. Гэвч үүнийг яаж автоматаар шийдвэрлэх

вэ? # apps/frontend/config/routing.yml job_show_user: url: /job/:company_slug/:location_slug/:id/:position_slug class: sfDoctrineRoute options: model: JobeetJob type: object method_for_query: retrieveActiveJob param: { module: job, action: show } requirements: id: \d+ sf_method: [GET] retrieveActiveJob() method нь Doctrine_Query объектыг хаяг(route)-аар үүсгэнэ. // lib/model/doctrine/JobeetJobTable.class.php class JobeetJobTable extends Doctrine_Table { public function retrieveActiveJob(Doctrine_Query $q) { $q->andWhere(‘a.expires_at > ?’, date(‘Y-m-d H:i:s’, time())); return $q->fetchOne(); } // … } Одоо хэрэв та идэвхигүй болсон ажлын жагсаалтыг харахаар оролдвол 404 хуудас (Page not found) гарах болно.

Link to the Category Page Гэвч хэсэг хүлээ. Бидний бэлтгэл ажил хараахан бэлэн болоогүй байна. Иймээс таньд илүү их чөлөөт цаг болон өөрийгөө хөгжүүлэх хангалттай мэдлэг хэрэгтэй! Энэ талын дадлага ажил хийцгээе. Маргааш өөрсний ажлыг эргэн шалгах болно. Final Thoughts Өөрийн локал Jobeet төсөл дээр ажиллалаа. Symfony-ийн онлайн API documentation2 болон үнэгүй бичиг баримтууд3 нь таньд тусална. Маргааш бид үүнийг хэрхэн хэрэгжүүлэх боломжийг судална.

Энэ бүлгийг орчуулсан: Ариунсүлд

7 дахь өдөр Playing with the Category Page

7Playing with the Category Page

SEP

Өчигдрийн хичээлээр та өөрийн Symfony-ийн мэдлэгээ Doctrine, fixtures, routing, debugging болон Custom configuration гэх мэтээр нэмсэн ба бяцхан дадлага ажлаар өнөөдрийн хичээлээ эхэлье.

Таныг Jobeet категори хуудсанд ажилласан ба өнөөдөр илүү чадавхижсан гэж найдаж байна.

Бэлэн үү? Боломжит хүгжүүлэлтүүдийн талаар ярилцъя.

The Category Route

Эхлээд категори хуудсанд зориулсан цомхон URL-ыг route-д нэмье. Routing файлын эхэнд дараахи кодыг нэмнэ:

# apps/frontend/config/routing.yml

category:

url: /category/:slug

class: sfDoctrineRoute

param: { module: category, action: show }

options: { model: JobeetCategory, type: object }

Хэдийгээр та шинэ онцлог нэвтрүүлж байгаа боловч URL болон холбоотой заагч (route)-ийн талаар сайн бодох хэрэгтэй бөгөөд анхдагч заагчийг устгах шаардлагатай.

Route нь холбоотой объект, параметрүүдийн дурын баганыг ашиглаж чадна. Үүнээс гадна холбоотой объект класст тодорхойлогсдон accessor-ийн утгыг агуулж байдаг. slug параметрт category хүснэгтийг зааж өгөх мөр байдаггүй тул бид JobeetCategory-

// lib/model/doctrine/JobeetCategory.class.php

д заагч хийх хийсвэр заагч (virtual accessor) нэмж өгье:

public function getSlug()

{

return Jobeet::slugify($this->getName());

}

The Category Link

Одооjob module-ийн indexSuccess.php

Бид зөвхөн холбогч нэмсэн. Энэ холбогч нь 10-аас дээш ажлын байрны мэдээлэлтэй категорийн хувьд нэг хуудсанд харуулах ажлын байрны тоонд хязгаарлалттгүй болох нь

template-т категори хуудастай холбоё:

<!– some HTML code –>

<h1>

<?php echo link_to($category, ‘category’, $category) ?>

</h1>

<!– some HTML code –>

</table>

<?php if (($count = $category->countActiveJobs() -

sfConfig::get(‘app_max_jobs_on_homepage’)) > 0): ?>

<div class=”more_jobs”>

and <?php echo link_to($count, ‘category’, $category) ?>

more…

</div>

<?php endif; ?>

</div>

<?php endforeach; ?>

</div>

харагдана. Иймээс JobeetCategory-дcountActiveJob() method нэмж өгснөөр асуудлыг шийдэж болно:

// lib/model/doctrine/JobeetCategory.class.php

public function countActiveJobs()

{

$q = Doctrine_Query::create()

->from(‘JobeetJob j’)

->where(‘j.category_id = ?’, $this->getId());

return Doctrine_Core::getTable(‘JobeetJob’)->countActiveJobs($q);

}

countActiveJobs() methot нь JobeetJobTable-д тодорхойлогдоогүй тулjobeetJobTable.php

{

файлд дараахи өөрчлөлт оруулъя:

// lib/model/doctrine/JobeetJobTable.class.php

class JobeetJobTable extends Doctrine_Table

{

public function retrieveActiveJob(Doctrine_Query $q)

{

return $this->addActiveJobsQuery($q)->fetchOne();

}

public function getActiveJobs(Doctrine_Query $q = null)

{

return $this->addActiveJobsQuery($q)->execute();

}

public function countActiveJobs(Doctrine_Query $q = null)

return $this->addActiveJobsQuery($q)->count();

}

public function addActiveJobsQuery(Doctrine_Query $q = null)

{

if (is_null($q))

{

$q = Doctrine_Query::create()

->from(‘JobeetJob j’);

}

$alias = $q->getRootAlias();

$q->andWhere($alias . ‘.expires_at > ?’, date(‘Y-m-d H:i:s’, time()))

->addOrderBy($alias . ‘.created_at DESC’);

return $q;

}

}

JobeetJobTable –ийн код шинэ addActiveJobsQuery()

method-ийг олон дахин дуудаж (Код дахин давтах нь буруу гэдэг боловч ) байгааг та анзаарсан байх.

Кодын багахан хэсгийг дахин хуулж ашиглах нь эхний ээлжинд амар байдаг. Гэвч хэрэв чи үүнийг өөрөөр шийдэхи йг хүсвэл дахин ачаалагдах бүхнийг shared function, method-уудад үүсгэх хэрэгтэй.

countActiveJobs() method-д execute() method-ийг ашиглаж үр дүнг тоолохын оронд count() method-

Бид маш олон файлд энгийн өөрчлөлтүүд хийсээр ирлээ. Гэвч код нэмэх бүртээ проаграмдаа зөв layer, дахин ашиглагдах (re-usable) код оруулахыг хичээж байлаа. Ингэсээр одоогийн кодонд хүрсэн билээ. Энэ бол symphony project-ийн ажиллах ерөн

ийг ашиглах нь хурдан байдаг.

хий зарчим. Доорхи дэлгэцний зураг дээр тавхан ажлын байрны жагсаалт байгаа нь хангалтгүй бөгөөд

бидэнд 10-аас олон ажлын байрны жагсаалт хэрэгтэй (max_jobs_on_homepage

Job Category Module Creation

тохиргооны хэрэгжилтийг харахын тулд).

Энэ командаар category module үүсгэнэ:

$ php symfony generate:module frontend category

Урьд нь module үүсгэхдээ doctrine:generate-module

хэрэглэсэн. Энэ нь сайн боловч кодын 90%-ийг автоматаар үүсгэхийг хүсээгүй. Бид энэ кодоор хоосон module үүсгэсэн.

Яагаад job module-д category action нэмээгүй вэ? Энэ боломжтой боловч category page нь категори төрлийнх ба ихэвчлэн үүнд зориулсан category module-аар үүсгэдэг.

Category page-д хандахад category route slug хувьсагчаар холбоотой категориудад хүсэлт явуулна. Гэвч slug нь өгөгдлийн санд хадгалагддаггүй тул категорийн нэрийг slug

Update the Database

-аар тодорхойлж чадахгүй.

Category хүснэгтэд slug багана нэмье:

Энд тодорхойлсон slug багана нь Doctrine-ны Sluggable гэдэг нэртэй төлвийг (behavior) ашигладаг. Иймээс JobeetCategory-ийн шаардлагатай төлвүүдийг enable болгоё:

# config/doctrine/schema.yml

JobeetCategory:

actAs:

Timestampable: ~

Sluggable:

fields: [name]

columns:

name:

type: string(255)

notnull: true

Одоо slug нь жинхэнэ багана болсон тул JobeetCategory-оос getSlug()

method-ийг устгана.

Slug баганы тохиргоо нь бичлэг оруулах бүрт автоматаар хадгалдаг бөгөөд талбарын нэрээр объект үүсгэдэг.

doctrine:build –all –and-load –аар өгөдлийн сангийн хүснэгтүүдийг шинэчилж бидний fixture-үүдийг бичнэ.

$ php symfony doctrine:build –all –and-load –no-confirmation

Бидэнд одоо executeShow()

method-ийг үүсгэх боломжтой боллоо. Category action файлыг дахин доорхи кодоор дарж засварлана уу:

// apps/frontend/modules/category/actions/actions.class.php

class categoryActions extends sfActions

{

public function executeShow(sfWebRequest $request)

{

$this->category = $this->getRoute()->getObject();

}

}

executeIndex() method-ийг устгасан тул түүний indexSuccess.phptemplate-ийг устгах шаардлагатай. Байрлал: (apps/frontend/modules/category/templates/indexSuccess.php).

Сүүлийн алхам бол showSuccess.php

<?php slot(‘title’, sprintf(‘Jobs in the %s category’,

template үүсгэх:

// apps/frontend/modules/category/templates/showSuccess.php

<?php use_stylesheet(‘jobs.css’) ?>

$category->getName())) ?>

<div>

<div class=”feed”>

<a href=”">Feed</a>

</div>

<h1><?php echo $category ?></h1>

</div>

<table>

<?php foreach ($category->getActiveJobs() as $i => $job): ?>

<tr class=”<?php echo fmod($i, 2) ? ‘even’ : ‘odd’ ?>”>

<td class=”location”>

<?php echo $job->getLocation() ?>

</td>

<td class=”position”>

<?php echo link_to($job->getPosition(), ‘job_show_user’, $job) ?>

</td>

<td class=”company”>

<?php echo $job->getCompany() ?>

</td>

</tr>

<?php endforeach; ?>

</table>

Partials

indexSuccess.php template файлд үүссэн ажлын байрны жагсаалтыг үүсгэхийн тулд <table> tag-ийг хуулж тавьсан билээ. Энэ нь муу тул шинэ арга судалъя. Template-ийн зарим хэсгийг дахин ашиглах хэрэгцээ гарахад partial үүсгэх хэрэгтэй. Partial нь template-ийн кодын хэсэг бөгөөд хэд хэдэн template-д дахин ашиглагдах боломжтой байдаг.Partial-ийг template-ээс ялгахын тулд доогуур зураас ( _ )-аар эхлүүлдэг.

_list.php файл үүсгэе:

// apps/frontend/modules/job/templates/_list.php

<table>

<?php foreach ($jobs as $i => $job): ?>

<tr class=”<?php echo fmod($i, 2) ? ‘even’ : ‘odd’ ?>”>

<td class=”location”>

<?php echo $job->getLocation() ?>

</td>

<td class=”position”>

<?php echo link_to($job->getPosition(), ‘job_show_user’, $job) ?>

</td>

<td class=”company”>

<?php echo $job->getCompany() ?>

</td>

</tr>

<?php endforeach; ?>

</table>

Partial-ийг include_partial() helper ашиглан дуудна.

<?php include_partial(‘job/list’, array(‘jobs’ => $jobs)) ?>

include_partial()

нь partial name (module name, /, болон _-аар эхлээгүй partial name (Жишээ: job/list )), partial-ийг ашиглах хувьсагчийн массивын нэр гэсэн аргументүүд авна.

Яагаад PHP-ийн include() method-ийг include_partial()helper-ийн оронд ашиглаж болдоггүй вэ? include_partial()helper нь cache support хийдэг үндсэн ялгаатай.

HTML код дахь <table> -ийг include_partial()-

List Pagination

аар даръя:

// in apps/frontend/modules/job/templates/indexSuccess.php

<?php include_partial(‘job/list’, array(‘jobs’ =>

$category->getActiveJobs(sfConfig::get(‘app_max_jobs_on_homepage’)))) ?>

// in apps/frontend/modules/category/templates/showSuccess.php

<?php include_partial(‘job/list’, array(‘jobs’ =>

$category->getActiveJobs())) ?>

2 дахь өдөр тодорхойлсноор:

“Хуудас бүрт 20 ажлын байр байхаар хуваая.”

Doctrine объектуудыг хуудаслахад symphony нь зориулсан класстай байдаг: sfDoctrinePager[1]. Category action-д showSuccess template-ийн job объектыг илгээхийн оронд pager-ийг дамжуулъя:

// apps/frontend/modules/category/actions/actions.class.php

public function executeShow(sfWebRequest $request)

{

$this->category = $this->getRoute()->getObject();

$this->pager = new sfDoctrinePager(

‘JobeetJob’,

sfConfig::get(‘app_max_jobs_on_category’)

);

$this->pager->setQuery($this->category->getActiveJobsQuery());

$this->pager->setPage($request->getParameter(‘page’, 1));

$this->pager->init();

}

sfRequest::getParameter() method нь 2 дахь аргументийн анхдагч утгыг авах ба action-ны хувьд хэрэв page request parameter үүсээгүй бол getParameter() нь 1 гэсэн утга буцаана.

sfDoctrinePager байгуулагч нь model класс болон нэг хуудсанд буцаах өгөгдлийн дээд хэмжээг авна. Сүүлд нь өөрийн тохиргооны файлыг зааж өгнө:

# apps/frontend/config/app.yml

all:

active_days: 30

max_jobs_on_homepage: 10

max_jobs_on_category: 20

sfDoctrinePager::setQuery() method нь Doctrine_Query объектыг өгөгдлийн сангаас select хийх үед ашиглана.

getActiveJobsQuery() method нэмэх:

// lib/model/doctrine/JobeetCategory.class.php

public function getActiveJobsQuery()

{

$q = Doctrine_Query::create()

->from(‘JobeetJob j’)

->where(‘j.category_id = ?’, $this->getId());

return Doctrine_Core::getTable(‘JobeetJob’)->addActiveJobsQuery($q);

}

Бид getActiveJobsQuery() method-ийг үүсгэснээрээ бусадJobeetCategory method-уудад үүнийг дахин ашиглах боломжтой болсон:

// lib/model/doctrine/JobeetCategory.class.php

public function getActiveJobs($max = 10)

{

$q = $this->getActiveJobsQuery()

->limit($max);

return $q->execute();

}

public function countActiveJobs()

{

return $this->getActiveJobsQuery()->count();

}

Эцэст нь template-ээ шинэчилье:

<!– apps/frontend/modules/category/templates/showSuccess.php –>

<?php use_stylesheet(‘jobs.css’) ?>

<?php slot(‘title’, sprintf(‘Jobs in the %s category’,$category->getName())) ?>

<div class=”category”>

<div class=”feed”>

<a href=”">Feed</a>

</div>

<h1><?php echo $category ?></h1>

</div>

<?php include_partial(‘job/list’, array(‘jobs’ => $pager->getResults())) ?>

<?php if ($pager->haveToPaginate()): ?>

<div>

<a href=”<?php echo url_for(‘category’, $category) ?>?page=1″>

<img src=”http://www.symfony-project.org/images/first.png”

alt=”First page” title=”First page” />

</a>

<a href=”<?php echo url_for(‘category’, $category) ?>?page=<?php echo $pager->getPreviousPage() ?>”>

<img src=”http://www.symfony-project.org/images/previous.png”

alt=”Previous page” title=”Previous page” />

</a>

<?php foreach ($pager->getLinks() as $page): ?>

<?php if ($page == $pager->getPage()): ?>

<?php echo $page ?>

<?php else: ?>

<a href=”<?php echo url_for(‘category’, $category) ?>?page=<?php echo $page ?>”><?php echo $page ?></a>

<?php endif; ?>

<?php endforeach; ?>

<a href=”<?php echo url_for(‘category’, $category) ?>?page=<?php echo $pager->getNextPage() ?>”>

<img src=”http://www.symfony-project.org/images/next.png” alt=”Next page” title=”Next page” />

</a>

<a href=”<?php echo url_for(‘category’, $category) ?>?page=<?php echo $pager->getLastPage() ?>”>

<img src=”http://www.symfony-project.org/images/last.png” alt=”Last page” title=”Last page” />

</a>

</div>

<?php endif; ?>

<div>

<strong><?php echo count($pager) ?></strong> jobs in this category

<?php if ($pager->haveToPaginate()): ?>

- page <strong><?php echo $pager->getPage() ?>/<?php echo

$pager->getLastPage() ?></strong>

<?php endif; ?>

</div>

Энэ кодын ихэнхи хэсэг нь бусад хуудсыг дуудах холбоосуудаас бүрдэнэ. Энд sfDoctrinePager method-ийг ашиглах жагсаалтуудыг харуулсан байна.

• getResults(): Идэвхитэй хуудасны Doctrine объектуудын утгууд (массив).

• getNbResults(): Олдсон нийт үр дүнгийн тоо.

• haveToPaginate(): Нэгээс олон хуудас байвал true (үнэн) буцаана.

• getLinks(): Дэлгэцэнд гарах хуудасны жагсаалтыг буцаана.

• getPage(): Одоогийн хуудасны дугаарыг харуулна.

• getPreviousPage(): Өмнөх хуудсыг дуудна.

• getNextPage(): Дараагийн хуудсыг дуудна.

• getLastPage(): Сүүлийн хуудсыг дуудна.

sfDoctrinePager нь мөн Iterator, Countable interface-үүдийг хэрэгжүүлдэг ба count() функцийг getNbResult() method-ийн оронд хэрэглэн ижил үр дүнг харж болно.

Final Thoughts

Хэрэв та 6 өдрийн хичээлээс хангалттай ихийг судлаагүй санагдаж байгаа бол энэ нь зөвхөн symfony-ийн философи-ийг ойлгоход чиглэгдсэн байлаа. Symfony вэбсайтад шинэ feature нэмэх нь үргэлж төстэй байдаг. Жишээ нь. URL-ууд, зарим нэг action үүсгэх, model шинэчилэх болон template бичих. Хэрэв та mix ашиглаж байсан дадлага туршлага сайтай бол symfony-д гаршихад маш хурдан байх болно.

Маргааш Jobeet-ийн шинэ долоо хоног эхэлнэ. Бид topic:automated tests-ийн талаар шинэ сэдэв үзнэ.

8 дахь өдөр хэсэг Эхний 5 өдрийн турш үзсэн Jobeet feature-үүдийг өөрчлөх (customize) болон шинийг үүсгэх хичээлүүдээ сүүлийн хоёр

өдрийн турш дахин үзэж дүгнэв.

Өнөөдөр бид өөр зүйл: авто тест (automated tests) үзнэ. Энэ сэдэв их том учир 2 өдрийн турш үзэх болно.

Tests in symfony

Symfoy-д хоёр төрлийн автомат тестийн арга байдаг: unit tests|Unit Testing болон functional tests.

Unit tests нь ажиллагаанд шаардлагатай method функц тус бүрийг шалгадаг (verify). Тест бүр нь бие даасан

бусдаасаа ангид байна.

Нөгөө талаас, функциональ тест нь програмын үр дүнг зөв байхыг шаарддаг.

Symfony-ийн тестүүд нь төслийн test/ хавтсанд хадгалагддаг бөгөөд дотроо unit test (test/unit/) болон functional test

(test/functional/) гэсэн 2 дэд хавтстай.

Өнөөдрийн хичээлээр unit test-ийн талаар үзэх ба маргаашийн хичээлээр functional test-ийн талаар үзнэ.

Unit Tests

Unit test-ийг бичих нь вэб хөгжүүлэлтийн хамгийн хүнд даалгаваруудын нэг юм. Вэб хөгжүүлэгчид тест

хэрэглэдэггүйгээс олон асуудал үүсдэг: Бид вэбийн бүтцийг (feature) тодорхойлохоосоо өмнө тест хийх ёстой юу?

Бид юуг нь тестлэх вэ? Бидний тест single edge case/Edge Case бүрт зориулагдсан байх ёстой юу? Бид яаж бүгдийг

нарийн сайн тестлэх вэ? Гэвч ихэвчлэн тулгардаг асуулт бол Хаанаас нь хэлэх вэ?

Хэдийгээр тестэд ихээр анхаарч байгаа ч symfony-ийн хандлага прагматик: Огт тест хийхгүй байснаас зарим нэг тест

хийх нь дээр. Та ихээхэн кодыг тестгүйгээр биччихсэн? Асуудалгүй. Танд бүрэн тестлэснээс ахисан төвшний тест нь

илүү үр ашигтай. Тестээ bug илрүүлэхээс эхэлье. Дээрхи хугацаанд таны код сайжран, code coverage-тэй болон тэр

нь хөгжсөн гэж найдаж байна. Таны кодонд энэ хугацаанд прагматик хандлагаар хэд хэдэн боломжит тест хийгдсэн.

Дараагийн алхам бол шинэ feature үүсгэхэд тест хийх. Таньд ойлгуулахад их хугацаа шаардлагагүй.

Ихэнхи тестийн сангууд програмын судалгааны хэсэгт байдаг нь асуудалтай. Тэгвэл Symfony яаж үүнийг хялбархан

шийдсэн бэ? Тестийг хялбархан хийх lime сантай.

Хэдийгээр энэ сурах бичиг нь lime-аар өргөтгөсөн тестийн санг ашиглаж байгаа боловч та хүсвэл PHPUnit сан гэх мэт

дурын тестийн санг ашиглаж болно.

The lime Testing Framework

Lime framework-оор бичигдсэн unit test-үүд нь ижилхэн кодоор эхэлдэг:

require_once dirname(__FILE__).’/../bootstrap/unit.php’;

$t = new lime_test(1);

Эхлээд unit.php файлын кодонд багахан зүйл нэмж өгье. Ингэснээр төлөвлөсөн тестийг тоог агуулсан lime_test

объект үүслээ.

Plan нь lime-ийг цөөхөн тестээр алдааны мэдээлэл харуулах боломжийг олгоно (Заавал PHP fatal error заалгаж байх

харахаас өмнө).

Тест нь method, функц дуудсанаар урьдчилан тодорхойлсон оролтуудын гаралтыг төлөвлөсөн үр дүнтэй жишнэ. Энэ

жишилт нь тестийн үр дүнг зөв эсэхийг тодорхойлно.

lime_test объектын хэд хэдэн method нь энэ ажиллагааг хөнгөвчилдөг:

Method тайлбар

ok($test) Хэрэв тест алдаагүй бол true.

is($value1, $value2) 2 аргумент тэнцүү(==) бол true.

isnt($value1, $value2) 2 аргумент тэнцүү биш бол true.

like($string, $regexp) Тэмдэгт мөр regular expression бол true.

unlike($string, $regexp) Тэмдэгт мөр regular expression биш бол true.

is_deeply($array1, $array2) 2 массив ижил утгатай бол true.

Магадгүй та lime-ийн ok() аргаар бүгдийг хийж болохоор байтал ийм олон тестийн аргууд байгааг хараад гайхаж

байгаа байх. Эдгээр нь тестийг элдвийн алдаагүй найдвартай байлгахын тулд ашиглагддаг.

Үүнээс гадна lime_test объект нь тохиромжтой тестийн аргуудыг ашигладаг:

Method тайлбар

fail() Always fails— Онцгой тестэд хэрэглэдэг

pass() Always passes— Онцгой тестэд хэрэглэдэг

skip($msg, $nb_test) Counts as $nb_tests tests— Нөхцөлт тестэд хэрэглэдэг

todo() Counts as a test— Бичигдээгүй кодонд хэрэглэдэг.

Эцэст нь хэлэхэд comment($msg) арга comment харуулах боловч тест хийдэггүй.

Running Unit Tests

Unit test-үүд нь test/unit/ хавтсанд хадгалагдана. Ер нь тестүүдийн нэр test гэж төгссөн байдаг. Гэвч та өөрийн

хүссэнээр test/unit/ хавтас дахь файлуудыг өөрчлөх боломжтой ба lib/ хавтас дахь хавтас, файлуудыг хувилж авахыг

зөвлөх байна.

Jobeet класс дээр жишээ болгон үзүүлье.

test/JobeetTest.php файл үүсгэж дараахи кодыг хуулъя:

// test/unit/JobeetTest.php

require_once dirname(__FILE__).’/../bootstrap/unit.php’;

$t = new lime_test(1);

$t->pass(’This test always passes.’);

Дараахи командаар тестийг ажиллуулна:

$ php test/unit/JobeetTest.php

Эсвэл test:unit хүсэлтээр:

$ php symfony test:unit Jobeet

Харамсалтай нь Windows-ийн command line (cmd) улаан, ногооноор highlight хийж чаддаггүй. Гэвч Cygwin

ашигласнаар symfony-ийн –color тохиргоог task-д ашиглах боломжтой болно.

Testing slugify

Jobeet::slugify() хэмээх гайхалтай аргачлалтай танилцъя:

Бид ~slug/Slug~ify() аргыг ашигласан бол 5 өдрийн турш URL гэх мэт тэмдэгт мөрүүдийг цэвэрлэж чадах байлаа. Энэ

хөрвүүлэлт нь non-ASCII –аас dash (-), эсвэл бүх тэмдэгтийг жижиг үсэг рүү хөрвүүлэх гэх мэт суурь

хөрвүүлэлтүүдтэй төстэй:

Оролт Гаралт

Sensio Labs sensio-labs

Paris, France paris-france

Тест файлыг доорхи кодоор өөрчил:

// test/unit/JobeetTest.php

require_once dirname(__FILE__).’/../bootstrap/unit.php’;

$t = new lime_test(6);

$t->is(Jobeet::slugify(’Sensio’), ’sensio’);

$t->is(Jobeet::slugify(’sensio labs’), ’sensio-labs’);

$t->is(Jobeet::slugify(’sensio labs’), ’sensio-labs’);

$t->is(Jobeet::slugify(’paris,france’), ‘paris-france’);

$t->is(Jobeet::slugify(’ sensio’), ’sensio’);

$t->is(Jobeet::slugify(’sensio ‘), ’sensio’);

Хэрэв та бидний бичсэн тестийг ойлгосон бол энэ бүх мөр нь зөвхөн ганц ижил утгатай болохыг харах болно. Энэ

тест нь unit test-ийн зарчмыг ойлгуулахыг зорьсон болно.

Одоо тест файлыг ажиллуулж сурлаа. Хэрэв бүх тест алдааны мэдээлэл өгөхгүй бол та “green bar” (ногоон мөр)

харуулах ба эсрэг тохиолдолд “red bar” (улаан мөр) харуулах ба үүнийг засах шаардлагатай.

Хэрэв тест алдаа заавал яагаад алдаа гарсан талаар алдааны мэдээлэл гарна. Гэвч хэрэв та олон арван тест

файлтай ажиллаж байвал энэ нилээн хүндэрнэ.

Lime test-үүд нь тэдний сүүлийн аргумент гэх мэт тэмдэгт мөр буцаадаг. Энэ нь таньд ямар хэсэгт тест явагдаж

байгааг нь мэдэхэд тусална. Үүнээс гадна хүлээгдэж буй behavior-ийг тодорхойлох документийн форм нь бас

тусална. Slygify тестийн файлд дараахи текстийг бичиж өгье.

require_once dirname(__FILE__).’/../bootstrap/unit.php’;

$t = new lime_test(6);

$t->comment(’::slugify()’);

$t->is(Jobeet::slugify(’Sensio’), ’sensio’,

‘::slugify() converts all characters to lower case’);

$t->is(Jobeet::slugify(’sensio labs’), ’sensio-labs’,

‘::slugify() replaces a white space by a -’);

$t->is(Jobeet::slugify(’sensio labs’), ’sensio-labs’,

‘::slugify() replaces several white spaces by a single -’);

$t->is(Jobeet::slugify(’ sensio’), ’sensio’,

‘::slugify() removes - at the beginning of a string’);

$t->is(Jobeet::slugify(’sensio ‘), ’sensio’,

‘::slugify() removes - at the end of a string’);

$t->is(Jobeet::slugify(’paris,france’), ‘paris-france’,

‘::slugify() replaces non-ASCII characters by a -’);

Тестийн тайлбарын бас нэгэн давуу тал нь тестийг ойлгоход хялбараар бичихэд туслана. Мөн тухайн тест юу

хийхийг тодорхойлсон байдаг.

Code coverage

Тест бичихдээ ямар нэгэн хэсгийг мартагдах нь тохиолддог.

Бүх кодыг сайн шалгахад тань туслахаар symfony нь test:coverage task-ийг гаргаж ирсэн. Энэ task нь таны төслийн

бүхий л фолдер, файл, аргументүүдийн тухай мэдээллийг харуулна:

$ php symfony test:coverage test/unit/JobeetTest.php lib/Jobeet.class.php

Тест аль мөрөнд ажиллаж байгааг мэдэхийг хүсвэл –detailed тохиргоогоор харж болно:

$ php symfony test:coverage –detailed test/unit/JobeetTest.php lib/Jobeet.class.php

Үүнийг ажиллуулснаар unit test бүрэн ажиллана гэдэгт итгэж болно.

test:coverage нь мэдээлэл цуглуулах XDebug-ийг ашиглах тул үүнийг суулгаж, идэвхижүүлсэн (enable) байх

шаардлагатай.

Adding Tests for new Features

slug нь хоосон тэмдэгт мөрөнд зориулсан тэмдэгт морь юм.Үүний ажиллагааг тестлэх боломжтой. Гэхдээ URL-д

хоосон тэмдэгт байх нь зохистой биш. Тиймээс slugify() method –д хоосон тэмдэгт мөр буцаахын оронд “n-a”

буцаахаар өөрчилье.

Тестийг ажиллуулчихаад method-уудыг өөрчлөх замаар тестийг сайжруулж болно. Ингэж бичих нь тестийг бүрэн

дүүрэн танин мэдэх тустай боловч анхнаас нь сайн төлөвлөж бичих хэрэгтэй.

$t->is(Jobeet::slugify(”), ‘n-a’, ‘::slugify() converts the empty string to n-a’);

Хөгжүүлэлтийн энэ аргачлалыг хэрэглэхээс өмнө Test Driven Development (TDD) зарчмыг судлах хэрэгтэй (TDD) .

Тестийг ажиллуулахад улаанаар тодотгосон мөр харагдана. Feature ажилласан болон таны тест бүрэн ажиллахгүй

байвал энэ төр гарахгүй.

Одоо Jobeet класст дараахи өөрчлөлт хийж хоосон тэмдэгт мөр буцаахгүй болгоё.

// lib/Jobeet.class.php

static public function slugify($text)

{

if (empty($text))

{

return ‘n-a’;

}

// …

}

Ногоон фоноор тестийн эерэг үр дүнг харуулах боловч үүнийг цаашид сайжруулах шаардлагатайг мартаж болохгүй.

Үгүй бол Долоо хэмжиж нэг огтлох “You planned six tests and ran one extra” хэрэгтэй. Тестийг төлөвлөгөөтэй

сайжруулснаар илүү сайн ойлгож төгөлдөржүүлэх боломжтой.

Adding Tests because of a Bug

Зарим job link-үүд нь 404 error page дууддаг сонирхолтой багг (weird bug) тохиолддог гэж ярьдаг: Үүнийг шалгахад

ихэнхдээ л company, position, location slug-ууд хоосон байснаас үүдсэн байдаг.

Яагаад ийм нөхцөл үүсдэг вэ?

Өгөгдлийн сан дахь бичлэгүүд нь хоосон биш байгааг харсан байх. Шалтгааны нь олохгүй таах биз. Тэмдэгт мөрүүд

нь non-ASCII (Unicode гэх мэт ASCII биш) фонт ашигласан үед slugify() method нь хоосон тэмдэгт буцаана. Иймээс

Jobeet классыг нээн үүнийг засах хэрэгтэй. Энэ нь болхи боловч эхлээд тест хийж үзье:

$t->is(Jobeet::slugify(’ - ‘), ‘n-a’,

‘::slugify() converts a string that only contains non-ASCII characters

to n-a’);

Тест ажиллахгүй алдаа заах ба Jobeet классыг засварлан хоосон мөр шалгахыг method-ийн төгсгөл рүү зөөвөл:

static public function slugify($text)

{

// …

if (empty($text))

{

return ‘n-a’;

}

return $text;

}

Одоо slugify() нь bug despite байгаагаас үл хамааран 100% ажиллана.

Тест нь хаана ажиллаж байгааг ойлгоход хүндрэлтэй боловч энэ нь зүгээр. Ямар нэгэн санаа олсон бол үүнийгээ

кодын түвшинд засахаас өмнө тестлэх хэрэгтэй. Ингэснээр код чинь алдаагүй сайн ажиллах болно.

Towards a better slugify Method

Symfony-ийг францчууд бичсэн тул тестэд франц үг хэллэг ашигласныг харах байх:

$t->is(Jobeet::slugify(’Développeur Web’), ‘developpeur-web’, ‘::slugify() removes accents’);

Ихэнхи алдаанууд e -ийн оронд é -г тавих гэх мэт алдаанууд байгаа тул үүнийг slugify() method-оор ( - ) тэмдэгтээр

даръя. Энэ алдааг transliteration буюу үсэг хөрвүүлэлт гэдэг. “iconv”-ийг суулгаснаар үүнийг хийх боломжтой болно.

slugify method-ийг дараахи хэлбэртэй болгоё:

// code derived from http://php.vrana.cz/vytvoreni-pratelskeho-url.php

static public function slugify($text)

{

// replace non letter or digits by -

$text = preg_replace(’#[^\\pL\d]+#u’, ‘-’, $text);

// trim

$text = trim($text, ‘-’);

// transliterate

if (function_exists(’iconv’))

{

$text = iconv(’utf-8′, ‘us-ascii//TRANSLIT’, $text);

}

// lowercase

$text = strtolower($text);

// remove unwanted characters

$text = preg_replace(’#[^-\w]+#’, ”, $text);

if (empty($text))

{

return ‘n-a’;

}

return $text;

}

PHP файлуудаа UTF-8 форматтай хадгалснаар symfony “iconv”-ийг ашиглан үсгийн хөрвүүлэлт хийх болно.

Мөн тестийг ажиллуулахдаа “iconv”-ээр ажиллуулах шаардлагатай:

if (function_exists(’iconv’))

{

$t->is(Jobeet::slugify(’Développeur Web’), ‘developpeur-web’,

‘::slugify() removes accents’);

}

else

{

$t->skip(’::slugify() removes accents - iconv not installed’);

}

Doctrine Unit Tests

Database Configuration

Doctrine model класст Unit test хийхэд өгөгдлийн сангийн холболтыг нэхдэг нь жаахан төвөгтэй болгодог. Урьд нь

хөгжүүлэлтийн үед зааж өгч байсан боловч энэ нь тестэд тусгайлан зориулсан бааз тодорхойлдог давуу талтай.

Энэ номын эхэнд application-ий хэд хэдэн орчинг танилцуулсан. Default (анхдагч)-аараа symfony-ийн бүх тестүүд test

орчинд ажилладаг ба энэ орчинд зориулсан өөр өгөгдлийн сан тохируулъя.

$ php symfony configure:database –name=doctrine

–class=sfDoctrineDatabase –env=test

“mysql:host=localhost;dbname=jobeet_test” root mYsEcret

env тохиргоогоор энэ өгөгдлийн санг зөвхөн test орчинд ашиглахыг зааж өгч байна. Бид энэ тохиргоог 3 дахь өдөр

ашигласан боловч env тохиргоог ашиглаагүй тул бүх орчинд ашиглагдахаар сантай болсон.

config/database.yml тохиргооны файлаас symfony тохиргооны орчнуудыг хэрхэн хялбархан өөрчилж байгааг харж

болно.

Өгөгдлийн санг нэгэнт тохируулсан болохоор нэмэлтгүйгээр doctrine:insert-sql task-ийн тусламжтайгаар ашиглах

боломжтой боллоо:

$ mysqladmin -uroot -pmYsEcret create jobeet_test

$ php symfony doctrine:insert-sql –env=test

Configuration Principles in symfony

4 дэх өдрийн хичээлээр тохиргооны файлуудад өөр түвшин тодорхойлохыг үзсэн билээ.

Эдгээрт орчинг давхар тодорхойлох боломжтой. Үүнийг бидний одоо хүртэл ашигласаар байгаа databases.yml,

app.yml, view.yml, болон settings.yml гэх мэт түгээмэл файлуудад ашигласаар байна. all үг нь бүх орчинд ажиллах

тохиргоог зааж байна:

# config/databases.yml

dev:

doctrine:

class: sfDoctrineDatabase

test:

doctrine:

class: sfDoctrineDatabase

param:

dsn: ‘mysql:host=localhost;dbname=jobeet_test’

all:

doctrine:

class: sfDoctrineDatabase

param:

dsn: ‘mysql:host=localhost;dbname=jobeet’

username: root

password: null

Test Data

Тестэд тусгайлан бэлдсэн өгөгдлийн сантай болсон тул бидэнд тестийн өгөгдөл хэрэгтэй. Гуравдахь өдөр бид

doctrine:data-load task-ийн тухай үзсэн бөгөөд үүнийг тестийн өгөгдлийг өгөгдлийг сан руу хийхэд ашиглая.

doctrine:data-load task нь өгөгдөл ачаалахдаа Doctrine_Core::loadData() method-ийг ашиглана:

Doctrine_Core::loadData(sfConfig::get(’sf_test_dir’).’/fixtures’);

sfConfig объект нь төслийн дэд фолдерүүдийн замыг бүрэн авдаг бөгөөд үүнийг анхдагч фолдерийн бүтцийг

өөрчлөхөд ашиглаж болно.

loadData() method нь анхдагч аргументдээ файл буюу фолдер авах ба үүндээ фолдер, файлын массив агуулж чадна.

Бид анхны зарим нэг өгөдлүүдийг data/fixtures/ хавтсанд үүсгэсэн. Үүнтэй адилаар тестийн fixture-уудыг test/fixtures/

хавтсанд хийе. Эдгээр fixture-үүд нь Doctrine-ийн unit болон functional тестэд ашиглагдана.

Эхний ээлжинд data/fixture/ хавтсанд байгаа файлуудыг test/fixtures/ хавтас руу хуулан ашиглая.

Testing JobeetJob

JobeetJob model class-ын зарим unit тестүүдийг үүсгэе.

Бидний жишээний хувьд Doctrine unit test-үүд нь бүгд ижил кодоор эхлэх тул bootsrap/ тест хавтсанд байрлах

Doctrine.php файл үүсгэе:

// test/bootstrap/Doctrine.php

include(dirname(__FILE__).’/unit.php’);

$configuration =

ProjectConfiguration::getApplicationConfiguration(

‘frontend’, ‘test’, true);

new sfDatabaseManager($configuration);

Doctrine_Core::loadData(sfConfig::get(’sf_test_dir’).’/fixtures’);

Энэ скрипт файл нь эмх цэгцтэй бичигдсэн байна:

• Front controllers-д test-ийн орчны объектыг зааж өглөө:

$configuration =

ProjectConfiguration::getApplicationConfiguration(

‘frontend’, ‘test’, true);

• Өгөгдлийн сангийн менежерийг үүсгэснээр Doctrine-ы холболтыг databases.yml тохиргооны файлд тодорхойлох

боломжтой болно.

new sfDatabaseManager($configuration);

• Тестийн өгөгдлүүдийг Doctrine_Core::loadData() ашиглан ачаална:

Doctrine_Core::loadData(sfConfig::get(’sf_test_dir’).’/fixtures’);

Doctrine-ы өгөгдлийн сангийн холболт нь хэдхэн SQL илэрхийллээр гүйцэтгэгэнэ.

Бүгдийг бэлдсэн тул JobeetJob классын тестийг эхлүүлье.

Эхлээд test/unit/model хавтсанд JobeetTest.php файл үүсгэе:

// test/unit/model/JobeetJobTest.php

include(dirname(__FILE__).’/../../bootstrap/Doctrine.php’);

$t = new lime_test(1);

getCompanySlug() method-ийг тест файлдаа нэмж өгье:

$t->comment(’->getCompanySlug()’);

$job = Doctrine_Core::getTable(’JobeetJob’)->createQuery()->fetchOne();

$t->is($job->getCompanySlug(), Jobeet::slugify($job->getCompany()),

‘->getCompanySlug() return the slug for the company’);

Зөвхөн тестэнд зориулагдсан getCompanySlug() method-ийг тодорхойлсноор slug-ийн алдаатай үгүйгээс үл

шалтгаалан бидний тест ажиллах боломжтой болно.

save() method-д тест бичих нь үл ялиг комплекс болдог:

$t->comment(’->save()’);

$job = create_job();

$job->save();

$expiresAt = date(’Y-m-d’, time() + 86400

* sfConfig::get(’app_active_days’));

$t->is($job->getDateTimeObject(’expires_at’)->format(’Y-m-d’), $expiresAt,

‘->save() updates expires_at if not set’);

$job = create_job(array(’expires_at’ => ‘2008-08-08′));

$job->save();

$t->is($job->getDateTimeObject(’expires_at’)->format(’Y-m-d’),

‘2008-08-08′, ‘->save() does not update expires_at if set’);

function create_job($defaults = array())

{

static $category = null;

if (is_null($category))

{

$category = Doctrine_Core::getTable(’JobeetCategory’)

->createQuery()

->limit(1)

->fetchOne();

}

$job = new JobeetJob();

$job->fromArray(array_merge(array(

‘category_id’ => $category->getId(),

‘company’ => ‘Sensio Labs’,

‘position’ => ‘Senior Tester’,

‘location’ => ‘Paris, France’,

‘description’ => ‘Testing is fun’,

‘how_to_apply’ => ‘Send e-Mail’,

‘email’ => ‘[email protected]’,

‘token’ => rand(1111, 9999),

‘is_activated’ => true,

), $defaults));

return $job;

}

Тестийг өргөтгөх бүртээ lime_test байгуулагч дахь дараагийн ажиллах тест (plan)-ийг мартаж болохгүй. JobeetJobTest

файлын хувьд 1-ийг 3 болгон өөрчлөх хэрэгтэй.

Test other Doctrine Classes

Инсгэснээр бүх Doctrine классуудыг тестлэх боломжтой болно. Одоо unit test-ийг хялбарханаар дуудан ашиглаж

болно.

Unit Tests Harness

test:unit task нь мөн төсөл (project) –ийн бүх unit test-ийг ажиллуулдаг:

$ php symfony test:unit

Task бүх алдаатай, алдаагүй файлууд харуулна.

Хэрэв test:unit task нь файлын “тодорхойгүй төлөв” буюу “dubious status” тохиолдвол скриптийг бүрэн ажиллуулалгүй

тасална. Тест файл нь зөвхөн алдааны мэдээллийг харуулна.

Final Thoughts

Тест нь application-ы хувьд нэн чухал боловч өнөөдрийн хичээлд зарим зүйл орхигдсон.

Мэдээж symfony нь фрэймворкуудын дундаа сайн боловч үүний чадварыг зөвхөн хөгжүүлэгчийн ухамсар болон сайн

дадлагын хүчээр л эзэмших боломжтой. Эдгээрийн нэг нь тест юм. Unit test-үүд таны хожмын ажлыг хөнгөвчилнө.

Энэ нь таны кодын найдвартай байдлыг бататгах бөгөөд үүнийг айх зүйлгүйгээр дураараа хөгжүүлэх боломжийг

олгоно. Unit test-үүд таныг ямар нэгэн зүйлийг алдахаас хамгаалн найдвартай мэдээлж байна. Symfony фрэймворк

нь өөртөө 9000 гаруй тесттэй.

Маргааш бид зарим job, category модулиудад зориулсан functional test (функциональ тест)-үүд бичнэ. Тэр болтол

Jobeet модель класст зориулсан unit тест-үүд бичээрэй.

10 дахь өдөр: Формууд

Өмнөх өдрийн хичээ лийг бид Symfony дахь сорилтын фреймворкуудтай танилцах алхмаас гялалзтал эхлүүлсэн. Өнөөдөр бид формын фреймворкуудтай танилцах болно.

Формын фреймворк Сайт бүр энгийн харилцааны формоос эхлэн олон тооны талбарууд бүхий нийлмэл түвэгтэй олон янзын формуудыг агуулсан байдаг. Форм бичнэ гэдэг нь формын HTML кодыг бичих, талбар нэг бүрийн утгыг шалгаж баталгаажуулах, өгөгдлийг боловсруулан баазад хадгалах, алдааны мэдээллүүдийг гаргах, түүнчлэн талбаруудыг дахин дахин бөглөж тэр бүрт формыг дуудах гээд вэб хөгжүүлэгчдийн хувьд өдөр тутам тохиолддог хялбар биш уйтгартай ажлуудын нэг билээ.

Дугуйг дахин дахин эргүүлэх нь мэдээж утгагүй хэрэг. Ийм учраас Symfony нь формын удирдлагыг хялбаршуулах зорилгоор тусгайлсан фреймворкийг бий болгосон байна. Формын фреймворк нь гурван хэсгээс бүрдэнэ:

o validation

o

: Валидэйтор – энэ бол оролтын өгөгдлийг (integer, string, email хаяг, …) шалгах зориулалт бүхий классуудыг агуулсан дэд фреймворк widgets: Виджетүүд -

o

энэ бол формын 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()

Формын Doctrine

метод ашиглан нэг формыг нь нөгөөд нь байрлуулах замаар хоёр формыг нэгтгэх боломжтой:

$this->mergeForm(new AnotherForm());

$this->embedForm('name', new AnotherForm());

Формуудын мэдээлээл нь тогтмол хугацаанд серилэгдэн (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

o Dropdown list (

) бусад виджетүүдэд янз бүрээр илэрхийлэгдэж болно:

<select>): o Dropdown box (

array('multiple' => false, 'expanded' => false) <select multiple="multiple">):

o List of radio buttons:

array('multiple' => true,

'expanded' => false)

o List of checkboxes: array('multiple' => false, 'expanded' => true)

Хэрэв та radio button-уудын аль нэгийг дефаолтаар сонгуулахыг хүсэж байвал (ж.нь

array('multiple' => true, 'expanded' => true)

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

o Тухайн файл вэбд нийцэх формат (

нь нэлээд сонирхол төрүүлэхүйц бөгөөд, олон зүйлийг хийдэг:

mime_types

o Файлын нэрийг давхцуулалгүйгээр оноож өгнө ) мөн эсэхийг шалгана

o Файлыг зааж өгсөн замаар (given patho

) хадгадна 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-той ижил)

Нууц талбар үүсгэнэ (hidden fields) renderHiddenFields()

Формд алдаа байвал 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

o

модулийн таван үйлдлийг удирддаг:

newo

: Ажлын байр үүсгэх хоосон формыг харуулна edit

o : Ажлын байрыг засварлах формыг харуулна

createo

: Хэрэглэгчийн оруулсан өгөгдөл бүхий шинэ ажлын байрыг үүсгэнэ update

o : Хэрэглэгчийн өөрчилсөн өгөгдлийн дагуу ажлын байрны мэдээллийг шинэчилнэ

processForm: create ба update үйлдлүүдээр дуудагддаг (баталгаажуулах, талбар бөглөлтийг хянах, формыг серилж баазад хадгалах үүрэгтэй)

o Бүх форм дараах амьдралын мөчлөгийг

туулдаг:

Бид 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болгоё:

Job формыг токеноор хамгаалах

// 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);

}

Форм холбогдсон үед түүний дефаолт утга нь хэрэглэгчийн оруулсан утгаар солигддог. Энэхүү өгөгдөл нь алдаа гарсан нөхцөлд формыг дахин бөглөхөд хэрэглэгдэнэ.

Ингээд л бүх зүйл сайхан ажиллана. Одоо хэрэглэгч ажлын байранд өөрийн токен (өвөрмөц тэмдэглэгээ)-ийг оруулна. Гэхдээ бид хэрэглэгчийн оруулах токен цорын ганц байж чадах эсэхэд эргэлзэж байгаа учраас түүнийг ажлын байрыг анх оруулахдаа автоматаар үүсгэх нь зохимжтой.

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-дээ ямар ч сорилт хийгээгүй. Апликейшн хөгжүүлэхэд хамгийн чухал зүйл нь сорилт бичих явдал учраас энэ бүхнийг бид маргааш эхний ээлжинд хийх болно.

11 дэх өдөр: Формын сорилт Өчигдөр бид Symfony ашиглан өөрсдийн анхны формыг байгуулсан. Одоо хэрэглэгч өөрийн шинэ ажлын байрыг Jobeet-од тавих боломжтой болсон тул бид зарим нэг сорилтыг амжиж нэмэх шаардлагатай.

Энэ бол бидний өнөөдрийн хийх ажил. Ингэх явцдаа бид формын фреймворкийг гүнзгийрүүлэн судлах болно.

Формын фреймворкийг Symfony-гүй дангаар нь ашиглах

Symfony-н бүрэлдэхүүнүүд нь маш уян хатнаар холбогддог. Өөрөөр хэлбэл тэдний олонхи нь MVC фреймворкоос тусдаа ашиглагдах боломжтой гэсэн үг. Формын фреймворк ч мөн адил Symfony-с хамааралгүй. Та түүнийг дурын PHP апликейшнд lib/form/, lib/widgets/ ба lib/validators/ директориудыг холбож өгөн ашиглах боломжтой.

Дангаар нь ашиглах боломжтой Symfony-н өөр нэг бүрэлдэхүүн бол route фреймворк юм. lib/routing/ директорийг өөрийн төсөлдөө хуулж хийгээд та URL-ээрээ гангараарай.

Хамааралгүй бүрэлдэхүүнүүд нь

symfony platform-ыг бүрдүүлдэг:

Формыг илгээх (Submitting a Form)

Ажлын байр үүсгэх болон баталгаажуулах процесст функциональ сорилтуудыг нэмэх зорилгоор jobActionsTest файлыг нээцгээе.

Ажлын байр үүсгэх хуудсыг харахын тулд та файлын төгсгөлд дараах кодыг нэм:

// test/functional/frontend/jobActionsTest.php

$browser->info('3 - Post a Job page')->

info(' 3.1 - Submit a Job')->

get('/job/new')->

with('request')->begin()->

isParameter('module', 'job')->

isParameter('action', 'new')->

end();

Бид өмнө нь click() методыг линкийн симуляцид ашиглаж байсан. Формыг илгээхэд яг тийм аргыг хэрэглэж болно. Формын хувьд та талбар бүрийн утгыг методын хоёрдогч аргументаар илгээх боломжтой. Браузер объект нь жинхэнэ браузерийн нэгэн адилаар формын илгээгдсэн утгуудыг дефаолт утгуудтай нь нэгтгэдэг.

Харин талбарын утгуудыг дамжуулахын тулд та тэдгээрийн нэрийг мэдэж байх хэрэгтэй. Хэрэв та хуудасны эх кодыг нээх юмуу Firefox Web Developer Toolbar-ын тусламжтайгаар “Forms > Display Form Details”-ийг харвал company талбарын нэр нь үнэн чанартаа jobeet_job[company] болохыг олж харна.

PHP нь jobeet_job[company] гэсэнтэй ижил хэлбэрийн нэрүүдрийг автоматаар jobeet_job нэртэй массив болгон хувиргадаг.

Формын талбаруудын нэрсийг илүү тодорхой болгохын тулд job[%s] форматыг оруулах дараах кодыг JobeetJobForm классын configure() методын төгсгөлд бичье.

// lib/form/doctrine/JobeetJobForm.class.php

$this->widgetSchema->setNameFormat('job[%s]');

Энэ өөрчлөлтийн дараа company талбарын нэр нь таны браузерт job[company]

гэсэн хэрлбэртэйгээр харагдана. Тэгэхээр одоо талбаруудын шалгагдсан утгуудыг

формд дамжуулахын тулд "Preview your job" товчлуурыг дарах цаг нь болсон:

// test/functional/frontend/jobActionsTest.php

$browser->info('3 - Post a Job page')->

info(' 3.1 - Submit a Job')->

get('/job/new')->

with('request')->begin()->

isParameter('module', 'job')->

isParameter('action', 'new')->

end()->

click('Preview your job', array('job' => array(

'company' => 'Sensio Labs',

'url' => 'http://www.sensio.com/',

'logo' => sfConfig::get('sf_upload_dir').'/jobs/sensio-labs.gif',

'position' => 'Developer',

'location' => 'Atlanta, USA',

'description' => 'You will work with symfony to develop websites for our

customers.',

'how_to_apply' => 'Send me an email',

'email' => '[email protected]',

'is_public' => false,

)))->

with('request')->begin()->

isParameter('module', 'job')->

isParameter('action', 'create')->

end();

Хэрэв та файлын абсолют замыг зааж өгвөл браузерийн цонх нь файлын upload хийгдэж буй байдлыг дууриаж (симуляци) харуулна. Формыг илгээсний дараа create үйлдэл гүйцэтгэгдсэн эсэхийг бид шалгасан.

Формын тестер (form tester)

Бидний илгээсэн форм хүчинтэй байх ёстой. Та үүнийн формын тестер

Redirect-ийн сорилт

ашиглан шалгаж болно:

with('form')->begin()->

hasErrors(false)->

end()->

Формын тестер нь формын одоогийн статусыг шалгах хэд хэдэн методтой, ж.нь errors.

Хэрэв та сорилтдоо алдаа гаргасан бол сорилт ажиллахгүй. Энэ тохиолдолд та 9 дэх өдрийн хичээлээр үзсэн with(‘response’)->debug()statement-ийг ашиглаж болно. Гэхдээ та алдааны мессежийг олж харахын тулд үүссэн HTML кодыг ухахаас өөр аргагүй. Энэ нь үнэхээр тохиромжгүй тул формын тестер нь формын статус болон түүнтэй холбоотой бүх алдааны мэдээллийг харуулдаг debug() методыг санал болгодог.

with(‘form’)->debug()

Форм маань баталгаажиж, шинээр ажлын байр үүссэн тул одоо redirect хийгдэж хэрэглэгч show хуудас руу шилжинэ.

isRedirected()->

followRedirect()->

with('request')->begin()->

isParameter('module', 'job')->

isParameter('action', 'show')->

end()->

isRedirected() метод нь redirect хийгдсэн эсэхийг шалгадаг, харин followRedirect() метод нь redirect-ийн гүйцэтгэлийг хангадаг.

Танд redirect хийгдэхийн өмнө объектуудын байдлыг шалгах шаардлага гарч болзошгүй учраас sfBrowser класс нь автоматаар redirect хийдэггүй.

Доктриний тестер

Хэрэглэгч ажлын байраа хараахан нийтлээгүй байгаа болохоор эцсийн дүнд бид ажлын байрны мэдээлэл баазад хадгалагдсан эсэх болон activated талбарын утга false байгаа эсэхэд сорилт хийх болж байна.

Үүнийг бид өнөөг хүртэл огт хэрэглээгүй байгаа Доктриний тестерийн тусламжтайгаар хялбархан гүйцэтгэж болно. Доктриний тестер нь суугаагүй байдаг тул эхлээд түүнийг нэмцгээе:

$browser->setTester(‘doctrine’, ‘sfTesterDoctrine’);

Доктриний тестер нь өгөгдлийн бааз дахь нэг эсвэл хэд хэдэн объект аргументад өгөгдсөн шалгуурт нийцэж буй эсэхийг шалгах check() методыг санал болгодог.

with('doctrine')->begin()->

check('JobeetJob', array(

'location' => 'Atlanta, USA',

'is_activated' => false,

'is_public' => false,

))->

end()

Шалгуурууд нь дээрхи жишээн дээр үзсэнтэй адил утгуудын массив, эсвэл илүү нарийн хүсэлтүүдийн хувьд Doctrine_Query-ийн instance байж болно. Та шалгуурыг хангаж буй объект байгаа эсэхийг гуравдагч аргуметыг Boolean (дефаолт нь true)-аар өгөх, эсвэл Integer-ээр өгөөд тохирч буй объектын тоог гаргах замаар тогтоох боломжтой.

Алдаагаар сорилт хийх

Хэрэв бид зөв утгуудыг илгээвэл ажлын байрны форм нь бидний хүлээж байснаар үүснэ. Харин буруу утга илгээхийг оролдсон тохиолдолд ямар үр дүн гарахыг шалгах зорилгоор дараах сорилтыг нэмье.

$browser->

info(' 3.2 - Submit a Job with invalid values')->

get('/job/new')->

click('Preview your job', array('job' => array(

'company' => 'Sensio Labs',

'position' => 'Developer',

'location' => 'Atlanta, USA',

'email' => 'not.an.email',

)))->

with('form')->begin()->

hasErrors(3)->

isError('description', 'required')->

isError('how_to_apply', 'required')->

isError('email', 'invalid')->

end();

hasErrors() метод нь бүхэл тоон аргумент өгөгдсөн нөхцөлд алдааны тоог, isError() метод нь тухайн талбарын кодын алдааг тус тус туршина.

Бидний бичсэн буруу утга илгээх сорилууд нь бүх формыг туршиж чадахгүй. Бид зөвхөн өвөрмөц хэсгүүдэд л сорилт нэмсэн.

Түүнчлэн та алдааны мэдээлэл агуулж буй эсэхийг нь шалгах зорилгоор үүссэн HTML-ийг туршиж болох хэдий ч бид формын давхаргыг (layout) өөрчлөөгүй байгаа тул манай тохиолдолд энэ нь зайлшгүй хийх зүйл биш.

Одоо бүгдээрээ урьдчилан харах цонхны админ-баарыг туршъя. Одоохондоо ажлын байрууд идэвхжээгүй байгаа учраас та түүнийг засварлах, устгах эсвэл нийтлэх боломжтой. Энэ гурван линкийг туршихын тулд эхлээд бид ажлын байрыг үүсгэх хэрэгтэй. Гэтэл баахан copy – paste

хийх шаардлагатай, бид харин үүнд дургүй тул JobeetTestFunctional классд ажлын байр үүсгэх методыг нэмж оруулъя:

// lib/test/JobeetTestFunctional.class.php

class JobeetTestFunctional extends sfTestFunctional

{

public function createJob($values = array())

{

return $this->

get('/job/new')->

click('Preview your job', array('job' => array_merge(array(

'company' => 'Sensio Labs',

'url' => 'http://www.sensio.com/',

'position' => 'Developer',

'location' => 'Atlanta, USA',

'description' => 'You will work with symfony to develop websites for our

customers.',

'how_to_apply' => 'Send me an email',

'email' => '[email protected]',

'is_public' => false,

), $values)))->

followRedirect()

;

}

Линкийн HTTP методыг албадах (Forcing the HTTP Method of a link)

// ...

}

createJob() метод нь ажлын байрыг үүсгэн, redirect хийж, урсагч интерфейсийг (fluent interface) тасалдуулахгүй байх үүднээс браузерийг буцаадаг. Түүнчлэн та зарим дефаолт утгуудтай нэгдэх утгуудын массивыг дамжуулж болно.

“Publish” линкийг турших нь одоо харьцангуй хялбар болсон:

$browser->info(' 3.3 - On the preview page, you can publish the job')->

createJob(array('position' => 'FOO1'))->

click('Publish', array(), array('method' => 'put', '_with_csrf' => true))->

with('doctrine')->begin()->

check('JobeetJob', array(

'position' => 'FOO1',

'is_activated' => true,

))->

end();

10 дахь өдрийн хичээлээс та санаж байгаа бол, “Publish” линк нь HTTP PUTметодоор дуудагдахаар тохируулагдсан. Браузерууд PUT хүсэлтийг ойлгохгүй тул link_to() хэлпер нь линкийн зарим кодыг JavaScript-рүү хөрвүүлдэг. Харин сорилтын браузерт JavaScript ажиллахгүй учраасclick() методын гуравдагч option-оор PUT методыг албадан дамжуулах шаардлагатай болдог. Түүнээс гадна, бид хичээлийн эхний өдөр CSRF хамгаалалтыг зөвшөөрсөн болохоор link_to() хэлпер нь CSRF токенийг оруулж, _with_csrf option нь энэхүү токенийг дууриадаг (симуляци).

“Delete” линкийн сорилт нь дээрхтэй яг адил:

$browser->info(' 3.4 - On the preview page, you can delete the job')->

createJob(array('position' => 'FOO2'))->

click('Delete', array(), array('method' => 'delete', '_with_csrf' => true))->

with('doctrine')->begin()->

check('JobeetJob', array(

'position' => 'FOO2',

), false)->

end();

Сорилтууд аюулаас хамгаална

Ажлын байр нийтлэгдсэн бол та түүнийг дахин засварлах боломжгүй. Хэдийгээр “Edit” линк урьдчилан харах цонхонд харагдахаа больсон ч, дээрхи шаардлагыг хангаж буй эсэхийг шалгах зорилгоор хэдэн сорилт нэмцгээе.

Эхлээд createJob() методод ажлын байрыг автоматаар нийтлэгдэхийг зөвшөөрөх шинэ аргумент нэмж, тухайн ажлын байрны байрлалын утгыг буцаадаг getJobByPosition() методыг үүсгэе:

// lib/test/JobeetTestFunctional.class.php

class JobeetTestFunctional extends sfTestFunctional

{

public function createJob($values = array(), $publish = false)

{

$this->

get('/job/new')->

click('Preview your job', array('job' => array_merge(array(

'company' => 'Sensio Labs',

'url' => 'http://www.sensio.com/',

'position' => 'Developer',

'location' => 'Atlanta, USA',

'description' => 'You will work with symfony to develop websites for our

customers.',

'how_to_apply' => 'Send me an email',

'email' => '[email protected]',

'is_public' => false,

), $values)))->

followRedirect()

;

if ($publish)

{

$this->

click('Publish', array(), array('method' => 'put', '_with_csrf' => true))->

followRedirect()

;

}

return $this;

}

public function getJobByPosition($position)

{

$q = Doctrine_Query::create()

->from('JobeetJob j')

->where('j.position = ?', $position);

return $q->fetchOne();

}

// ...

}

Ажлын байр нийтлэгдсэн бол засварлах хуудас нь 404 status code-ийг буцаах ёстой.

$browser->info(' 3.5 - When a job is published, it cannot be edited

anymore')->

createJob(array('position' => 'FOO3'), true)->

get(sprintf('/job/%s/edit', $browser->getJobByPosition('FOO3')->getToken()))-

>

with('response')->begin()->

isStatusCode(404)->

end();

Харин бид өчигдөр хамгаалалтыг бүрэн хэмжээгээр хэрэгжүүлэхээ мартсан тул та сорилтоос хүссэн үр дүнгээ харж чадахгүй. Та бүхий л муу зүйлийг урьдчилан тооцсон байх ёстой учраас сорилт бичих нь кодын цоорхойг илрүүлэх хамгийн зөв арга юм.

Цоорхойг нөхөх нь маш амархан, учир нь ажлын байр идэвхжсэн нөхцөлд бид хэрэглэгчийг зүгээр л 404 status code-ын хуудас руу дамжуулчихаж болно.

{

// apps/frontend/modules/job/actions/actions.class.php

public function executeEdit(sfWebRequest $request)

$job = $this->getRoute()->getObject();

$this->forward404If($job->getIsActivated());

$this->form = new JobeetJobForm($job);

}

Алдааг засах нь маш хялбар байлаа. Гэхдээ та бусад бүх зүйл хүссэний дагуу ажиллана гэдэгт итгэлтэй байна уу? Та өөрийн браузерийг нээж ажлын байр засварлах хуудасд нэвтрэх боломжит бүх хувилбар комбинациудаар сорилт хийж үзэж болно. Гэхдээ үүнээс дээр арга бий: өөрийн сорилтуудын цуглуулгыг ажиллуулж үзэх; хэрэв та регресс оруулбал Symfony нэн даруй танд мэдээлнэ.

Сорилтын ирээдүй рүү буц

Ажлын байрны хугацаа дуусахаас 5-аас цөөн хоног үлдсэн, эсвэл хугацаа нь аль хэдийн дууссан бол хэрэглэгч энэхүү хугацааг өнөөдрөөс эхлэн дахин 30 хоногоор сунгаж болно.

Энэ шаардлагыг браузерт турших нь хялбар биш даалгавар, учир нь хүчинтэй хугацаа нь ажлын байрыг үүсгэхэд автоматаар 30 хоногоор тавигддаг. Ийм учраас ажлын байрны хуудсыг нээхэд хугацаа сунгах линк байдаггүй. Мэдээж хэрэг та огноог баазад нь шууд өөрчлөх, эсвэл хуудасны темплэйтийг өөрчилж линкийг байнга харагдаж байхаар болгон засварлаж болно. Гэв ч энэ нь ядаргаатай бөгөөд асар олон алдааг дагуулна.

Таны таамагласанчлан, цөөн хэдэн сорилт бичих нь бидэн дахин тус болно.

Байнга хийдэг шигээ бид эхний ээлжинд extend методод шинэ route нэмж өгөх шаардлагатай:

# apps/frontend/config/routing.yml

job:

class: sfDoctrineRouteCollection

options:

model: JobeetJob

column: token

object_actions: { publish: PUT, extend: PUT }

requirements:

token: \w+

Дараа нь _admin partial дахь “Extend” линкийн кодыг баяжуулъя:

<!-- apps/frontend/modules/job/templates/_admin.php -->

<?php if ($job->expiresSoon()): ?>

- <?php echo link_to('Extend', 'job_extend', $job, array('method' => 'put'))

?> for another <?php echo sfConfig::get('app_active_days') ?> days

<?php endif; ?>

Контроллерт extend үйлдлийг үүсгэе:

// apps/frontend/modules/job/actions/actions.class.php

public function executeExtend(sfWebRequest $request)

{

$request->checkCSRFProtection();

$job = $this->getRoute()->getObject();

$this->forward404Unless($job->extend());

$this->getUser()->setFlash('notice', sprintf('Your job validity has been

extended until %s.', $job->getDateTimeObject('expires_at')-

>format('m/d/Y')));

$this->redirect('job_show_user', $job);

}

Контроллер нь JobeetJob классын extend() метод ажлын байрны хугацаа сунгагдсан бол true, үгүй бол false утгыг буцаана гэж хүлээж байгаа:

// lib/model/doctrine/JobeetJob.class.php

class JobeetJob extends BaseJobeetJob

{

public function extend()

{

if (!$this->expiresSoon())

{

return false;

}

$this->setExpiresAt(date('Y-m-d', time() + 86400 *

sfConfig::get('app_active_days')));

$this->save();

return true;

}

// ...

}

Эцэст нь сорилтын сценарийг нэмье:

$browser->info(' 3.6 - A job validity cannot be extended before the job

expires soon')->

createJob(array('position' => 'FOO4'), true)->

call(sprintf('/job/%s/extend', $browser->getJobByPosition('FOO4')-

>getToken()), 'put', array('_with_csrf' => true))->

with('response')->begin()->

isStatusCode(404)->

end()

;

$browser->info(' 3.7 - A job validity can be extended when the job expires

soon')->

createJob(array('position' => 'FOO5'), true);

$job = $browser->getJobByPosition('FOO5');

$job->setExpiresAt(date('Y-m-d'));

$job->save();

$browser->

call(sprintf('/job/%s/extend', $job->getToken()), 'put', array('_with_csrf'

=> true))->

with('response')->isRedirected();

$job->refresh();

$browser->test()->is(

$job->getDateTimeObject('expires_at')->format('y/m/d'),

date('y/m/d', time() + 86400 * sfConfig::get('app_active_days'))

);

Сорилтын сценарит хэд хэдэн шинэ зүйл бий:

o call() метод нь URL-ээс GET юмуу POST-оос ялгаатай методуудыг ялган авч хүсэлт боловсруулан хэрэгжүүлдэг

o Ажлын байрны мэдээлэл шинэчлэгдсэний дараа бидэнд $job->refresh()-ийн тусламжтайгаар локал объектыг дахин ачаалах шаардлага гардаг

o Эцэст нь бид ажлын байрны хүчинтэй хугацааны сорилтыг шууд хийх боломжтой болох ба ингэхдээ оруулж өгсөн lime объектоо ашиглана

Формын аюулгүй байдал

Формын серилэлтийн ид шид (Form Serialization Magic!)

Формын Doctrine нь маш олон ажлыг автоматжуулсан тул хэрэглэхэд маш амар. Жишээлбэл формуудыг серилж баазад хадгалах үйлдлийг зүгээр л $form->save() гээд л боллоо.

Харин энэ бүхэн яаж ажилладаг юм бол? Нэн түрүүнд save()метод дараах алхмуудыг гүйцэтгэнэ:

o Транзэкшнийг эхлүүлдэг (формын Doctrine нь бүгд үндсэн формтойгоо нэг дор хадгалагддаг учраас)

o Илгээгдэсэн утгуудыг боловсруулдаг (хэрэв updateCOLUMNColumn() метод өгөгдсөн бол түүнийг дууддаг)

o Багануудын утгыг шинэчлэх зорилгоор Doctrine объектийн fromArray() методыг дууддаг o Объектыг өгөгдлийн баазад хадгалдаг o Транзэкшнийг байгуулдаг (commit the transaction)

Аюулгүй байдлын мөн чанар (Built-in Security Features)

fromArray() метод нь утгуудын массивыг авч харгалзах багануудын утгыг шинэчилдэг. Энэ нь аюулгүй байдалд нөлөөлж чадах уу? Хэрэв хэн нэг нь өөрийн хандах эрхгүй баганын утгыг шинэчлэхийг оролдвол яах вэ? Жишээлбэл би token баганын утгыг хүчээр өөрчилж чадах уу?

Тэгвэл ажлын байрны мэдээллийг token талбартай хамтад нь хадгалж буй байдлыг дууриан харуулах (simulate) сорилт бичцэгээе:

// test/functional/frontend/jobActionsTest.php

$browser->

get('/job/new')->

click('Preview your job', array('job' => array(

'token' => 'fake_token',

)))->

with('form')->begin()->

hasErrors(7)->

hasGlobalError('extra_fields')->

end();

Та формыг илгээмэгцээ extra_fields гэсэн глобал алдаа гарахыг харах болно. Яагаад гэвэл дефаолтдаа форм нь нэмэлт талбар илгээхийг зөвшөөрдөггүй. Ийм ч учраас формын талбар бүр нь өөрийн валтдэйтортой байдаг.

Түүнчлэн та Firefox Web Developer Toolbar гэх мэт хэрэгсэл ашиглан браузерийн тусламжтайгаар нэмэлт талбар илгээхээр оролдож болно.

Та аюулгүй байдлын энэхүү арга хэмжээг allow_extra_fields сонголтын утгыг true болгох замаар идэвхгүй болгож болно.

class MyForm extends sfForm

{

public function configure()

{

// ...

$this->validatorSchema->setOption('allow_extra_fields', true);

}

}

Энэ тохиолдолд сорилт ажиллана, харин token талбарын утга илгээгдэхгүй орхигдоно. Ийм маягаар та өмнөхтэйгөө адил формын аюлгүй байдлыг алдагдуулж чадахгүй. Харин танд дээрхи сонголт үнэхээр хэрэтэй байгаа бол filter_extra_fields сонголтыг false болгоорой:

$this->validatorSchema->setOption(‘filter_extra_fields’, false);

Энэ бүлэгт бичсэн сорилтууд нь зөвхөн үзүүлэнгийн зориулалттай. Танд Symfony-н өөрийнх нь боломжийг сорих шаардлага байхгүй тул дээрхи сорилтуудыг Jobeet төслөөс устгаж болно.

Юуны өмнө тэр XSS халдлагын эсрэг хамгаалалтыг идэвхжүүлдэг. Өөрөөр хэлбэл темплэйтэд хэрэглэгдэж буй бүх хувьсагчдад escape хийгдэхээр тохируулсан гэсэн үг. Хэрэв та дотроо

XSS ба CSRF-ийн хамгаалалт

Эхний өдрийн хичээлээс л бид generate:app таск нь хамгаалагдсан апликейшн үүсгэдэг гэдгийг мэдэж авсан.

HTML тэг агуулсан ажлын байрны мэдээлэл илгээвэл symfony түүнийг ердийн текст хэлбэрээр дэлгэцэд харуулна.

Түүнчлэн CSRF халдлагын эсрэг хамгаалалт мөн идэвхждэг. CSRF токен тавигдсан үед бүх формуудад _csrf_token нууц талбар нэмэгддэг.

Escape-ийн стратеги болон CSRF нууцлалыг хүссэн цагтаа apps/frontend/config/settings.yml тохиргооны файлыг засварлан өөрчилж болно. Түүнчлэн databases.yml файлд гүйцэтгэлийн тодорхой орчинд зориулсан тохиргоонууд агуулагддаг.

all:

.settings:

# Form security secret (CSRF protection)

csrf_secret: Unique$ecret

# Output escaping settings

escaping_strategy: true

escaping_method: ESC_SPECIALCHARS

Хэрэглээний таск үүсгэх

Symfony нь хэдийгээр вэб фреймворк болов ч command line tool-ийг ашигладаг. Та төслийн болон апликейшний директорийн бүтцийг үүсгэх, түүнчлэн моделийн янз бүрийн файлуудыг үүсгэхдээ үүнийг ашиглаж байсан. Symfony-н command line нь фреймворкийнхоо дотор нь байдаг учраас шинэ таск нэмж оруулахад маш хялбар.

Хэрэглэгч шинээр ажлын байр оруулаад, түүнийгээ бусдад нээллттэй болгохын тулд идэвхжүүлэх ёстой. Ингэхгүй бол өгөгдлийн бааз нь идэвхгүй ажлын байрны мэдээллүүдээр дүүрэх болно. Иймд өгөгдлийн баазаас идэвхгүй ажлын байруудыг устгах таскийг үүсгэе. Энэ таск нь ихэвчлэн ажлын байрны cron-д дуудагдан ажиллана:

// lib/task/JobeetCleanupTask.class.php

class JobeetCleanupTask extends sfBaseTask

{

protected function configure()

{

$this->addOptions(array(

new sfCommandOption('application', null, sfCommandOption::PARAMETER_REQUIRED,

'The application', 'frontend'),

new sfCommandOption('env', null, sfCommandOption::PARAMETER_REQUIRED, 'The

environement', 'prod'),

new sfCommandOption('days', null, sfCommandOption::PARAMETER_REQUIRED, '',

90),

));

$this->namespace = 'jobeet';

$this->name = 'cleanup';

$this->briefDescription = 'Cleanup Jobeet database';

$this->detailedDescription = <<<EOF

The [jobeet:cleanup|INFO] task cleans up the Jobeet database:

[./symfony jobeet:cleanup --env=prod --days=90|INFO]

EOF;

}

protected function execute($arguments = array(), $options = array())

{

$databaseManager = new sfDatabaseManager($this->configuration);

$nb = Doctrine_Core::getTable('JobeetJob')->cleanup($options['days']);

$this->logSection('doctrine', sprintf('Removed %d stale jobs', $nb));

}

}

Таскийн конфигураци нь configure() методод биелдэг. Таск бүр нь namespace:name гэсэн цор ганц хослолыг агуулахын зэрэгцээ аргумент ба сонголтуудтай байж болно.

Илүү олон жишээ харъя гэвэл Symfony-н таск хавтсыг (lib/task/) үз.

jobeet:cleanup таск нь хоёр сонголтыг тодорхойлдог: –env ба –days хэд хэдэн дефаолт утгын хамт.

Энэ таскийг ажиллуулах нь бусад дурын таск дуудахтай ижил:

$ php symfony jobeet:cleanup –days=10 –env=dev

Өгөгдлийн бааз цэвэрлэх код нь бусад кодуудын адил JobeetJobTable классд төвлөрдөг:

// lib/model/doctrine/JobeetJobTable.class.php

public function cleanup($days)

{

$q = $this->createQuery('a')

->delete()

->andWhere('a.is_activated = ?', 0)

->andWhere('a.created_at < ?', date('Y-m-d', time() - 86400 * $days));

return $q->execute();

}

Symfony-н таскууд нь гүйцэтгэлийн үр дүнг илэрхийлсэн утгыг буцаадаг учраас орчинтойгоо сайн зохицож ажилладаг. Та буцаагдах бүхэл тоог таскийнхаа төгсгөлд тодорхой зааж өгч болно.

Сорилт – энэ бол Symfony-н хэрэгслийн болон философийн зүрх нь юм. Бид өнөөдөр вэбийн боловсруулалтыг хялбар, хурдан, илүү найдвартай болгохын тулд Symfony-н хэрэгслийг хэрхэн ашиглах талаар дахин судаллаа.

Маргааш уулзацгаая

Symfony-н формын фреймворк – энэ бол зөвхөн виджет, валидэйтор биш, түүнээс хамаагүй том зүйл: тэр танд формын сорилтын энгийн аргуудыг өгөөд зогсохгүй формууд тань найдвартай хамгаалагдсан гэсэн итгэлийг төрүүлнэ.

Symfony-н гайхамшигтай ертөнцөөр аялах манай аялал өнөөдөр дуусаагүй. Маргааш бид Jobeet-ийн бээкэнд апликейшнийг байгуулна. Бээкэнд интерфейс бол олонхи вэб-төслийн чухал хэсэг бөгөөд Jobeet-ийн хувьд ч мөн адил. Харин бид түүнийг хэрхэн ганц цагийн дотор байгуулах вэ? Маш энгийн – бид Symfony-н админ үүсгэгч фреймворкийг ашиглана. Харин тэр болтол биеэ бодоорой.

Б.Батжаргал

Орчуулсан:

[email protected] http://ssacci.blogspot.com

Дурьдатгал:

Олны хүч оломгүй далай гэгчээр бидний орчуулгын хэсэгт маань Б.Батжаргал гишүүн өөрийн хүчээ хавсаргалаа. Таньд энэ хичээл таалагдсан бол Батжаргалд баярлалаа гээрэй.

Энэхүү админ үүсгэгч нь symfony framework байдаг том давуу талуудын нэг бөгөөд маш хэрэгтэй сэдвүүдийн нэг яалтчгүй мөн юм. Үүний ачаар та өөрийн прожектынхоо админы хэсгийг яаж үүсгэхэд санаа зовох шаардлагагүй боллоо гэсэн үг.

Асуух зүйл байвал comment үлдээгээрэй эсвэл [email protected]

Day 12: The Admin Generator (Өдөр 12: Админ үүсгэгч)

-группын гишүүдээс асуух боломжтой.

Энэхүү номыг монгол хэлээр хөрвүүлөх ажилд маань оролцож буй бүх гишүүддээ БАЯРЛАЛАА. Номын буян дэлгэрэх болтугай.

Бид jobeet –ийн 11 өдөрийн турш ажил нийтлэх болон ажил хайх frontend application хийсэн билээ. Одоо backend application –ны талаар бага зэрэг ярья. Өнөөдөр, Jobeet –ийн backend интерфэйсийг хөгжүүлэхэд нэгхэн цаг л хангалттай бөгөөд бид symfony –ийн админ үүсгэгч функцтэй танилцах болно.

Backend creation (Backend байгуулалт)

Хамгийн эхний алхам нь backend application үүсгэх юм. Хэрвээ та сайн ой тогтоолттой бол, generate:app комманд (task) –ыг хэрхэн ашигладагийг санаж байгаа байгаа байх.

$ php symfony generate:app backend

Одоо backend application–ны бүтээгдэхүүний орчин (prod environment)http://jobeet.localhost/backend.php/ болон хөгжүүлэлтийн орчин (dev environment) http://jobeet.localhost/backend_dev.php/ бэлэн болсон.

v Frontend application үүсгэх үед, бүтээгдэхүүний front controller нь index.php нэртэй байсан. Фолдер (directory) бүрт index.php файл зөвхөн нэг байх ёстой тул symfony хамгийн эхний бүтээгдэхүүний (production) front controller –т index.php файл үүсгэдэг ба дараагийн файлуудыг application –ны нэрээр нэрлэдэг.

Хэрэв data fixtures –ийг doctrine:data-load коммандаар дахин үүсгэхийг оролдвол,

энэ нь ажиллахгүй юм. Учир нь,JobeetJob::save() функц (method) нь frontend

application –aac app.yml configuration файл руу хандна. Одоо бидэнд

хоёрapplication байгаа, эхнийх нь symfony –ийн ашиглаж

байгааfrontend application, хоёрдах нь backend application юм.

Бид тохиргоонууд (settings) нь өөр өөр түвшинд тохируулагддаг гэдгийг 8 –н өдрийн турш үзсэн билээ. apps/frontend/config/app.yml файлын кодыг (content) config/app.yml файл руу зөөснөөр тохиргоонууд нь бүх application –уудын хувьд идэвхижих ба асуудал (problem) засагдана. Одоо admin generator –т model классуудыг ашиглах мөн backend application-ны app.yml файлд хувьсагчуудыг тодорхойлох өөрчлөлтийг хийе.

v Хэрэв нэг эсвэл өөр application –аас зарим тусгай тохиргоонууд хэрэгтэй бол doctrine:data-load коммандын

Backend Modules (backend модулиуд)

--application боломж (option) –ийг тавина.

$ php symfony doctrine:data-load --application=frontend

Frontend application –ны хувьд doctrine:generate-module комманд үндсэн CRUD модульд суурилагдсан Model классдээр bootstrap –ийг ашигласан. Backend application –ны хувьд Model класс-ийн backend интерфэйс үүсгэхэд doctrine:generate-admin коммандыг хэрэглэнэ.

$ php symfony doctrine:generate-admin backend JobeetJob --module=job

$ php symfony doctrine:generate-admin backend JobeetCategory --

module=category

Дээрхи коммандууд нь JobeetJob болон JobeetCategory model (загвар) классуудад харгалзан job болон category module (модуль) үүсгэнэ.

--module боломж (option)–ийг тодорхойлж өгсөнөөр коммандынdefault –аар

үүсгэсэн модулийн нэрийг солино. (хэрэв тодорхойлоогүй бол JobeetJob –ийн

хувьд үүссэн модуль ньjobeet_job

нэртэй байна.)

Арын хэсгүүд, комманд нь мөн модуль бүрийн custom route (чиглүүлэгч хэв) – г үүсгэдэг.

# apps/backend/config/routing.yml

jobeet_job:

class: sfDoctrineRouteCollection

options:

model: JobeetJob

module: job

prefix_path: job

column: id

with_wildcard_routes: true

Admin generator –т хэрэглэгдэж байгаа route -н класс нь санамсаргүй зүйл биш

юм. (Admin Generator бол sfDoctrineRouteCollection юм.) Админ интерфэйсийн

гол зорилго нь model (загвар) обьектуудын ажиллах циклийн менежмент

(management of the life-cycle) юм.

Дээрхи route тодорхойлолтонд түүнчлэн бидний өмнө нь үзээгүй хэдэн боломжууд (options) –ыг тодорхойлсон байна.

o · prefix_path: route (чиглүүлэгч) үүсгэх угтвар замыг тодорхойлдог(жишээ нь,

засварлах хуудас нь /job/1/edit

o шиг байж болно).

· column: обьектыг лавлах холбоосуудын

o

URL-д хэрэглэх хүснэгтийн баганыг

тодорхойлно. with_wildcard_routes

v Шинэ комманд (task) хэрэглэхийн өмнө үргэл тусламж (help) –ийг уншиж байх нь сайн зуршил (good idea) юм.

: Админ интерфэйс нь сонгодог (classic) CRUD үйлдлүүдээс илүү боломжуудтай. Энэ боломж (option) нь route –ийг засварлахгүйгээр олон обьект болон action –ны цуглуулга (collection) тодорхойлохыг зөвшөөрдөг.

$ php symfony help doctrine:generate-admin

Энэ нь чамд коммандын бүх аргументууд блон бололмжууд(options) -ийг мөн дээр

нь хэрхэн ашиглах зарим сонгодог жишээнүүдийг харуулах болно.

Backend Look and Feel (backendхарагдац болон ойлголт)

Нүд ирмэх зуур л модулиудаа үүсгэлээ. Одоо ашиглаж болно:

http://jobeet.localhost/backend_dev.php/job

http://jobeet.localhost/backend_dev.php/category

Админ модулиуд (modules) нь бидний өмнөх өдрүүдэд үүсгэсэн энгийн модулиудаас

(modules) илүү олон онцлогуудтай. PHP –н нэг ч мөр бичилгүйгээр модуль

(module) бүр дараах олон онцлогуудаар хангагддаг:

· Обьектуудын жагсаалт нь хуудаслагдсан ( paginated ).

· Жагсаалт нь эрэмблэлттэй ( sortable ).

· Жагсаалтаас шүүлт хийнэ ( filtered ) .

· Обьектууд үүсгэж, засварлаж, устгаж болно. ( created, edited, and

deleted )

· Сонгосон обьектуудыг batch –аас устгах.

· Формын оролт шалгалт ( form validation ) идэвхижсэн.

· Хэрэглэгч руу шууд feedback (мэдэгдэх) өгөх flash messages

· ... болон илүү олон

Admin generator нь backend интерфэйс үүс гэхэд хэрэгтэй энгийн тохиргооны

пакеж (configure package) дахь бүх онцлогуудаар хангадаг.

Үүсгэгдсэн хоёр модулиудыг хараад, webdesign идэвхижээгүй байхад symfony үндсэн график интерфэйсийг default –аар үүсгэсэн байгааг чи ажигласан байх. Одоо sfDoctrinePlugin –н файлууд (assets -хөрөнгө) web/ фолдерт байрлаагүй байгаа ба бид plugin:publish-assets коммандыг хэрэглэн web/ фолдерт тэдгээрийг байрлуулана:

$ php symfony plugin:publish-assets

Хэрэглэгчийн чадварыг бага зэрэг нэмэгдүүлэх үүднээс default backend –ийг өөрчлөх хэрэгтэй. Мөн өөр модуль хооронд шилжихэд (navigate) хялбар болгох энгийн цэс (menu) нэмнэ.

<div id="header">

layout файлын агуулгыг доорхи кодоор соль (replace):

// apps/backend/templates/layout.php

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">

<head>

<title>Jobeet Admin Interface</title>

<link rel="shortcut icon" href="/favicon.ico" />

<?php use_stylesheet('admin.css') ?>

<?php include_javascripts() ?>

<?php include_stylesheets() ?>

</head>

<body>

<div id="container">

<h1>

<a href="<?php echo url_for('homepage') ?>">

<img src="/images/logo.jpg" alt="Jobeet Job Board" />

</a>

</h1>

</div>

<div id="menu">

<ul>

<li>

<?php echo link_to('Jobs', 'jobeet_job') ?>

</li>

<li>

<?php echo link_to('Categories', 'jobeet_category') ?>

</li>

</ul>

</div>

<div id="content">

<?php echo $sf_content ?>

</div>

<div id="footer">

<img src="/images/jobeet-mini.png" />

powered by <a href="http://www.symfony-project.org/">

<img src="/images/symfony.gif" alt="symfony framework" /></a>

</div>

</div>

</body>

</html>

Энэ layout (давхарга) нь admin.css stylesheet (загвар хуудас) хэрэглэдэг. Энэ файлыг 4 дэхь өдөр бусад stylesheet -уудтай хамт web/css/ фолдерт хуулсан (installed) байгаа.

Эцэст нь, routing.yml файл дахь symfony homepage –ийг өөрчилнө:

# apps/backend/config/routing.yml

homepage:

url: /

param: { module: job, action: index }

The symfony Cache (symfony кэйш)

Их сониуч хүн бол магадгүй аль хэдийн коммандаарapps/backend/modules/ директорт үүссэн файлуудыг нээчихсэн байгаа байх. Үгүй бол одоо тэднийг нээнэ үү. Surprise! templates директорууд хоосон байгаа ба actions.class.php файлууд бараг хоосон байна:

// apps/backend/modules/job/actions/actions.class.php

require_once dirname(__FILE__).'/../lib/jobGeneratorConfiguration.class.php';

require_once dirname(__FILE__).'/../lib/jobGeneratorHelper.class.php';

class jobActions extends autoJobActions

{

}

Яаж ажиллаж байна вэ? Хэрвээ чи сайн харах юм бол, jobActions классautoJobActions классаас удамшсан (extends) байгааг мэдэх болно. ХэрэвautoJobActions класс байхгүй бол symfony автоматаар үүсгэдэг.autoJobActions классыг cache/backend/dev/modules/autoJob/директороос олж болно. Энэ нь “real” модулийг агуулдаг:

// cache/backend/dev/modules/autoJob/actions/actions.class.php

class autoJobActions extends sfActions

{

public function preExecute()

{

$this->configuration = new jobGeneratorConfiguration();

if (!$this->getUser()->hasCredential(

$this->configuration->getCredentials($this->getActionName())

))

{

// ...

Admin generator нь зарим төлөв байдлыг сануулах замаар ажилдаг. Бид үнэндээ ийм model болон форм классуудын тухай аль хэдийн сурчихсан. Symfony model тодорхойлсон схем дээр суурилж model болон форм классуудыг үүсгэдэг. Admin generator –ийн хувьд үүсгэгдсэн модулийг модуль дахь config/generator.yml файлыг засварлаж тохируулга хийнэ:

# apps/backend/modules/job/config/generator.yml

generator:

class: sfDoctrineGenerator

param:

model_class: JobeetJob

theme: admin

non_verbose_templates: true

with_show: false

singular: ~

plural: ~

route_prefix: jobeet_job

with_doctrine_route: true

config:

actions: ~

fields: ~

list: ~

filter: ~

form: ~

edit: ~

new: ~

generator.yml файлыг засварлах бүр symfony кэш (cache) үүсгэж байдаг. Бид дараа админы үүсгэгдсэн модулиудыг засаж өөрчлөх нь амархан, хурдан бөгөөд хөгжилтэй ажил болохыг харах болно.

v Автоматаар дахин үүсгэсэн кэш файлууд нь зөвхөн хөгжүүлэлтийн орчинд (development environment) харагддаг. Харин бүтээгдэхүүний орчинд (production environment) cache:clear коммандыг ажиллуулж кэшийг устгах хэрэгтэй.

v with_show параметр нь ямарч нөлөөгүй (no effect) юм. Энэ параметр нь зөвхөн doctrine:generate-module комманд

Backend Configuration (backend тохиргоо)

“standard” модулиуд үүсгэж байна гэсэн утгатай.

generator.yml файлын config

o

түлхүүрийг засварласанаар админ модулийг өөрчилнө. Энэ тохиргоо нь долоон хэсгээс бүтнэ:

actions

o : жагсаалт (list) болон фомрын action –нуудын default тохиргоо

fields

o : талбаруудын default тохиргоо

list

o : жагсаалтын (list) тохиргоо

filter

o : шүүлтийн (filter) тохиргоо

form

o : шинээр үүсгэх болон завсарлах формуудын тохиргоо

edit: засварлах хуудасны тохиргоо тодорхойлох

o new

Өөрчлөлтөө эхэлцгээе!

: шинээр үүсгэх хуудасны тохиргоо тодорхойлох

Title Configuration (гарчигны тохиргоо)

Title боломж (option)-ийг тодорхойлсоноор category модулийн жагсаалт (list), засварлах ( edit), болон шинээр үүсгэх (new)хэсгүүдийн гарчигийг өөрчилж болно:

# apps/backend/modules/category/config/generator.yml

config:

actions: ~

fields: ~

list:

title: Category Management

filter: ~

form: ~

edit:

title: Editing Category "%%name%%"

new:

title: New Category

Засварлах (edit) хэсгийн title -д динамик утга авдаг: %% тэмдэгийн хооронд обьектын тохирох баганы утгыг тавьж өгнө.

job модулийн тохиргоо нь яг адилхан:

# apps/backend/modules/job/config/generator.yml

config:

actions: ~

fields: ~

list:

title: Job Management

filter: ~

form: ~

edit:

title: Editing Job "%%company%% is looking for a %%position%%"

new:

title: Job Creation

Fields Configuration (талбаруудын тохиргоо)

Харагдац бүрийн (list, new, болон edit) талбарууд өөр зохион байгуулалттай. Талбар нь model классын багана эсвэл virual багана байна. Virtual баганыг дараа үзнэ.

Талбаруудын default тохиргоог fields хэсэгт өөрчилнө:

# apps/backend/modules/job/config/generator.yml

config:

fields:

is_activated: { label: Activated?, help: Whether the user has activated

the job, or not }

is_public: { label: Public?, help: Whether the job can also be

published on affiliate websites, or not }

fields хэсэг дэхь is_activated талбарын label нь бүх (list, edit, болон new) харагдацын тохиргоог өөрчилнө.

Admin generator тохиргоо нь cascade зарчим дээр суурилагдсан. Тухайлбал, хэрэв та зөвхөн list харагдацын label –г өөрчлөхийг хүсвэлlist хэсэгт fields боломж (option)-г тодорхойлох хэрэгтэй:

# apps/backend/modules/job/config/generator.yml

config:

list:

fields:

is_public: { label: "Public? (label for the list)" }

Үндсэн fields

o

хэсэгт тавьсан ямарч тохиргооноос (configuration) харагдацад тодорхойлсон тохиргоо нь давуу байна. Доор давуу зэргийн зарчимыг харуулсан байна:

new болон edit нь form -оос удамшсан. form нь fields o

–ээс удамшсан. list нь fields

o –ээс удамшсан

filter нь fields

v form (

–ээс удамшсан

form, edit, болон new) хэсгүүдийн хувьд label болон helpболомж (option) -ууд form классуудад тодорхойлсоныг дахин тодорхойлдог.

List View Configuration (жагсаалт харагдацын тохиргоо)

display

default –аар list харагдацын баганууд нь схем файлд (schema file) тодорхойлсон model –ийн бүх баганууд байдаг.

(харуулах)

display боломж (option) нь дэлгэцэнд харагдах багануудыг дахин тодорхойлдог:

# apps/backend/modules/category/config/generator.yml

config:

list:

title: Category Management

display: [=name, slug]

баганын name –ын өмнө = тэмдэг байгаа нь тэмдэг мөрийг холбоос руу хөрвүүлэхийг заана.

Одоо job модулийг мөн адил уншихад илүү хялбар болгоцгооё:

# apps/backend/modules/job/config/generator.yml

config:

list:

title: Job Management

display: [company, position, location, url, is_activated, email]

layout

list –ийг өөр давхаргуудаар (layouts) харуулж болно. Default –аар

(давхарга)

tabularдавхаргаар (layout) харагддаг ба энэ нь багана бүрийн утга өөрийн хүснэгтийн баганад харагдана гэсэн үг. Гэвч jobмодулийн хувьд stacked давхарга (layout) –ыг хэрэглэсэн нь бусад давхарга (layout) –аар хийхээс илүү дээр юм:

# apps/backend/modules/job/config/generator.yml

config:

list:

title: Job Management

layout: stacked

display: [company, position, location, url, is_activated, email]

params: |

%%is_activated%% <small>%%category_id%%</small> - %%company%%

(<em>%%email%%</em>) is looking for a %%=position%% (%%location%%)

stacked давхарга (layout) нь обьект бүрийг params боломж (option) –д тодорхойлсоноор нэг тэмдэгт мөрөөр харуулдаг.

v display

“Virtual” columns (хийсвэр багана)

боломж (option) нь хэрэглэгчийн эрэмлэлт хийх багануудад хүртэл хэрэглэгддэг.

Virtual column тохиргооны %%category_id%% хэсэг категорийн (category) primary key –ээр солигдоно. Энэ нь категорийн нэрийг илүү утга агуулгатай харагдуулна.

Та хэзээ ч юм %% тэмдэглэл хэрэглэж байхдаа хувьсагчийг нь database schema дэхь жинхэнэ баганыг тохируулахад хэрэглэгддэггүй байсан байх. Admin generator нь зөвхөн model класс дахь холбоотой getter –г олоход хэрэглэнэ.

%%category_id%% -ийг %%category_name%% -ээр сольсоноор JobeetJobmodel классын getCategoryName() функц категорийн нэрийг харуулах болно.

Гэхдээ JobeetJob класст харгалзах category обьектыг буцаадагgetJobeetCategory() функц аль хэдийн зарлагдсан байгаа. Хэрэв та%%jobeet_category%% гэж хэрэглэвэл JobeetCategory класс дахь шидэт (magic) __toString() функц обьектыг тэмдэгт мөр рүү хөрвүүлсэнээр ажиллах болно.

# apps/backend/modules/job/config/generator.yml

%%is_activated%% <small>%%jobeet_category%%</small> - %%company%%

(<em>%%email%%</em>) is looking for a %%=position%% (%%location%%)

sort

Хэрэв та администратор байсан бол магадгүй хамгийн сүүлд зарлагдсан ажлуудыг харахыг илүү хүсэх байсан байх.

(эрэмбэлэх)

sort боломж (option) –ийг нэмснээр эрэмбэлэгдсэн баганыг default –аар тохируулах болно:

# apps/backend/modules/job/config/generator.yml

config:

list:

sort: [expires_at, desc]

max_per_page

жагсаалт (list) нь хуудаслагдсан бөгөөд default –аар хуудса бүрт 20 зүйл (item) байна. Үүнийг

(хуудасанд харагдах хэмжээ)

max_per_page боломж (option) –оор өөрчилнө:

# apps/backend/modules/job/config/generator.yml

config:

list:

max_per_page: 10

batch_actions

Жагсаалт дах action нь зарим обьектуудад ашиглагдана. Эдгээр batch action-ууд нь

(багцын үйлдлүүд)

category модульд хэрэглэгдэхгүй, тиймээс, тэднийг устгацгаая:

# apps/backend/modules/category/config/generator.yml

config:

list:

batch_actions: {}

batch_actions боломж (option) –оор batch action-уудын жагсаалтыг тодорхойлдог. Хоосон array нь харагдахгүй болгоно.

Framework нь модуль бүрт default -аар delete batch action –ыг тодорхойлсон байдаг. Гэвч job модулийн хувьд сонгосон ажлуудыг дахин 30 –н өдрөөр сунгадаг байх хэрэгтэй учир extend үйлдэлийг нэмье:

# apps/backend/modules/job/config/generator.yml

config:

list:

batch_actions:

_delete: ~

extend: ~

Framework –оос хангаж өгдөг action-ууд нь бүгдээрээ _ (доогуур зураас) –аар эхэлдэг. Хэрэв броузероо (browser) refresh хийгээд batch action –аас extend –ийг сонговол, symfony “та executeBatchExtend() функцыг үүсгэ” гэсэн утгатай алдааг илгээх болно:

// apps/backend/modules/job/actions/actions.class.php

class jobActions extends autoJobActions

{

public function executeBatchExtend(sfWebRequest $request)

{

$ids = $request->getParameter('ids');

$q = Doctrine_Query::create()

->from('JobeetJob j')

->whereIn('j.id', $ids);

foreach ($q->execute() as $job)

{

$job->extend(true);

}

$this->getUser()->setFlash('notice', 'The selected jobs have been

extended successfully.');

$this->redirect('jobeet_job');

}

}

Сонгогдсон primary key –үүдийг ids параметрт хадгалдаг. Сонгогдсон ажил бүрийн хувьд дуусах хугацааг шалгахыг заасан нэмэлт аргументтайJobeetJob::extend() функцыг дууддаг.

Энэ шинэ аргументыг тавьж extend() функцыг сайжруулна:

// lib/model/doctrine/JobeetJob.class.php

class JobeetJob extends BaseJobeetJob

{

public function extend($force = false)

{

if (!$force && !$this->expiresSoon())

{

return false;

}

$this->setExpiresAt(date('Y-m-d', time() + 86400 *

sfConfig::get('app_active_days')));

$this->save();

return true;

}

// ...

}

Бүх ажил сунгагдсаны дараа хэрэглэгч рүү job модулийн нүүр хуудсыг дахин харуулах болно.

object_actions

Жагсаалтын actions гэсэн нэмэлт багананд тухайн нэг обьект дээр хийгдэх үйлдлүүд байдаг.

(обьектын үйлдлүүд)

Category модулийн хувьд категорийн нэрэнд нь засварлах холбоос холбогдсон ба жагсаалтаас шууд устгах холбоос ил байх нь бидэнд хэрэггүй тул засварлах болон устгах үйлдлүүдийг устгацгаая:

# apps/backend/modules/category/config/generator.yml

config:

list:

object_actions: {}

Харин job модуль дээр batch action дээр нэмсэнтэй адил extend үйлдлийг нэмж харуулая:

# apps/backend/modules/job/config/generator.yml

config:

list:

object_actions:

extend: ~

_edit: ~

_delete: ~

batch action –ны хувьд framework нь _delete болон _edit үйлдлүүдийн аль нэгийг нь

тодорхойлдог. Бид extend холбоосын ажиллагааг хангах listExtend() үйлдлийг тодорхойлох хэрэгтэй:

// apps/backend/modules/job/actions/actions.class.php

class jobActions extends autoJobActions

{

public function executeListExtend(sfWebRequest $request)

{

$job = $this->getRoute()->getObject();

$job->extend(true);

$this->getUser()->setFlash('notice', 'The selected jobs have been

extended successfully.');

$this->redirect('jobeet_job');

}

// ...

}

аctions

Бид сая нэг эсвэл олон (жагсаалт) обьект дээр хийгдэх холбоос үйлдийн тухай үзсэн билээ. Шинэ обьект үүсгэдэг холбоостой адилхан ямар нэг обьект дээр тавидаггүй үйлдлүүдийг

(үйлдлүүд)

actions боломж (option) –оор тодорхойлдог. default new үйлдлийг (action) устгаад нийтлэгчээр (ажил оруулагч) идэвхижүүлэлт хийгдэлгүй 60 –аас их өдөр болж байгаа бүх ажиллуудыг устгах шинэ үйлдэл (action) нэмцгээе:

# apps/backend/modules/job/config/generator.yml

config:

list:

actions:

deleteNeverActivated: { label: Delete never activated jobs }

Бид одоог хүртэл тодорхойлсон бүх үйлдлүүд (actions) –ээ ~ тэмдгээр тодорхойлсон. Энэ нь symfony үйлдлийг (action) автоматаар тохируулна гэсэн утгатай. Параметрын массив (array) тодорхойлсоноор үйлдлийг (action) өөрчилж болно. label боломж (option) нь symfony –н үүсгэсэн default label –г дарна.

Холбоос дээр дарахад default –аар үйлдлийн (action) нэрийн өмнө нь listгэсэн угтвар залгасан үйлдэл (action) ажиллах болно.

job модульд listDeleteNeverActivated үйлдлийг үүсгэе:

// apps/backend/modules/job/actions/actions.class.php

class jobActions extends autoJobActions

{

public function executeListDeleteNeverActivated(sfWebRequest $request)

{

$nb = Doctrine_Core::getTable('JobeetJob')->cleanup(60);

if ($nb)

{

$this->getUser()->setFlash('notice', sprintf('%d never activated jobs

have been deleted successfully.', $nb));

}

else

{

$this->getUser()->setFlash('notice', 'No job to delete.');

}

$this->redirect('jobeet_job');

}

// ...

}

Бид өчигдөр тодорхойлсон JobeetJobTable::cleanup()

v

функцыг дахин ашиглах болно. Дахин ашиглалтын өөр сайхан жишээ бол MVC загвар юм.

action параметрыг дамжуулсанаар гүйцэтгэх үйлдлийг өөрчилж болно: deleteNeverActivated: { label: Delete never activated jobs, action: foo }

table_method

Ажлын (job) жагсаалтын хуудсыг харуулахад хэрэглэгдсэн өгөгдлийн сангийн (database) –ийн хүсэлтийн тоо нь 14 байгааг web debug toolbar дээр үзүүлсэн байна.

Хэрэв та уг тоон дээр дарвал ажил (job) бүрийн хувьд категорийн нэрийг дахин авчирсан олон хүсэлт байгааг харах болно:

Query –ийн тоог цөөлөхийн тулд, бид

(хүснэгтийн функц)

table_method боломж (option) –ийг хэрэглэн ажил авч байгаа default функцыг сольж болно:

# apps/backend/modules/job/config/generator.yml

config:

list:

table_method: retrieveBackendJobList

retrieveBackendJobList() функцэнд job болон category хүснэгтүүдийг (tables) хооронд нь холбох холболт нэмсэнээр категори (category) обьект нь ажил (job) бүртэй автомат холболт үүсгэнэ.

Одоо lib/model/doctrine/JobeetJobTable.class.php. файлынJobeetJobTable –д retrieveBackendJobList функц үүсгэх хэрэгтэй.

// lib/model/doctrine/JobeetJobTable.class.php

class JobeetJobTable extends Doctrine_Table

{

public function retrieveBackendJobList(Doctrine_Query $q)

{

$rootAlias = $q->getRootAlias();

$q->leftJoin($rootAlias . '.JobeetCategory c');

return $q;

}

// ...

retrieveBackendJobList() функцэнд job болон category хүснэгтүүдийг (tables) хооронд нь холбох холболт нэмсэнээр категори (category) обьект нь ажил (job) бүртэй автомат холболт үүсгэнэ.

Одоо хүсэлтийн тоо нь дөрөв болсон байна:

Form Views Configuration (формын харагдацын тохиргоо)

Формын харагдацын тохиргоо нь form, edit, болон new гурван хэсгээс бүтнэ. Эдгээрийн тохиргоонууд үйлчлэл нь ижилхэн бөгөөд зөвхөн form хэсгийн тохиргоог хийхэд edit болон new хэсэгүүдэд нөлөөлнө.

display

Жагсаалтын хувьд display боломж (option) –оор дэлгэцэнд харагдах талбаруудыг өөрчилж байсан. Харин формыг харуулахдаа талбарыг устгах гэж оролдох хэрэггүй бөгөөд устгавал санамсаргүй оролтын алдаанууд (unexpected validation errors) үүсч болно.

Формын харагдацын display боломж (option) –г ашиглан талбаруудыг эмхлэж, групп үүсгэж болдог:

# apps/backend/modules/job/config/generator.yml

config:

form:

display:

Content: [category_id, type, company, logo, url, position, location,

description, how_to_apply, is_public, email]

Admin: [_generated_token, is_activated, expires_at]

Дээрхи тохиргоо нь

(харагдац)

Content болон Admin гэсэн хоёр групп үүсгэж, групп бүрт байх формын талбаруудыг тавьж өгсөн байна.

- Admin групп дах баганууд нь одоохондоо броузер дээр харагдахгүй байгаа, учир нь тэднийг ажил (job) формын тодорхойлолтонд харуулахгүй (unset) гэж тодорхойлсон. Админ application –ны ажил (job) формын загварыг тодорхойлоход тэдгээр нь цөөхөн харагдана.

Admin generator нь олон – олон (n-n) гэсэн холбоог дэмждэг. Категори (category) формд, танд нэр (name) , slug оруулах input box болон affiliate (элсэх)- тэй холбоотой drop-down box байгаа. Энэ хуудсанд энэ холбоог (relation) засварлах боломж байх хэрэггүй. Тиймээс үүнийг устгая (харуулахгүй болгох):

// lib/form/doctrine/JobeetCategoryForm.class.php

class JobeetCategoryForm extends BaseJobeetCategoryForm

{

public function configure()

{

unset($this['created_at'], $this['updated_at'],

$this['jobeet_affiliates_list']);

}

}

“Virtual” columns (хийсвэр баганууд)

Ажил (job) формын display боломж (options) –д _generated_tokenталбар доогуур зураастай (_) –тай үүсдэг. Энэ нь энэ талбарыг үүсгэхэд_generated_token.php partial (хэсэгхэн) загвар ашиглана гэсэн утгатай юм.

Энэ partial –ыг дараах кодоор үүсгэнэ:

// apps/backend/modules/job/templates/_generated_token.php

<div>

<label>Token</label>

<?php echo $form->getObject()->getToken() ?>

</div>

Partial –д, та тухайн форм руу хандаж ба холбоотой обьектыг getObject() функцээр хялбархан авч болно.

v Түүнчлэн компонентын үүсгэлтийг талбарын өмнө долгионтой зураас (~) тавьж төлөөлүүлж болно.

class

Администраторууд формыг хэрэглэдэг бөгөөд бид хэрэглэгчийн ажлын форм тодорхойлсоноос илүү их мэдээллийг дэлгэцэнд харна. Гэвч одоо тэдний заримыг нь

(класс)

JobeetJobForm классаас устгасан тул форм дээр харагдахгүй.

Frontend болон backend –ийн формууд нь өөр байх тул бид формын хоёр классыг үүсгэх хэрэгтэй. BackendJobeetJobForm классаас удамшсанJobeetJobForm классыг үүсгэе. Бидэнд hidden хийх (нуух) ижилхэн талбарууд байхгүй учир BackendJobeetJobForm –г дахин тодорхойлохJobeetJobForm классын функц дэх unset() зарлагааг бага зэрэг

зөөж өөрчиллөх хэрэгтэй:

// lib/form/doctrine/JobeetJobForm.class.php

class JobeetJobForm extends BaseJobeetJobForm

{

public function configure()

{

$this->removeFields();

$this->validatorSchema['email'] = new sfValidatorAnd(array(

$this->validatorSchema['email'],

new sfValidatorEmail(),

));

// ...

}

protected function removeFields()

{

unset(

$this['created_at'], $this['updated_at'],

$this['expires_at'], $this['is_activated'],

$this['token']

);

}

}

// lib/form/doctrine/BackendJobeetJobForm.class.php

class BackendJobeetJobForm extends JobeetJobForm

{

protected function removeFields()

{

unset(

$this['created_at'], $this['updated_at'],

$this['token']

);

}

}

Admin generator –ийн degfault форм классыг class боломж (option) –оор тодорхойлдог:

# apps/backend/modules/job/config/generator.yml

config:

form:

class: BackendJobeetJobForm

v Шинэ класс нэмсэний дараа кэйш устгахаа мартаж болохгүй.

The edit form still has a small annoyance. Тухайн upload хийгдсэн лого нь харагдахгүй байгаа бөгөөд түүнийг устгаж чадахгүй.sfWidgetFormInputFileEditable

// lib/form/doctrine/BackendJobeetJobForm.class.php

widget нь засварлах боломжтой файл оруулах энгийн widget –ийг нэмдэг:

class BackendJobeetJobForm extends JobeetJobForm

{

public function configure()

{

parent::configure();

$this->widgetSchema['logo'] = new sfWidgetFormInputFileEditable(array(

'label' => 'Company logo',

'file_src' => '/uploads/jobs/'.$this->getObject()->getLogo(),

'is_image' => true,

'edit_mode' => !$this->isNew(),

'template' => '<div>%file%<br />%input%<br />%delete%

%delete_label%</div>',

));

$this->validatorSchema['logo_delete'] = new sfValidatorPass();

}

// ...

}

sfWidgetFormInputFileEditable

o

widget -н харагдалт болон онцлогыг тохируулах хэдэн сонголт (option) –ыг тавьж өгнө:

file_src

o : тухайн upload хийгсэн файлын вэб зам (path)

is_image

o : хэрэв үнэн бол файлыг зураг шиг харуулна (render)

edit_mode

o : форм нь засварлах горимд эсэх

with_delete

o : устгах checkbox –г харуулах эсэх

template

Admin generator –ын харагдацаныг үүсгэгдэх template (загвар)-т

: widget харуулах загвар хэрэглэх

classболон id атрибутуудыг тодорхойлсоноор хялбархан тохируулж болно. Тухайлбал, sf_admin_form_field_logo классыг хэрэглэсэнээр лого талбарыг өөрчилж болно. Талбар бүрт түүнчлэн sf_admin_textэсвэл sf_admin_boolean гэх мэт

талбарын төрлөөс хамаарсан класс байна.

edit_mode сонголт (option) нь sfDoctrineRecord::isNew()

Хэрэв формын model обьект нь шинэ бол үнэн бусад үед худал утга буцаадаг. Та embedded обьектын төлвөөс хамаарсан өөр widget эсвэл validator –уудыг хэрэглэхэд энэ нь сайн тусламж болно.

функцыг хэрэглэдэг.

Filters Configuration (шүүлтийн тохиргоо)

Шүүлтийн тохиргоо хийх нь формын харагдацыг тохируулсантай яг адилхан. Учир нь шүүлт бол формын тухайн нэг тохиолдол юм. Формын классуудыг doctrine:build --

all коммандаар үүсгэсэн. Мөнdoctrine:build --filters коммандаар тэднийг дахин үүсгэж (re-generate) болно.

Шүүлт формын классууд нь lib/filter/ хавтсанд байрладаг ба model класс бүрийн форм класст туслах шүүлт класс байна. (JobeetJobFormклассын хувьд JobeetJobFormFilter класс).

Категори (categоry ) модулийн хувьд тэднийг бүрт устгая:

# apps/backend/modules/category/config/generator.yml

config:

filter:

class: false

Ажил ( job ) модулийн хувьд заримыг нь усгая

Actions Customization (үйлдлүүдийн өөрчлөлт)

:

# apps/backend/modules/job/config/generator.yml

filter:

display: [category_id, company, position, description, is_activated,

is_public, email, expires_at]

Шүүлт нь үргэлж туслах чанарын байдаг тул шүүлт формын классыг дахин тодорхойлогүйгээр харагдах талбаруудыг тохируулдаг.

Тохиргоо хангалтгүй үед action класст шинэ функц нэмнэ. Бид өмнө ньextend онцлогыг нэмж байсан. Мөн үүсгэгдсэн action функцуудыг дахин тодорхойлж болно:

Функц Тайлбар

executeIndex() Жагсаалт харагдацын action

Шүүлтүүдыг шинэчилнэ executeFilter()

Функц Тайлбар

executeNew() New (шинээр үүсгэх) харагдацын action

Шинэ ажил (Job) үүсгэнэ executeCreate()

executeEdit() Edit (засварлах) харагдацын action

Ажил (Job) шинэчилнэ executeUpdate()

Ажил (Job) устгана executeDelete()

batch action биелүүлнэ executeBatch()

executeBatchDelete() _delete batch action –г биелүүлнэ

Ажил форм (Job form) боловсруулах processForm()

Тухайн шүүлтүүдийг буцаана getFilters()

Шүүлт тавина setFilters()

Жагсаалт (list) pager буцаана getPager()

Хуудаслагчийн хуудасыг (paper page) авна getPage()

Хуудаслагчийн хуудасыг (paper page) тавина setPage()

Жагсаалтын (list)buildCriteria() Criteria байгуулна

Функц Тайлбар

Жагсаалтын эрэмбэлсэнaddSortCriteria() Criteria нэмнэ

Тухайн эрэмбэлсэн баганыг буцаана getSort()

Тухайн эрэмбэлэх баганыг тавина setSort()

Үүсгэгдсэн функц бүр зөвхөн нэг зүйлтэй, энэ нь олон код copy болон paste хийхгүйгээр байдлыг (behavior) өөрчлөхөд хялбар юм.

Templates Customization (загварын өөрчлөлт)

Бид admin generator нь HTML кодонд class болон id аттрибутуудыг нэмж үүсгэсэн template (загвар) –г хэрхэн өөрчилдгийг харлаа.

Мөн та классуудад оргинал template (загвар) –уудыг дахин тодорхойлж болно. Template (загвар) -ууд нь энгийн PHP файлууд болон PHP биш классууд юм. Модуль ижил нэртэй template (загвар) үүгэсэнээр template (загвар) –г дахин тодорхойлж болно (тухайлбал job админ модулийнapps/backend/modules/job/templates/ хавтсанд):

Template (загвар) Тайлбар

Темплатиүдэд хэрэглэгдэх CSS болон JS харуулна

_assets.php

filters box (шүүлт) –г харуулна _filters.php

filter (шүүлт) –н нэг field (талбар) –г үзүүлнэ

_filters_field.php

flash мессежүүдийг үзүүлнэ _flashes.php

Формыг харуулна _form.php

Template (загвар) Тайлбар

Формын action –уудыг харуулна _form_actions.php

Формын нэг field (талбар) –г харуулна _form_field.php

Формын fieldset -г харуулна _form_fieldset.php

Формын footer –г харуулна _form_footer.php

Формын header –г харуулна _form_header.php

Жагсаалт (_list.php list)-ыг харуулна

Жагсаалтын action –уудыг харуулна _list_actions.php

Жагсаалтын batch action-уудыг харуулна

_list_batch_actions.php

Жагсаалтын нэг boolean талбар (field) –г харуулна

_list_field_boolean.php

Жагсаалтын footer –г харуулна _list_footer.php

Жагсаалтын header –г харуулна _list_header.php

Мөрийн (row) обьект action –уудыг харуулна

_list_td_actions.php

Мөрийн checkbox –г харуулна _list_td_batch_actions.php

Template (загвар) Тайлбар

Мөрийн stacked layout (давхарга) –г харуулна

_list_td_stacked.php

Жагсаалтын нэг талбарыг (field) харуулна

_list_td_tabular.php

header -н нэг баганийн нэрийг харуулна

_list_th_stacked.php

header -н нэг баганийн нэрийг харуулна

_list_th_tabular.php

Жагсаалтын хуудаслалтыг харуулна _pagination.php

editSuccess.php edit харагдац (view) –г харуулна

Жагсаалтын (indexSuccess.php list) харагдацыг

харуулна

newSuccess.php new харагдацыг харуулна

Final Configuration (эцсийн тохиргоо)

Jobeet админ тохиргоо нь эцсийн байдлаар дараах шиг байна:

# apps/backend/modules/job/config/generator.yml

generator:

class: sfDoctrineGenerator

param:

model_class: JobeetJob

theme: admin

non_verbose_templates: true

with_show: false

singular: ~

plural: ~

route_prefix: jobeet_job

with_doctrine_route: true

config:

actions: ~

fields:

is_activated: { label: Activated?, help: Whether the user has

activated the job, or not }

is_public: { label: Public? }

list:

title: Job Management

layout: stacked

display: [company, position, location, url, is_activated,

email]

params: |

%%is_activated%% <small>%%JobeetCategory%%</small> - %%company%%

(<em>%%email%%</em>) is looking for a %%=position%% (%%location%%)

max_per_page: 10

sort: [expires_at, desc]

batch_actions:

_delete: ~

extend: ~

object_actions:

extend: ~

_edit: ~

_delete: ~

actions:

deleteNeverActivated: { label: Delete never activated jobs }

table_method: retrieveBackendJobList

filter:

display: [category_id, company, position, description, is_activated,

is_public, email, expires_at]

form:

class: BackendJobeetJobForm

display:

Content: [category_id, type, company, logo, url, position,

location, description, how_to_apply, is_public, email]

Admin: [_generated_token, is_activated, expires_at]

edit:

title: Editing Job "%%company%% is looking for a %%position%%"

new:

title: Job Creation

# apps/backend/modules/category/config/generator.yml

generator:

class: sfDoctrineGenerator

param:

model_class: JobeetCategory

theme: admin

non_verbose_templates: true

with_show: false

singular: ~

plural: ~

route_prefix: jobeet_category

with_doctrine_route: true

config:

actions: ~

fields: ~

list:

title: Category Management

display: [=name, slug]

batch_actions: {}

object_actions: {}

filter:

class: false

form:

actions:

_delete: ~

_list: ~

_save: ~

edit:

title: Editing Category "%%name%%"

new:

title: New Category

Бид энэ хоёр тохиргооны файлуудад цаг хугацаа зарцуулсан хүчинд агуу backend интерфэйсийг хөгжүүллээ.

v Та YAML файл дах зарим нэг тохируулгийг хялбар PHP код хэрэглэн хийх боломжтой гэдгийг мэдэж авсан байх. Admin generator –ийн хувьд,

таapps/backend/modules/job/lib/jobGeneratorConfiguration.class.phpфайлыг засварлаж болно. Энэ нь танд PHP интерфэйс дээр YAML файлынх шиг ижил боломжийг олгодог. Функцүүдийн нэрийгcache/backend/dev/modules/autoJob/lib/BaseJobGeneratorConfiguration.class.php

Final Thoughts (дүгнэлт) . – д үүсгэгдсэн base классаас харж болно.

Бид нэгхэн цагийн дотор Jobeet прожектын бүрэн гүйцэт backend интерфэйсийг байгууллаа. Бүх хэсэгт нийлээд 50 хүрэхгүй PHP кодын мөр бичсэн билээ. Иймд олон онцлогууд нь тийм ч муу биш юм!

Маргааш бид backend application –ийг хэрэглэгчийн нэр болон нууц үгээр хамгаалах тухай үзнэ. Энэ нь түүнчлэн symfony –ын user классын талаар ярих шалтгаан болно.

13 –р өдөр Хэрэглэгч Өчигдөр бид маш их мэдээлэл авсан билээ. Symfony –ийн админ үүсгэгч (admin generator) нь, PHP –ийн цөөхөн хэдэн мөр бичсэнээр бээкэнд интерфэйсүүдийг богино хугацаанд үүсгэх боломжийг хөгжүүлэгчидэд олгодог.

Өнөөдөр бид HTTP хүсэлтүүдийн (requests) хооронд Symfony хэрхэн өгөгдөл (persistent data) дамжуулдаг болохыг судлах болно. Та магадгүй НTTP протокол нь стэйтлес (stateless) гэдгийг мэдэх байх. Энэ нь, хүсэлт (request) бүр HTTP протоколын preceding эсвэл proceeding –ийн аль нэгнээс үл хамаарна гэсэн үг. Одоогийн вэб сайтуудад хэрэглэгчийн туршлагийг (user experience) нэмэгдүүлэх хүсэлтүүдийн хооронд дамжигдах өгөгдлийг хэвээр нь хадгалах арга зам хэрэгтэй байдаг.

Хэрэглэгчийн сэйшн (session) –г күүкий (cookie) ашиглан таньж болно. Symfony –д, хөгжүүлэгч нь сэйшн (session)-тэй шууд харьцах хэрэггүй бөгөөд sfUser обьектыг ашигладаг. sfUser обьект нь апликэйшний хэрэглэгчийг төлөөлдөг.

Хэрэглэгчийн флэйшүүд (User Flashes)

Бид өмнө нь хэрэглэгч обьектын флэйшүүдтэй ээкшнүүдийг харж байсан билээ. Флэйш гэдэг нь хэрэглэгчийн сэйшнд хадгалагдсан эпиминрал (ephemeral) мессэж юм. Энэ нь дараагийн хүсэлт ирэхэд автоматаар устгагддаг. Флэйш нь шууд шилжилт (redirect) хийсний дараа хэрэглэгчид мессэж харуулахад их хэрэгтэй байдаг. Ажил (job) хадгалах, устгах эсвэл сунгах гэх мэт үйлдлүүд хийхэд, админ үүсгэгч нь хэрэглэгчид feedback (хариу) харуулахдаа флэйшүүдийг ашигладаг.

sfUser обьектын setFlash методыг хэрэглэн флэйшийг тавьдаг:

// apps/frontend/modules/job/actions/actions.class.php

public function executeExtend(sfWebRequest $request)

{

$request->checkCSRFProtection();

$job = $this->getRoute()->getObject();

$this->forward404Unless($job->extend());

$this->getUser()->setFlash('notice', sprintf('Your job validity has been

extended until %s.', $job->getDateTimeObject('expires_at')-

>format('m/d/Y')));

$this->redirect($this->generateUrl('job_show_user', $job));

}

Эхний аргумент нь флэйшийн тодорхойлогч, хоёрдох аргумент нь харуулах мессэж байна. Та өөрийн хүссэн флэйшийг тодорхойлж өгөх боломжтой бөгөөд notice болон error нь ерөнхий хоёр нь юм. (Админ үүсгэгчд notice болон error нь өргөн хэрэглэгдсэн байдаг.)

Хөгжүүлэгч нь темплэйтэд флэйш мессэжийг оруулж өгнө. Jobeet –ийн хувьд, layout.php файлд оруулж өгнө:

// apps/frontend/templates/layout.php

<?php if ($sf_user->hasFlash('notice')): ?>

<div><?php echo $sf_user->getFlash('notice') ?></div>

<?php endif ?>

<?php if ($sf_user->hasFlash('error')): ?>

<div><?php echo $sf_user->getFlash('error') ?></div>

<?php endif ?>

Темплэйтэнд, тусгай $sf_user хувьсагчаар дамжуулан хэрэглэгчд хялбархан хандана.

v Темплэйтэнд symfony-ийн зарим обьектуудад, ээкшнээс (action) обьектууд руу тодорхой дамжих шаардлагагүйгээр хялбархан ханддаг: $sf_request, $sf_user болон $sf_response.

Хэрэглэгчийн аттрибутууд (User Attributes)

Харамсалтай нь, Хэрэглэгчийн сэйшнд Jobeet хэрэглэгчийн мэдээллийг хадгалах шаардлага (requirement) байхгүй. Тиймээс шинэ шаардлага (requirement) нэмцгээе: ажил үзэхийг хялбаржуулах (ease job browsing), хэрэглэгчийн хамгийн сүүлд үлдсэн гурван ажлыг үзэх холбоосыг цэсэнд харуулах.

Хэрэглэгч ажил хуудсанд (job page) хандахад дэлгэцэнд харагдаж байгаа ажил обьект нь сэйшн дэхь хэрэглэгчийн түүхэнд нэмэгдэн хадгалагддаг байх хэрэгтэй:

// apps/frontend/modules/job/actions/actions.class.php

class jobActions extends sfActions

{

public function executeShow(sfWebRequest $request)

{

$this->job = $this->getRoute()->getObject();

// fetch jobs already stored in the job history

$jobs = $this->getUser()->getAttribute('job_history', array());

// add the current job at the beginning of the array

array_unshift($jobs, $this->job->getId());

// store the new job history back into the session

$this->getUser()->setAttribute('job_history', $jobs);

}

// ...

}

v Бид JobeetJob обьектуудыг шууд сэйшнд хадгалах боломжтой юм. Гэхдээ ингэх хэрэггүй. Учир нь сэйшн хувьсагчууд нь хүсэлтүүдийн хооронд сериалайз (serialized цуваа) байдаг. Сэйшн ачаалагдахад JobeetJob обьектууд нь de-serialized байх ёстой. Хэрэв сэйшнтэй ажиллаж байх хооронд сэйшн өөрчлөгдөх юмуу эсвэл устгагдвал “стаолед” (“stalled” хашигдах, мухардах) болдог.

getAttribute(),

Ялгагчийг (identifier) тодорхойлж өгсөнөөр хэрэглэгчийн сэйшнээс sfUser::getAttribute() методоор дамжуулан утгуудыг авдаг. Урвуу үйлдэл нь, тодорхойлсон ялгагчын (identifier) сэйшнд setAttribute() методыг ашиглан ямарч PHP хувьсагчийг хадгалж болно.

Хэрэв ялгагч (identifier) нь тодорхойлогдоогүй бол getAttribute() метод нь дефаолт утгийг буцаана.

v Дефаолт утга авах getAttribute() методын шорткат нь дараахтай адил байна:

if (!$value = $this->getAttribute('job_history'))

{

$value = array();

}

setAttribute()

myUser класс (The myUser

Ажлаа хэсэглэж хуваах нь дээр байдаг бөгөөд кодоо myUser класс руу зөөцгөөе. myUser класс нь апликэйшний тусгай төлвүүдтэй symfony –ийн үндсэн sfUser классыг дахин тодорхойлно:

// apps/frontend/modules/job/actions/actions.class.php

class jobActions extends sfActions

{

public function executeShow(sfWebRequest $request)

{

$this->job = $this->getRoute()->getObject();

$this->getUser()->addJobToHistory($this->job);

}

// ...

}

class)

// apps/frontend/lib/myUser.class.php

class myUser extends sfBasicSecurityUser

{

public function addJobToHistory(JobeetJob $job)

{

$ids = $this->getAttribute('job_history', array());

if (!in_array($job->getId(), $ids))

{

array_unshift($ids, $job->getId());

$this->setAttribute('job_history', array_slice($ids, 0, 3));

}

}

}

Түүнчлэн, хэрэглэгчийн эрх нь бүх шаардлагийг хангаж байхаар кодыг өөрчилсөн байна:

o !in_array($job->getId(), $ids)

o : Тухайн ажил нь түүхт хоёр дахин хадгалагдахгүй

array_slice($ids, 0, 3)

Layout –д $sf_content хувьсагчийн өмнө дараах кодыг нэмж харуулна:

// apps/frontend/templates/layout.php

<div id="job_history">

Recent viewed jobs:

<ul>

<?php foreach ($sf_user->getJobHistory() as $job): ?>

<li>

<?php echo link_to($job->getPosition().' - '.$job->getCompany(),

'job_show_user', $job) ?>

</li>

<?php endforeach ?>

</ul>

</div>

<div>

<?php echo $sf_content ?>

</div>

Layout –д тухайн ажлын түүхийг буцаадаг getJobHistory() методыг ашигласан байна:

// apps/frontend/lib/myUser.class.php

: Хамгийн сүүлд хэрэглэгчийн үзсэн гурван ажлыг харуулна

class myUser extends sfBasicSecurityUser

{

public function getJobHistory()

{

$ids = $this->getAttribute('job_history', array());

if (!empty($ids))

{

return Doctrine_Core::getTable('JobeetJob')

->createQuery('a')

->whereIn('a.id', $ids)

->execute()

;

}

return array();

}

// ...

}

getJobHistory() метод нь Doctrine_Query обьектыг ашиглан JobeetJob обьектуудыг буцаадаг.

Ажлын түүх харуулах API –г хийж дууслаа. Одоо түүхээ ресит (reset) хийдэг методыг нэмцгээе:

// apps/frontend/lib/myUser.class.php

class myUser extends sfBasicSecurityUser

{

public function resetJobHistory()

{

$this->getAttributeHolder()->remove('job_history');

}

// ...

}

sfParameterHolder классын обьект нь хэрэглэгчийн аттрибутуудыг удирддаг. getAttribute() болон setAttribute() методууд нь

sfParameterHolder

getParameterHolder()-

>get() болон getParameterHolder()->set()методуудыг төлөөлж чадна.

Харин remove() методыг төлөөлж чадах метод sfUser обьектод байдаггүй бөгөөд

параметр холдер(parameter holder)

v

обьектыг шууд хэрэглэнэ.

sfRequest нь sfParameterHolder

Application Security классыг хэрэглэн параметрүүдийг хадгалдаг.

Authentication

Symfony –ийн бусад олон онцлогийн адилаар секюритийг security.yml YAML файлаар удирддаг. Тухайлбал, config/ директори дотор бээкэнд апликэйшний дефаолт тохиргоо байдаг.

# apps/backend/config/security.yml

default:

is_secure: false

Хэрэв is_secure оролтыг true болгож сольвол бээкэнд апликэйшн бүхлээрээ хэрэглэгч жинхэлэгдсэн (authenticated) байхыг шаардана.

v YAML файл дахь true болон false тэмдэгт мөрүүд нь бүүлиэн (boolean) утгийг илэрхийлнэ.

Вэб дебаг түүлбар дахь логуудыг харвал, таны хандахыг оролдсон хуудас бүрт defaultActions классын execureLogin() методыг дуудсан болохы

г тэмдэглэсэн байна.

Жинхэлээгүй хэрэглэгч (un-authenticated user) секюрид ээкшн (secured action) хийж хандахыг оролдох үед, symfony нь settings.yml файлд тохируулагдсан логин ээкшн рүү хүсэлтийг илгээдэг:

all:

.actions:

login_module: default

login_action: login

v Логин ээкшнийг секюри хийх боломжгүй. Энэ нь дуусашгүй рекурс болохоос зайлсхийж байгаа юм.

v Өдөр 4 –т үзсэнтэй адилаар, ижил тохиргооны файлыг хэдэн газарт тодорхойлно. Энэ нь security.yml файл юм. Модулийн config/ директори дотор, зөвхөн нэг ээкшн нь un-secure, бүхэл модулийн хувьд secure байх security.yml файл үүсгэ:

index:

is_secure: false

all:

is_secure: true

Дефаолтоор, myUser класс нь sfUser биш sfBasicSecurityUser классаас удамшсан байна. sfBasicSecurityUser

Authorization

класс нь хэрэглэгчийн authentication болон authorization –г удирдах нэмэлт методуудаар хангагдсан байдаг.

Хэрэглэгчийн authentication –г удирдахдаа, isAuthenticated() болон setAuthenticated() методуудыг ашигладаг:

if (!$this->getUser()->isAuthenticated())

{

$this->getUser()->setAuthenticated(true);

}

Хэрэглэгч authenticated хийх үед credentials (итгэмжлэх)–г тодорхойлж өгсөнөөр зарим ээкшний хандалтыг илүү хязгаарлаж болно. Хэрэглэгч хуудас руу хандахдаа шаардлагатай credentials (итгэмжлэх) –тэй байх хэрэгтэй болно:

default:

is_secure: false

credentials: admin

Symfony –ийн credential (итгэмжлэлт) –н систем нь энгийн бөгөөд маш хүчирхэг юм. Credential (итгэмжлэх) нь таны тодорхойлж өгсөн ямарч апликэйшний секюрити моделийг төлөөлж чадна (групп болон permission –уудтай адил).

Нийлмэл итгэмжлэх (Complex Credentials)

security.yml файлын credentials оролт нь нийлмэл итгэмжлэхийн шаардлагийг тодорхойлох бүүлиэн (boolean) үйлдлүүдийг дэмждэг.

Хэрэв хэрэглэгч нь A болон B итгэмжлэхтэй байх ёстой бол, дөрвөлжин хаалтаар credentials –г хаана:

index:

credentials: [A, B]

Хэрэв хэрэглэгч A эсвэл B итгэмжлэхтэй байх ёстой бол, хоёр хос дөрвөлжин хаалтаар хаана:

index:

credentials: [[A, B]]

Credentials –ийн тооноос хамаарч бүүлиэн (boolean) илэрхийлэлийн ямарч төрлийг тодорхойлсон тохирох хаалтуудыг тэгш холино.

sfBasicSecurityUser класс нь хэрэглэгчийн credentials (итгэмжлэх) –г удирдах хэдэн методоор хангадаг:

// Нэг эсвэл олон credentials нэмэх

$user->addCredential('foo');

$user->addCredentials('foo', 'bar');

// Хэрэв хэрэглэгч credential –тэй бол шалгах

echo $user->hasCredential('foo'); => true

// Хэрэглэгч хоёр credentials –тэй бол шалгах

echo $user->hasCredential(array('foo', 'bar')); => true

// Хэрэглэгч credentials –уудын аль нэгтэй бол шалгах

echo $user->hasCredential(array('foo', 'bar'), false); => true

// Credential –г устгах

$user->removeCredential('foo');

echo $user->hasCredential('foo'); => false

// Бүх credential –г устгах (logout үйлдэлд хэрэглэгддэг)

$user->clearCredentials();

echo $user->hasCredential('bar'); => false

Jobeet бээкэнд апликэйшний хувьд, бидэнд зөвхөн администратор гэсэн нэг л профайл байгаа тул бид ямар ч credentials (итгэмжлэх) хэрэглэхгүй:

Плагин (Plugins)

Дугуйг дахин зохион бүтээх хэрэггүйтэй адил, бид логин ээкшнийг хөгжүүлэхгүй. Үүний оронд, бид symfony плагин

Symfony фрэймворкын агуу хүчнүүдийн нэг нь

суулгах болно.

плагин экосистем

Өнөөдөр, бид бээкэнд апликэйшнийг хамгаалах (secure)

юм. Бид ирэх өдрүүдэд, плагин үүсгэх нь ямар хялбар зүйл болохыг үзэх болно. Плагин нь маш хүчирхэг бөгөөд модулиуд болон ассетууд (assets) –ыг тохируулах ямарч тохиргоог агуулж чадна.

sfDoctrineGuardPlugin плагиныг суулгана.

$ php symfony plugin:install sfDoctrineGuardPlugin

plugin:install

Плагины бүх боломжтой хувилбарыг symfony –ийн хувилбараар нь групп үүсгэн

таск нь плагиныг нэрээр нь суулгадаг. Бүх плагинууд plugins/ директори дотор хадгалагддаг бөгөөд плагин директори бүр нь плагины нэрээрээ нэрлэгдсэн байдаг.

v plugin:install таскыг ажиллуулахын тулд PEAR –г суулгасан байх ёстой.

plugin:install таскаар плагин суулгах үед, symfony нь плагины хамгийн сүүлийн тогтвортой хувилбарыг суулгадаг. Плагины онцгой хувилбарыг суулгахын тулд –release сонголтыг дамжуулна.

плагин хуудсанд

Плагин нь өөрөө директори дотор агуулагддаг шиг, түүнчлэн та symfony-ийн вэб сайтаас

жагсаасан байгаа.

пакежийг татаж аваад задлахад болно. Эсвэл плагины дэд хувилбарыг агуулах svn:externals холбоосыг үүсгэнэ.

plugin:install таск нь автоматаар ProjectConfiguration.class.php файлыг шинэчилж, автоматаар плагин (ууд) –ыг идэвхижүүлдэг. Гэхдээ subversion –аар эсвэл плагины архив файлыг татаж авсан тохиолдолд, ProjectConfiguration.class.php файлд плагин идэвхижүүлэлтийг та гараараа хийж өгөх хэрэгтэй:

}

// config/ProjectConfiguration.class.php

class ProjectConfiguration extends sfProjectConfiguration

{

public function setup()

{

$this->enablePlugins(array(

'sfDoctrinePlugin',

'sfDoctrineGuardPlugin'

));

}

Бээкэнд секюрити (Backend Security)

Плагин бүрт плагиныг хэрхэн тохируулахыг тайлбарласан README файл байдаг.

Одоо шинэ плагиныг хэрхэн тохируулахыг үзэцгээе. Плагин нь users, groups болон permissions –ийг удирдах нилээд хэдэн шинэ модел классуудаар хангагдсан байдаг. Та өөрийн моделийг дахин байгуулах (rebuild) хэрэгтэй:

$ php symfony doctrine:build --all --and-load --no-confirmation

v doctrine:build --all --and-load таск өмнө нь үүссэн байсан бүх хүснэгтүүдийг устгаад шинээр үүсгэдэг гэдгийг та санасан байх. Үүнээс зайлсхийхийн тулд та models, forms, болон filters –ийг үүсгээд, дараа нь data/sql/ дотор хадгалагдаж байгаа үүсгэгдсэн SQL statement-уудаар шинэ хүснэгтүүдийг үүсгэнэ.

sfDoctrineGuardPlugin нь хэрэглэгчийн класст нилээд хэдэн методуудыг нэмдэг тул та myUser классын үндсэн классыг sfGuardSecurityUser болгон өөрчлөх хэрэгтэй:

// apps/backend/lib/myUser.class.php

class myUser extends sfGuardSecurityUser

{

}

sfDoctrineGuardPlugin нь хэрэглэгчүүдийг authenticate хийхsfGuardAuth модуль

дахь signin ээкшнээр хангадаг.

Логин хуудасны дефаолт ээкшнийг өөрчилж, settings.yml файлыг засварлана:

# apps/backend/config/settings.yml

all:

.settings:

enabled_modules: [default, sfGuardAuth]

# ...

.actions:

login_module: sfGuardAuth

login_action: signin

# ...

Прожектын бүх апликэйшнууд нь плагинуудыг дундаа эзэмшдэг тул тухайн хэрэглэхийг хүсэж байгаа модулиудаа enabled_modules тохиргоонд нэмж модулиудын идэвхижүүлэлтийг тодорхой болгох хэрэгтэй.

Сүүлийн алхам бол администратор хэрэглэгч үүсгэх:

$ php symfony guard:create-user fabien SecretPass

$ php symfony guard:promote fabien

v Хэрэв subversion trunk –аас sfDoctrineGuardPlugin плагиныг суулгасан бол та дараах нэг коммандаар хэрэглэгч үүсгэж, promote (эрх нэмэх) хийнэ:

$ php symfony guard:create-user [email protected] fabien SecretPass Fabien

Potencier

TIP sfGuardPlugin нь коммандын мөрнөөс users, groups, болон permissions –г удирдах таскуудаар хангагдсан байдаг. list таскыг хэрэглэсэнээр guard namespace –д хамаарах бүх таскуудыг жагсаана:

$ php symfony list guard

Хэрэглэгч authenticated хийгдээгүй үед, бид цэсийн хэсгийг нуух хэрэгтэй:

// apps/backend/templates/layout.php

<?php if ($sf_user->isAuthenticated()): ?>

<div id="menu">

<ul>

<li><?php echo link_to('Jobs', 'jobeet_job') ?></li>

<li><?php echo link_to('Categories', 'jobeet_category') ?></li>

</ul>

</div>

<?php endif ?>

Хэрэглэгч authenticated хийгдсэн үед, бид цэсэнд гарах (logout) холбоосыг нэмэх хэрэгтэй:

// apps/backend/templates/layout.php

<li><?php echo link_to('Logout', 'sf_guard_signout') ?></li>

v app:routes таскыг хэрэглэж, sfDoctrineGuardPlugin плагины бүхroutes –г харна.

Jobeet бээкэнд апликэйшнийг илүү сайжруулж, администратор хэрэглэгчидийг удирдах шинэ модуль нэмцгээе. Талархууштай, Плагин нь модулиар хангадаг. sfGuardAuth модулийн хувьд түүнийг settings.yml файлд идэвхижүүлэх хэрэгтэй:

// apps/backend/config/settings.yml

all:

.settings:

enabled_modules: [default, sfGuardAuth, sfGuardUser]

Цэсэнд шинэ холбоос нэмэе:

// apps/backend/templates/layout.php

<li><?php echo link_to('Users', 'sf_guard_user') ?></li>

Бид дууслаа!

Хэрэглэгчийн тестчилэл (User Testing)

Өдөр 13 хараахан дуусаагүй, учир нь бид хэрэглэгчийн тестчилэлийн талаар ярилцаагүй байгаа билээ. Symfony browser нь күүкий (cookie) –нүүдийг үзүүлэх болно. sfTesterUser тестер built-in –г ашиглан хэрэглэгчийн төлвүүдийг тестлэх нь тун хялбархан юм.

Бидний одоог хүртэл нэмж ирсэн, цэсний онцлогт зориулсан функцианаль тестүүдийг шинэчилцгээе. Ажил (job) модулийн функцианаль тестүүдийн төгсгөлд дараах кодыг нэм:

// test/functional/frontend/jobActionsTest.php

$browser->

info('4 - User job history')->

loadData()->

restart()->

info(' 4.1 - When the user access a job, it is added to its history')->

get('/')->

click('Web Developer', array(), array('position' => 1))->

get('/')->

with('user')->begin()->

isAttribute('job_history', array($browser->getMostRecentProgrammingJob()-

>getId()))->

end()->

info(' 4.2 - A job is not added twice in the history')->

click('Web Developer', array(), array('position' => 1))->

get('/')->

with('user')->begin()->

isAttribute('job_history', array($browser->getMostRecentProgrammingJob()-

>getId()))->

end()

;

Тестчилэлийг хялбаржуулахын тулд, бид эхлээд fixtures өгөгдлийг дахин ачаалаад (reload), дараа нь броузерыг дахин ачаалсанаар (restart) сэйшнийг цэвэрлэж ажлуулна.

isAttribute() метод нь хэрэглэгчийн өгөгдсөн атрибутыг шалгадаг.

v Мөн түүнчлэн, sfTesterUser тестер нь хэрэглэгчийн authentication болон autorizations –г тестчилэх isAuthenticated() болонhasCredential()

Дүгнэлт (Final Thoughts) методуудаар хангадаг.

Symfony-ийн хэрэглэгчийн классууд нь PHP сэйшн удирдлагийг хийсвэрлэх сайхан арга юм. Бид хэдхэн минутын дотор Jobeet-н бээкэнд апликэйшнийг Symfony-ийн агуу плагин систем болон sfGuardPlugin плагины хослолоор хамгааллаа. Мөн бид өөрийн администратор хэрэглэгчидийг чөлөөтэй удирдах цэвэрхэн интерфэйсийг нэмсэн. Плагины модулиудад баярлалаа.