Website Pentru Rezervarea Biletelor
CUPRINS
Limbajul de programare PHP
Dezvoltarea limbajului PHP a început în anul 1994, când dezvoltatorul Rasmus Lerdorf a scris o serie de Common Gateway Interface (CGI), care erau scripturi Perl, pe care le-a folosit pentru a menține pagina sa personală. Instrumentele au realizat sarcini, cum ar fi afișarea CV-ul său și înregistrarea traficului de pe website-ul lui. El a rescris aceste script-uri în C pentru motive de performanță, extinzându-le pentru a adăuga capacitatea de a lucra cu formularele și pentru a comunica cu bazele de date, și a numit implementarea aceasta “Personal Home Page / Forms Interpreter” sau PHP / FI.
PHP este un limbaj de programare folosit pentru dezvoltarea paginilor dinamice și aplicațiilor web. Codul PHP poate fi amestecat simplu cu cod HTML sau poate fi folosit în combinație cu un template engine sau web framework. Codul PHP este încorporat între niște instrucțiuni de procesare de început și de sfârșit speciale <?php și ?>, care permit intrarea și ieșirea din modul PHP. PHP este axat în principal pe scripting de partea server-ului. După ce codul PHP este interpretat și executat, serverul de web trimite clientului rezultatul. Clientul va primi rezultatele rulării scriptului PHP, fără a putea cunoaște codul ce stă la bază. De exemplu, codul PHP poate genera o pagină întreagă de web, o imagine sau alte date. Permite crearea coșurilor de cumpărături online pentru site-urile de e-commerce.
Limbajul PHP este în esență un supliment pentru HTML, pentru că o mulțime de sarcini pot fi efectuate de către codul PHP, de care scripturile client-side nu sunt capabile, cum ar fi autentificarea, managementul bazei de date, gestionarea fișierelor și altele. Practic, generează un fișier de ieșire într-un fișier de intrare. Cel mai des data de ieșire va fi HTML, deși ar putea fi JSON, XML sau date binare, cum ar fi imagini sau audio.
Folosirea limbajului PHP reduce timpul de a crea site-uri de mari dimensiuni. Ajută la crearea unei experiențe de utilizare personalizată pentru vizitatori pe baza informațiilor care sunt adunate de la ei.
PHP poate fi utilizat pe toate sistemele de operare majore, ca UNIX, Linux, Windows sau Mac OS X și poate interacționa cu majoritatea serverelor web. Codul PHP este interpretat de serverul web și generează un cod HTML care va fi văzut de utilizator.
Începând de la versiunea 4.3.0 include și modul “linie de comandă” (CLI), permițând crearea aplicațiilor independente. Începând cu versiunea 5.3 limbajul PHP colectează gunoiul, adică curețe obiectele memorate și alte variabile care nu vor mai fi necesare.
PHP stochează numere întregi într-un interval dependent de platformă, fie un 64-bit sau 32-bit întreg cu semn. Numerele întregi fără semn sunt convertite la valori semnate în anumite situații. Acest comportament este diferit de alte limbaje de programare. Variabile întregi pot fi atribuite folosind notații zecimale (pozitive și negative), octale, hexazecimale și binare.
Numerele cu virgulă mobilă sunt, de asemenea, stocate într-un interval specific platformei. Ele pot fi specificate folosind notația cu virgulă mobilă, sau două forme de notație științifică. PHP are un tip boolean nativ, care este similar cu tipurile boolean native în C++ și Java. Folosind regulile de conversie, valori diferite de zero sunt interpretate ca și adevărat (true) și valorile de zero ca și fals (false), la fel ca în Perl și C++. Tipul de date nul reprezintă o variabilă care nu are nicio valoare. Numai valoarea NULL este permis pentru acest tip de date. Variabilele de tip “resursă” reprezintă o referință la resurse din surse externe. Acestea sunt de obicei create de funcții de la o anumită extensie, și pot fi prelucrate doar de funcții de la aceeași extensie, ca de exemplu fișiere sau imagini. O matrice poate conține elemente de orice tip care sunt suportate de PHP, inclusiv alte resurse, obiecte și chiar și alte matrici. PHP susține, de asemenea, siruri de caractere, care pot fi utilizate cu ghilimele simple, ghilimele duble, sintaxa nowdoc sau heredoc.
Funcționalitatea de bază de programare orientată pe obiecte a fost adăugată în PHP 3 și îmbunătățită în PHP 4. Manipularea obiectelor a fost complet rescrisă în PHP 5, extinzând setul de caracteristici și îmbunătățind performanța. În versiunile anterioare ale limbajului PHP, obiectele au fost tratate ca tipuri de valoare. Dezavantajul acestei metode este că întregul obiect era copiat atunci când o variabilă a fost atribuită sau a transmisă ca un parametru la o metodă.
PHP 5 a introdus variabile și metode private și protejate, împreună cu clase abstracte, clase finale, metode abstracte și metode finale. Acesta a introdus, de asemenea, o modalitate standard de constructori și destructori, similare cu cea din alte limbi orientate de obiecte, cum ar fi C#, și un model standard de manipularea excepțiilor. În plus, PHP 5 adăugat interfețe și a permis mai multor interfețe să fie implementate. Sunt interfețe speciale care permit obiectelor să interacționeze cu sistemul de rulare.
Drupal
Despre Drupal
Drupal este un pachet de software gratuit care permite organizarea, gestionarea și publicarea conținutului cu ușurință, cu o varietate nesfârșită de personalizare. Se numește un sistem de administrare a conținutului.
Drupal este un sistem modular open source, un cadru de dezvoltare pentru aplicații web și motor pentru blogging. Este scris în limbajul PHP, dar instalarea, dezvoltarea și întreținerea unui site creat de Drupal nu necesită neaparat cunoștințe de programare în limbajul PHP. Drupal este menținut și dezvoltat de o comunitate de mai mult de 630.000 utilizatori și dezvoltatori. Este distribuit sub termenii GNU General Public License sau “GPL”, ceea ce înseamnă că oricine este liber să-l descarcă și să o folosească. Principiile proiectului Drupal încurajează modularitatea, standardizarea, colaborarea și ușurinta de utilizare.
Dries Buytaert a început să implementeze software-ul Drupal ca un mesaj de bord în 1999. În termen de un an sau cam așa ceva, mai mulți oameni au devenit interesați de utilizarea lui și de a contribui la Drupal, astfel încât proiectul a fost făcut open source.
Valorile apreciate a sistemului Drupal sunt următoarele: flexibilitatea, simplitatea, utilitatea; lucrul în echipă și inovație; modularitatea, extensibilitatea și întreținerea codului.
Sistemul Drupal conține module de bază, aceasta include module de înregistrarea și gestionarea utilizatorilor, gestionarea meniurilor și a conținutului, administrarea sistemului.
Versiunea cea mai recentă a sistemului Drupal este 7.28, care a fost lansat în 8 mai 2014. O mulțime de modificări au fost introduse în Drupal 7 față de Drupal 6. Are noi cerințe minime legate de sistem: baza de date trebuie să fie MySQL 5.0.15 sau PostgreSQL 8.3, necesită PHP 5.2 sau o versiune mai mare și memorie PHP 40M – 64M. Schimbările legat de Securitate sunt: o implementare mai sigură pentru sarcini programate (cron.php), un sistem mai sigur pentru parole și logare, iar modulele pot fi actualizate prin web.
Link-uri administrative pentru a edita elementele paginii existente sunt acum disponibile pe fiecare pagină web, fără a fi nevoie de a merge la o pagină de administrare în primul rând. Suportul este îmbunătățit pentru integrarea editoarelor WYSIWYG. Au fost adăugat mai mult drag-and-drop pentru sarcinile administrative. Permisiunile au capacitatea de a gestiona mai multe meta date, adică permisiuni au o descriere. Primul user este creat ca parte a procesului de instalare. Aceasta este userul admin. Configurarea sarcinilor automatizate poate fi realizat fără a instala orice script-uri pe serverul de web. “Input formats” a fost redenumit să fie “text formats”. Permisiunile legate de formatare de text au fost mutate la pagina principală de permisiuni. Au fost adăugate “file vertical”, o componentă de interfață reutilizabil, care oferă rezumate automate și crește gradul de uzabilitate. A fost eliminat setarea temelor proprii pentru utilizatori, dar module contribuite cu funcționalitate similară sunt disponibile. A fost adăugat un nou modul numit “Shortcuts” pentru a permite utilizatorilor de a crea propriul meniu lor pentru paginile pe care le vizitează cel mai mult.
Au fost adăugate constructori de interogare pentru INSERT, UPDATE, DELETE, MERGE și SELECT interogări, suport pentru replicare master / slave, tranzacții, interogări multi-insera, insertii întârziate, și alte caracteristici. A fost implementat suport pentru motorul de baze de date SQLite.
Fișierele sunt obiecte Drupal cu file_load(), file_save() și file_validate() funcții și hook-urile corespunzătoare. A fost adăugat un câmp special pentru încărcarea fișierelor, furnizate anterior de modulul contribuit “FileField”. Manipulare imaginilor a fost îmbunătățită, inclusiv suportul mai bun pentru add-on image librării. Tot așa, a fost adăugat un câmp special pentru încărcarea imaginilor, furnizate anterior de către modulul contribuit “ImageField”.
Au fost implementate mai multe îmbunătățiri de performanță și suport mai bun pentru instalații multisite, suport mai bun pentru optimizarea pentru motoare de căutare.
Sistemul modular
Prin sistem modular înțelegem înpărțirea sistemului în componente separate care pot fi create independent și apoi folosite în alte componente pentru a completa diferite operații. Un sistem modular este caracterizat prin ușurința de modificare pentru a obține transparența tehnologiei și a face uz de standardele industriale pentru interfețe-cheie, partiționarea funcțională în module distincte, reutilizabile și scalabile compuse din elemente funcționale izolate și utilizarea riguroasă a interfețelor modulare bine definite, inclusiv descrierea orientată pe obiecte a funcționalitatea modulului. Designul modular este o încercare de a combina avantajele de standardizare cu cele de personalizare. Volumul ridicat în mod normal este egal cu costurile reduse de producție. În afara costului redus și flexibilitatei în design, modularitatea oferă și alte beneficii ca și augmentare, care înseamnă adăugarea de noi soluții prin simpla adăugarea a unui modul nou.
Dezavantajul modularității este faptul că sistemele modulare nu sunt optimizate pentru performanță. Acest lucru depinde de gradul de modularitate.
Nucleul Drupalului include module opționale care pot fi activate de către administratorul site-ului pentru a extinde funcționalitatea site-ului. Distribuția de bază Drupal oferă mai multe funții cum ar fi: bloguri, cărți, comentarii, forumuri, sondaje, căutare avansată, sistem de meniuri multi-nivel, profile pentru utilizatori, caching și supraîncărcarea caracteristică pentru o performanță îmbunătățită.
Module contribuite
Module contribuite oferă caracteristici suplimentare sau alternative ca de exemplu galerii de imagini, tipuri de conținut personalizat și listări de conținut, editoare WYSIWYG, mesagerie privată, instrumente de integrare de la terți, și multe altele. În februarie 2014, site-ul Drupal enumeră mai mult de 25,500 de module contribuite. Unele dintre modulele contribuite cel mai frecvent utilizate includ “Content Construction Kit” (CCK), care permite administratorilor site-ului crearea dinamică a tipurilor de conținut prin extinderea schemei bazei de date. "Tip de conținut", descrie tipul informației. Tipurile de conținut includ, dar nu sunt limitate la, evenimente, invitații, recenzii, articole și produse. În Drupal 7 CCK Fields API este în nucleu, dar în Drupal 6 încă nu a făcut parte nucleului.
Un alt modul utilizat frecvent este modulul “Token”. Token-uri sunt mici bucăți de text care pot fi plasate în documente mai mari, prin substituenți simpli, cum ar fi %site-name sau [user]. Modulul “Token” oferă un API central pentru module de a utiliza aceste token-uri și expune propriile sale valori simbolice. Modulul “Token” nu oferă funcții vizibile pentru utilizatori, oferă doar servicii de manipulare simbolice pentru alte module.
Un alt modul folosit frecvent estcvent este modulul “CAPTCHA”. Un CAPTCHA este un test de provocare-răspuns cel mai des plasate în formulare web pentru a determina dacă utilizatorul este uman. Scopul CAPTCHA-ului este de a bloca completarea formularelor de spamboți, care sunt script-uri automate care posta conținut spam. Modulul “CAPTCHA” oferă această caracteristică la aproape orice utilizator care se confruntă formular web pe un site Drupal. Un alt modul similar este modulul “reCAPTCHA”, care depinde de modulul “CAPTCHA”. Acest modul folosește serviciul web reCAPTCHA pentru a îmbunătăți sistemul CAPTCHA și proteja adresele de e-mail. Sunt și niște alternative pentru acest modul, ca de exemplu modulul “Mollom” sau modulul “Honeypot”
Date
Modulul “Date” conține un tip de câmp flexibil pentru date și timp și un API pe care alte module pot folosi. Cel mai nou cod include două module noi, “Date Repeat Field”, un modul pentru a crea câmpuri de acest tip care folosesc Data Repeat API și “Date All Day”, un modul de a manipulare valorile pentru o ziua întreagă. Anterior ambele au fost incluse în modulul de bază “Date”, dar s-au scos pentru a simplifica codul și a face posibil pentru a le dezactiva. De asemenea, ele servesc ca exemple de modul în care alte module pot interveni pentru a modifica data de procesare. Nu există suport pentru modulul “Token” în Drupal 7.
Există posibilitatea de a alege și de a crea o dată ISO sau un unix timestamp. Fiecare are niște avantaje și dezavantaje. Datele de tip ISO sunt stocate în baza de date în format ISO, adică YYYY-MM-DDTHH:MM:SS. Această este un format ușor de ințeles de către oameni. Poate fi folosit pentru datele incomplete, de exemplu, doar un an sau doar un an și o lună, și alte valorile devin zero, deci nu pare a fi mai precis decât este în realitate. Este un format care este recunoscut pe plan internațional și este folosit pe mai multe site-uri web și în multe aplicații. Datele în forma unix timestamp sunt stocate în baza de date ca un integer, deci ocupă mai puțin spațiu în baza de date, deoarece este mai mic. De multe ori este mai ușor de utilizat pentru calcule deoarece se poate mări sau micșora doar prin adăugarea sau scăderea secundelor. Acesta este formatul folosit de funcțiile de data php. Acesta trebuie să fie umplut cu o dată complet – an, lună, zi, oră, minut, secundă, deci va trebui uneori să fie stabilite în mod arbitrar unele dintre aceste valori, chiar dacă acestea nu sunt aplicabile.
Sunt mai multe widget-uri pentru a alege modul în care utilizatorii pot introduce date pentru acest domeniu. Widget-ul de date “Text Field” utilizează un format personalizat stabilit în setările câmpului, cum ar fi “09.07.2014”. Ca o rezervă widget-ul va încerca să accepte textul introdus permis de funcția PHP “strtotime”. Acest lucru permite utilizatorului să tastează o dată în mai multe formate naturale, cum ar fi “July 9, 2014”. Există limitări la “strtotime”, astfel stabilind un format personalizat este mult mai fiabil. Funcția “strtotime” va asuma că datele sunt în format american LL / ZZ / AA și nu va funcționa pentru datele înainte de 1970.
Widget-ul de date “Select List” prezintă utilizatorilor o listă drop-down sau textfield pentru fiecare parte de dată, adică anul, luna, ziua, ora, etc. Întreaga selectorul este prăbușit pe o singură linie, folosind CSS. Selectorul este extrem de configurabil și se poate să fie configurat pentru a utiliza intervale de 5, 10 sau 15 minute pentru minute și secunde, sau de a face unele părți de tip textfield în loc de drop-down-uri, utile pentru a permite orice an, fără a crea un selector drop-down imens.
Widget-ul “Javascript Pop-up Calendar” este oferit ca o alternativă de intrare în cazul în care este instalat modulul “Popup Date”. Data este împărțit în câmpuri pentru data și ora, iar câmpul pentu data folosește un calendar pop-up jQuery și câmpul pentru timp folosește un widget jQuery numit “timeselector”, care permite numai intrarea timpurilor valide.
Chaos tools suite
Această suită este în primul rând un set de API-uri și instrumente pentru a îmbunătăți experiența de dezvoltator. Acesta conține, de asemenea, un modul numit “Page Manager” a căror sarcină este gestionarea paginilor. În special, gestionează pagini panou, dar pe măsură ce crește, va fi capabil de a gestiona mult mai mult decât doar panouri. Anumite metode de a face lucruri, în special cu AJAX, obiecte exportabile și un sistem plugin sunt utile în afară de doar Views și Panels. Acest modul nu oferă aproape nimic direct pentru utilizatorul final, dar în schimb, creează o bibliotecă pentru alte module de a o utiliza.
Instrumentul de plugin-uri permite unui modul permiterea altor modulelor și temelor oferirea plugin-urilor care oferă un fel de funcționalitate sau un fel de sarcină. De exemplu, în “Panels” există mai multe tipuri de plugin-uri: tipuri de conținut, care sunt ca blocuri, layouts, care sunt aspectele de pagină, și stiluri, care pot fi folosite pentru stilul unui panou. Fiecare plugin este reprezentată de un fișier de tip .inc. Un modul care folosește plugin-uri se poate implementa un hook, care descrie plugin-ul. Aceasta nu este necesar, pentru că valorile vor fi completate cu valori prestabilite. Apoi apelează o funcție ctools, care încarcă fie toate plugin-urile cunoscute folosite, pentru listare / alegere, sau un plugin specific. Din punctul de vedere al sistemului de plugin, un plugin este un pachet de date, de obicei, niște informații și o listă de callback-uri. Un modul care implementează plugin-uri trebuie să implementeze mai întâi funcția hook_ctools_plugin_directory, care pur și simplu arată sistemului care plugin-uri sunt susținute și de în ce foldere să le caute. Fiecare plugin va fi într-o separat fișier de tip .inc. Fișierul .inc va conține un hook numit special, care returnează datele necesare pentru implementarea plugin-ului.
Există două piese principale în utilizarea plugin-urilor. Primul este obținerea datelor, iar a doua este utilizarea datelor. Pentru a defini un plugin nou mai întâi trebuie să fie implementată hook_ctools_plugin_type(), pentru a spune sistemului despre plugin-ul.
Următoarele informații pot fi specificate pentru fiecare tip de plugin:
cache, implicit este FALSE. Dacă este setat la TRUE, rezultatele funcției ctools_get_plugins vor fi stocate în tabelul “cache”, prevenind astfel fișiere .inc să fie încărcate. Hook-ul ctools_get_plugins căutând un anumit plugin va încărca întotdeauna fișierul .inc adecvat.
cache table, implicit este “cache”. În cazul în care “cache” este TRUE, atunci această valoare specifică tabelul cache în care vor fi stocate informațiile.
defaults, implicit este array(). O serie de valori implicite, care ar trebui să fie adăugate fiecărui plugin. Aceasta poate fi folosită pentru a se asigura că fiecare extensie are datele de bază necesare.
load themes, implicit este FALSE. Dacă este setat la TRUE, atunci plugin-uri de acest tip pot fi furnizate de teme precum și de module. Dacă acesta este cazul, toate temele care sunt în prezent activate va oferi un plugin. Temele stabilite prin variabila $custom_theme nu trebuie neapărat să fiu activate.
hook, implicit are o valoare dinamică. Acesta conține numele hook-ului, care este folosit pentru a colecta date pentru acest plugin. În mod normal, acest lucru este $modul . “_” . $tip, dar acest lucru poate fi schimbat aici.
process, implicit este “”, un string gol. Acest lucru poate fi folosit pentru a furniza setările automate, care trebuie să fie calculate pe instanță de plugin; de exemplu, nu este suficient să fie adăugată pur și simplu o matrice prin “defaults”. Parametrii acestui callback sunt: callback(&$plugin, $info), unde $plugin este o referință la plugin-ul, iar $info este rezultatul complet prelucrat de hook_ctools_plugin_api_info ().
extension, implicit este “inc”. Poate fi folosit pentru a schimba extensia fișierelor care conțin plugin-uri de acest tip. În mod implicit, extensia va fi “inc”, deși se va seta implicit la “info” dacă “info fole” este setat la true. Nu trebuie să fie inclus punctul în extinderea, acesta va fi adăugat în mod automat.
info file, implicit este FALSE. Dacă este setat la TRUE, atunci plugin-ul va căuta un fișier de top .info în loc de un fișier de .inc. Aceasta va arăta exact la fel, deși, evident, un fișier de .info nu poate conține funcții. Acest lucru poate fi bun pentru stilurile care nu are nevoie de cod.
use hooks, implicit este TRUE. Poate fi utilizați pentru a activa suportul pentru hook-uri de definiție pentru plugin în loc de fișiere de definiție pentru plugin. Folosirea unui hook de definiție central este mai puțin optimă pentru sistemul de plugin-uri, și, ca atare, acest lucru va fi setat implicit la FALSE în versiunile ulterioare.
child plugins, implicit este FALSE. Dacă este setat la TRUE, tipul plugin-ului poate avea în mod automat “plugin-uri copii”, ceea ce înseamnă că fiecare plugin poate oferi de fapt, mai multe plugin-uri. Acest lucru este folosit in principal pentru plugin-uri care stochează o parte din informațiile lor în baza de date, cum ar fi views, blocks sau versiuni personalizate exportabile plugin-ului. Pentru a implementa, fiecare plugin poate avea un “get child” și “get children” callback. Ambele ar trebui să fie implementate pentru motive de performanță, pentru a evita obținerea tuturor copiilor, dacă nu este necesar, dar în cazul în care “get child” nu este implementată, “get children” va fi apelată. Plugin-uri copii ar trebui să fie numite părinte:copil, : fiind separatorul. Metoda “get children” trebuie cel puțin să se întoarcă plugin-ul părinte. Argumentele metodei “get children” sunt $plugin și $parent, iar și argumentele metodei “get child” sunt $plugin, $parent și $child.
Fiecare plugin returnează un pachet de date. Este garantat că fiecare plugin va avea întotdeauna următoarele date: nume, modul, fișier și cale. Numele plugin-ului este, de asemenea, cheia în matrice, care conține lista completă de plugin-uri. Modulul conține modulul, care furnizează plugin-ul, iar fișierul conține fișierul actual conține plugin-ul. Calea conține calea către fișierul, care conține plugin-ul. Acest lucru este util pentru utilizarea fișierelor secundare, cum ar fi template-uri, fișiere CSS sau imagini.
Form wizard-ul sau formularul multi-pas este un proces, care este utilizat pentru a crea un singur obiect sau a efectua o singură sarcină folosind mai multe formulare. În mod tradițional este dificil în Drupal să fie creat un astefel de formular multi-pas, deoarece nu există nici un loc unde se poate pune date între formulare. Acest instrumentul permite un singur punct de intrare pentru a crea cu ușurință un wizard alcătuit din mai multe formulare, oferă callback, care se ocupă cu stocarea datelor și face actualizări între forme și când formularele sunt completate. Acest instrument merge bine cu instrumentul “object cache” pentru depozitarea datelor.
Wizard-ul pornește cu o serie de date, care descrie toate formularele disponibile pentru wizard și stabilește opțiuni pentru modul în care wizard-ul va fi prezentat. Următoarele sunt elementele, care pot apărea în matricea info:
id, care este un ID pentru wizard. Acest lucru este folosit ca un hook pentru a boteza în mod automat callback-urile, precum și funcția, care se ocupă cu construirea unui pas din formular.
path, care este utilizat pentru redirecționarea între formulare. %step va fi înlocuit cu cheia pentru formular.
return path, care este folosit atunci când un formular este completat. Acest lucru este necesar în cazul în care butonul de “return” este apăsat și nu este folosit AJAX. Este de asemenea folosit pentru butonul “finish”. În cazul în care nu este prezent, calea specificată pentru “cancel” va fi verificată.
cancel path, care este apelat când un formular este anulat. Acest lucru este necesar în cazul în care butonul “cancel” este apăsat și nu este folosit AJAX.
show trail, care dacă este setat la TRUE, traseul formularului va fi afișat ca un breadcrumb în partea de sus a fiecărui formular. Implicit este setat la FALSE.
show back, care dacă este setat la TRUE, afișează un buton “back” pe fiecare formular. Implicit este setat la FALSE.
show return, care dacă este setat la TRUE, afișează un buton “return” pe fiecare formular. Implicit este setat la FALSE.
show cancel, care dacă este setat la TRUE, afișează un buton “cancel” pe fiecare formular. Implicit este setat la FALSE.
back text, care setează textul butonului “back”. Implicit este setat la t(‘Back’).
next text, care setează textul butonului “next”. Implicit este setat la t(‘Continue’).
return text, care setează textul butonului “return”. Implicit este setat la t(‘Update and return’).
finish text, care setează textul butonului “finish”. Implicit este setat la t(‘Finish’).
cancel text, care setează textul butonului “cancel”. Implicit este setat la t(‘Cancel’).
ajax, care pornește capacitățile AJAX, folosind fișierul ajax.inc. Implicit este setat la FALSE.
modal, care pune wizard-ul într-un instrument modal. Modal trebuie să fie deja deschisă și apelată de un buton pentru ca aceasta să funcționeze, dar este ușor de realizat cu ajutorul funcțiilor oferite de instrumentul modal.
ajax render, care este un callback pentru a afișa formularul prin ajax. Acest lucru nu este necesar în cazul în care formularul este afișat cu ajutorul funcției modal, dar altfel trebuie să fie specificat pentru că AJAX-ul în sine nu știe cum să producă un rezultat afișabil. Parametriile funcției sunt &$form_state și $output.
finish callback, care este un callback apelat când un formular este completat și butonul de “finish” a fost apăsat. Această funcție ar trebui să finalizeze toate datele. Parametrul funcției este &$form_state. Implicit este setat la $form_info[‘id’] . ‘_finish’ dacă există funcția.
cancel callback, care este un callback apelat când un formular este anulat de către utilizator. Această funcție ar trebui să curețe datele care sunt stocate în cache. Parametrul funcției este &$form_state. Implicit este setat la $form_info[‘id’] . ‘_cancel’ dacă există funcția.
return callback, care este funcția apelată atunci când un formular este completat și butonul “return” a fost apăsat. Acesta este de multe ori aceeași callback ca și callback-ul de la “finish”. Parametrul funcției este &$form_state. Implicit este setat la $form_info[‘id’] . ‘_return’ dacă există funcția.
next callback, care este funcția apelată când butonul “next” a fost apăsat. Această funcție ar trebui să pune datele în cache. Parametrul funcției este &$form_state. Implicit este setat la $form_info[‘id’] . ‘_next’ dacă există funcția.
order, care este o matrice opțională, care reprezintă ordinea implicită a formularelor. Dacă nu este setată, atunci matricea din “forms” va controla ordinea.
forms, care este o matrice care conține alte matrici, descriind fiecare formular disponibil pentru wizard. Fiecare matrice conține:
form id, care este ID-ul formularului. Aceasta este, de asemenea, numele funcției care reprezintă constructorul formularului. Implicit este setat la $form_info[‘id’]. ‘_’ . $step . ‘_form’.
include, care este numele unui fișier care conține codul pentru formular. Acest lucru trebuie să fie calea completă a fișierului. Acesta poate fi, de asemenea, o serie de fișiere în cazul în care mai multe fișiere trebuie să fie incluse.
titlu, care conține titlul formularului. Acesta este necesar atunci când se utilizează modal-ul și $form_state[“title”] nu este setat.
CTools Object Cache diferă de la mecanismul standard de cache folosit în Drupal, care este volatilă, ceea ce înseamnă că datele pot fi șterse în orice moment și este de așteptat ca orice date din cache pot fi ușor reconstruite. În schimb, datele stocate în această memorie cache nu este de așteptat să fie întregibile. Acesta este utilizat în principal pentru a stoca datele introduse de utilizator, care este preluat în etape, pentru a permite mai multe interacțiuni. Obiectul cache este format din 3 funcții normale de întreținere cache, și 2 funcții suplimentare pentru a facilita blocare. Pentru a utiliza oricare dintre aceste funcții, trebuie să fie incluse mai întâi cu ctools_include(‘object-cache’).
Entity API
Acest modul extinde API-ul din Drupal pentru entități, și are scopul de a oferi un mod unificat de a lucra cu entități și proprietățile lor. În plus, acesta oferă un controler CRUD pentru entități, care ajută la simplificarea crearea de noi tipuri de entități. Acesta este un modul API, așa că nu oferă caracteristici utilizatorilor finali. Cu toate acestea, ea oferă funcționalități generice pentru alte module: un plugin pentru Views care se leagă de orice entitate (de către view-mode), un plugin CTools pentru randarea oricărui entitate (de către view-mode). Acesta vine cu modulul “Entity tokens”, care asigură că există token-uri pentru cele mai multe proprietăți și câmpuri, adică oferă înlocuiri simbolice pentru toate proprietățile, care nu au token-uri și sunt cunoscute de modul.
Modulul oferă funcții API care permit modulelor crearea, salvarea, ștergerea și vizualizarea sau determinarea accesului pentru orice entitate, cu funcțiile entity_create(), entity_save(), entity_delete(), entity_view() și entity_access(). Funcțiile entity_load(), entity_label() și entity_uri() sunt deja furnizate de către nucleul lui Drupal. API-ul introduce un loc unic pentru metadate despre relațiile dintre entități și proprietățile entităților: hook_entity_property_info(). Aceste informații despre proprietățile entității conțin tipul de date și callback-ul pentru a obține și a stabili datele de o proprietate. Modulele se pot baza pe aceste informații, cu scopul de a suporta orice fel de proprietate, de exemplu, Rules și Search API au fost construite pe acesta.
Modulul se ajută la definirea unui nou tip de entitate. Pentru acesta oferă un controller pentru entități, care implemetează o funcționalitate completă CRUD pentru entități. Opțional, entitățile pot fi create pe baza clasei derivate din clasa furnizată ‘Entity’. Modulul ajută la crearea entităților “fieldable”, opțional revivizionabile, precum și exportabile. În plus, acesta susține implementarea bundle-urilor de entități, adică pachete de obiecte, cum ar fi tipurile de noduri, pentru entitățile fieldable implementat, pentru care callback-urile corespunzătoare sunt invocate în mod automat. Pentru tipurile de elemente implementate bazate pe CRUD API acesta furnizează alte integrări, de exemplu sunt asigurate evenimente pentru “Rules” pentru toate hook-uri legate de CRUD, niște informații de bază pentru proprietățile entităților pentru hook_entity_property_info() și entitățile exportabile sunt integrate în mod automat cu modulul “Features”. Aceste integrări sunt implementate în clase separate de controlleri, care poate fi înlocuite sau activate / dezactivate separat.
Opțional, “Entity API” oferă o interfață administrativă pentru gestionarea entităților.
Views
În “Views”, un plugin este un pic ca un handler, dar plugin-uri nu sunt direct responsabile pentru construirea interogărilor. În schimb, ele sunt obiecte care sunt utilizate pentru a afișa rezultatul sau să facă alte modificări.
Există 10 tipuri de plugin-uri în modulul “Views”:
tipul “display”: plugin-uri sunt responsabile pentru a controla unde se află un view; adică, modul în care acestea sunt expuse pentru alte părțile ale lui Drupal. “Page” și “block” sunt cele mai comune moduri de afișare, precum și modurile de afișare “master” sau “default”.
tipul “style”: plugin-uri de acest tip controlează modul în care un view este afișat. Pentru cea mai mare parte acestea sunt object wrapper-e din jurul template-urilor. Stilurile ar putea fi, de exemplu liste HTML sau tabele.
tipul “row style”: stilurile de acest fel se ocup de fiecare înregistrare individuală din tabelul principal. Doi stiluri sunt incluse din start, unul afișează întreaga entitate, iar al doilea numai câmpurile selectate.
tipul “argumentul default”: plugin-uri de tip “argument default” permit modalități conectabile de a furniza valori implicite pentru filtre contextuale. Acest lucru este util pentru blocuri și alte tipuri de afișaj, lipsite de o intrare naturală pentru argumente. Exemple sunt plugin-uri pentru a extrage noduri și ID-uri de utilizatori din URL-ul.
tipul “argumentul validator”: plugin-uri de acest tip pot asigura că argumentele sunt valabile și fac transformări legate de argumentele acestea. Ele pot oferi șablonuri de înlocuire pentru titlurile view-urilor. De exemplu, validatorul "conținut" verifică dacă valoarea argumentului corespunde unui nod, încarcă nodul și oferă titlul nodului ca un șablon de înlocuire.
tipul “access”: plugin-uri de acces sunt responsabile pentru controlul accesului. View-urile includ plugin-uri pentru verificarea rolurilor de utilizator și drepturilor de acces individuale.
tipul “query”: plugin-uri generează și execută o interogare, astfel încât să poată fi văzute ca un backend de date. Implementarea implicită folosește SQL. Există module contribuite, care citesc date din alte surse.
tipul “cache”: plugin-uri de acest tip controlează depozitarea și încărcarea din cache. În prezent, ei pot face caching atât din rezultat cât și din interogările generate.
tipul “pager”: plugin-uri pagere trebuie să aibă grijă de tot ce ține de pagere, de la obținerea și setarea sumei totală de elemente până la randarea pagerului și stabilirea matricei de pagere.
tipul “exposed form”: plugin-uri de tip “exposed form” sunt responsabile pentru construirea, randarea și controlarea formularelor expuse. Ele pot expune părți noi al lui views pentru utilizatori.
tipul “localization plugins”: plugin-uri ocup cu traducerea view-urilor.
tipul “display extenders”: plugin-uri permit scalarea opțiunilor view-urilor pe orizontală.
Plugin-uri noi sunt înregistrate prin implementarea hook-ului hook_views_plugins() în fișierul modulename.views.inc și returnează o serie de date. Trebuie asigurat fișierele plugin-ului sunt adăugate în fișierul modulename.info.
Fiecare plugin va fi înregistrat cu un identificator pentru plugin-ul respectiv, plus o listă destul de lungă de elemente care definesc cum și unde este utilizat plugin-ul.
Toate template-urile de view pot fi înlocuite cu o varietate de nume, folosind view-ul, ID-ul a view-ului, tipul de afișare a view-ului sau o combinație a acestora. Pentru fiecare view va exista minim două șabloane utilizate. Primul este folosit pentru toate view-urile: views-view.tpl.php. Al doilea șablon este determinată de stilul selectat pentru view-ul respectiv. Pentru anumite aspecte ale view-ului se pot schimba ce stil este utilizat, de exemplu, argumente care oferă un rezumat s-ar putea schimba stilul de unul dintre stilurile speciale pentru rezumate. Stilul implicit pentru toate view-urile este views-view-unformatted.tpl.php. Stilul pentru rânduri implicit este views-view-fields.tpl.php.
Panels
Modulul “Panels” permite unui administrator de site crearera layout-urilor personalizate pentru utilizări multiple. În centrul său este un manager de conținut drag and drop care permite crearea unui design în mod vizual și plasarea unui conținut. Integrarea cu alte sisteme permite crearea nodurilor care folosesc acest modul, paginile principale care folosesc acest modul, și chiar suprascrierea paginilor din sistem, cum ar fi taxonomie și pagina de nod, astfel încât se poate personaliza aspectul site-ului cu permisiuni.
“Panels 3” utilizează sistemul de context din modulul “Chaos tools”, astfel încât conținutul pe care se plasează pe pagină poate să fie conștient de ceea ce este afișat. De exemplu, în configurarea unui Drupal existent, un bloc nu are nicio cunoaștere reală de ceea ce afișează pagina principală. Există tot felul de trucuri și instrumente pe care se poate utiliza pentru a obține informații pentru blocuri, dar acest lucru înseamnă, în general, scrierea unui cod PHP pentru a scana URL-ul și tragerea datei din afară, ceea ce nu este un lucru foarte bun atunci când datele ar trebui să existe deja.
Într-un panel se poate crea contexte, care reprezintă obiectele afișate. De exemplu, atunci când se afișează vizualizarea unui nod, argumentul NID pe pagina este convertit într-un context prin sistemul “argumente”. Se poate crea apoi o relație de la nod la autorul nodului. Odată ce contextele sunt la locul lor, conținutul acestor contexte pot fi plasate. Pentru contextul nod se poate adăuga câmpuri CCK, corpul nodului, fișiere atașate și o serie de alte informații care pot fi furnizate prin plugin-uri. Pentru contextul user se poate afișa lucruri, cum ar fi fotografia de utilizator sau profilul.
În plus, aceste contexte pot fi verificate pentru informații și a le utiliza nu numai pentru a face conținutul disponibil pentru a afișare, dar și pentru a alege care aspect să fie activ. De exemplu, în cazul în care site este internațional, există posibilitatea să fie utilizat un context pentru a vedea dacă nodul privit este stabilit pentru o anumită limbă și se alege să-l afișa într-un fel în cazul în care aceasta este în limba franceză sau într-un alt fel în cazul în care acesta este în limba engleză. Se poate selecta, de asemenea, pe atribute, cum ar fi tipul de nod, dacă utilizatorul are acces la editarea nodului sau nu, și mai multe. Acest sistem este pluggable și se poate adăuga propriile criterii personalizate cu doar o cantitate mică de cod.
“Panels” include aplicații simple de drag and drop. Există un tip de nod (nodul "panel"), care poate fi pur și simplu adăugat ca și conținut pentru sistemul dumneavoastră. Fiind un nod pierde o mulțime de caracteristici mai puternice pe care sistemul de pagină le are, dar are avantajul simplicității și de a obține toate funcționalitățile pe care nodurile le obțin în mod normal.
Panourile pot fi folosite și pentru elemente mai mici decât pagini. Cu “Panels” se poate crea un “mini-panou”, cu un aspect cu două coloane. Se adaugă un bloc la stânga, un bloc la dreapta și este gata mini-panoul. Acest mini-panou va fi apoi disponibil pentru sistem ca un bloc obișnuit sau conținut de panou pentru a merge în alte panouri.
“Panels” susține stiluri, care poate controla modul în care “Panes” individuale de conținut, regiuni în cadrul unui panou, și întregul panou vor fi randate. În timp ce modulul “Panels” vine cu câteva stiluri implementate, stilurile pot fi furnizate prin plugin-uri, precum și de teme. Constructorul de aspect este frumos pentru proiectarea unui aspect vizual. Module și teme pot oferi aspecte particularizate, care pot potrivi specificațiile exacte unui designer, dar tot permite constructorului site-ului plasarea conținutului oriunde dorește.
“Panels” include un mecanism de caching pluggable. Un singur tip de cache este inclus, cache-ul “simplu”, care este bazată pe timp. Deoarece cele mai multe site-uri au nevoie de cache foarte specific, bazate pe șabloane de conținut și de trafic, acest sistem a fost proiectat pentru a permite site-urilor care au nevoie de a elabora propriile sale triggere pentru cache implementarea plugin-urilor, care vor lucra cu “Panels”. Panourile pot fi memorate în cache ca un întreg, ceea ce înseamnă că întreaga producție a panoului poate fi memorat în cache, sau pane-urile individuale de conținut pot fi memorate în cache.
“Panels” pot fi integrate cu “Organic Groups” prin intermediul modulului og_panels pentru a permite grupurilor individuale de a avea propriile lor șabloane personalizate.
Modulul “Panels” se integrează cu “Views” pentru a permite administratorilor să adauge orice view ca conținut.
Services
Modulul “Services” este un API standardizat pentru Drupal, care permite crearea “serviciilor”, sau o colecție de metode, destinate consumului de aplicații remote. Mai multe “servere”, sau protocoale, oferă diferite modalități de a apela aceste metode de la un site remote. Acesta funcționează similar cu capacitățile existente de Drupal legate de XMLRPC, dar oferă funcții suplimentare cum ar fi:
module “server” atașabile care este permis altor protocoalelor decât XMLRPC, cum ar fi SOAP, REST sau AMF
module “service” atașabile permițând dezvoltatorilor să adauge servicii suplimentare remote
mecanisme de autentificare atașabile
multe module de servicii incluse care interacționează cu module Drupal existente, cum ar fi node, taxonomy, user, views și system
Modulul “Services” oferă o soluție standardizată pentru integrarea aplicațiilor externe în Drupal. Serviciul callbak poate fi utilizat cu mai multe interfețe, cum ar fi REST, XMLRPC, JSON, JSON-RPC, SOAP, AMF, etc. Acest lucru permite unui site Drupal oferirea unui servicii de web prin intermediul mai multor interfețe în timp ce, folosește același cod pentru callback-uri.
Service API permite modulelor crearea altor servicii, inclusiv controlul al accesului pluggable. Server API permite modulelor crearea altor servere, cum ar fi SOAP. Modulul oferă integrare cu funcționalități de bază al lui Drupal cum ar fi fișiere, noduri, taxonomie, utilizatori și mai mult. Response format API permite definirea formatelor de răspuns pentru content-type, de exemplu application/json sau application/xml.
Pathauto
Modulul “Pathauto” generează automat aliasuri pentru URL-uri pentru diferite tipuri de conținut (noduri, termeni de taxonomie, utilizatori), fără a cere utilizatorul să specifice manual aceste aliasuri. Acest modul permite să avem aliasuri URL, cum ar fi /categorie/titlul-nodului în loc de /node/123. Aliasurile se bazează pe un sistem de “model”, care utilizează token-uri pe care administratorul le poate schimba.
Acest modul necesită să fie instalat și activat modulul “Token”.
Atunci când un model este înlocuit cu textul real există o anumită filtrare și transcriere care pot să apară. În Pathauto 5.x transliterare este controlată de existența fișierului i18n-ascii.txt. Trebuie să fie activat modulul de bază “Locale” și să aibă activat mai mult de o limbă pentru a suporta modulul “Pathauto” în crearea automată unui alias limbaj specific.
De asemenea, trebuie remarcat faptul că unele modele pot fi periculoase atunci când sunt utilizate în “Pathauto”. Dacă avem un alias, cum ar fi [title-raw] pentru o bucată de conținut pe care utilizatorii pot crea le permitem să creeze pagini, cum ar fi “http://www.example.com/google1234567.html”, care sunt utilizate pentru autentificarea în Google sau Yahoo! webmaster tools. Acest lucru, atunci permite utilizatorului pentru a autentifica în calitate de proprietar al site-ului și de a controla intrările în aceste instrumente inclusiv eliminarea site-ului din index, schimbarea între www și versiuni fără www ale site-ului, poate spune botului de căutare să viziteze mai puțin frecvent. Acest lucru nu este implicit și nu este recomandat. Dacă sunt dorite alias-uri scurte, modelul ar fi bine să fie ceva de genul “c/[title-raw]”, ca să pune o literă “c” înainte de fiecare titlu.
O altă problemă apare atunci când se creează un model alias cu user/[user] pentru utilizatori. Apoi, un utilizator înregistrează cu un nume care conține caractere care nu sunt în tabelul de traducere, astfel “Pathauto” creeză un alias, care strică pagina “My Account”.
Dezvoltarea modulelor în Drupal 7
Un site-ul Drupal poate avea trei tipuri de module: module de bază care sunt distribuite cu Drupal și sunt aprobate de către dezvoltatorii de bază și a comunității, module contribuite scrise de comunitatea Drupal și partajate sub aceeași licență GNU Public License (GPL), ca Drupal, și module personalizate create de dezvoltator de multe ori pentru un anumit caz de utilizare specifică pe site-ul pe care lucrează.
Fișierele a unui modul
Un modul Drupal trebuie să conține minim două fișiere: fișierul .info, care specifică numele, descrierea, versiunea și dependințele modulului, și fișierul .module, care implementează hook-uri și funcții pentru a realiza funcționarea modulului.
Fișierul .info este utilizat pentru redare de informații pe paginile de administrare Drupal Web GUI, pentru furnizarea de criterii pentru a controla modul de activare și dezactivare și pentru scopuri administrative generale în alte contexte. Acest fișier .info este necesară pentru ca sistemul să recunoască prezența unui modul.
Fișierul .info trebuie să aibă același nume ca și fișierul .module. și să fie în același directory. De exemplu, în cazul în care modulul este numit example.module atunci fișierul .info trebuie să fie numit example.info. Acest fișier este un standard fișier .ini, care definește proprietăți în perechi cheie / valoare, separate de semnul egal (cheie = valoare). Se poate folosi ghilimele pentru a încheia valoarea. Valorile menționate pot conține liniile noi. Fișierele .info poate conține comentarii. Un punct și virgulă este plasat la începutul unei linii care este o linie de comentariu și că linia nu va fi analizat. Ori de câte ori se modifică fișierul.info, trebuie șters memoria cache al site-ul pentru ca modificările să aibă efect.
Fișierul .info poate conține următoarele proprietăți:
name (obligatoriu). Aceasta afișează numele de modul, care va apărea pe pagina de module. Din moment ce module sunt nume proprii, ar trebui să fie valorificate ca un nume propriu, de exemplu, “Foo Bar”, nu “foo bar” sau “Foo bar”, și ar trebui să fie un nume citibil de un om, adică să nu fie foo_bar.
description (obligatoriu). O scurtă descriere preferabil de o linie care va spune pe pagina de administrare ce face modulul. Acest câmp este limitat la 255 de caractere. Descrieri pot conține link-uri către documentație și surse.
core (obligatoriu). Versiunea de Drupal pentru care modulul era implementat. Pentru Drupal 7 acest lucru ar fi 7.x. Modulele nu pot specifica versiunea minoră de un branch, deci 6.x este corect, iar 6.2 nu este.
stylesheets (opționale). Drupal 7 permite adăugarea fișierelor CSS în fișierul de informații al modulului în cazul în care ar trebui să fie adăugate pe fiecare pagină.
scripts (opționale). Se poate adăuga și fișierele de Javascript în fișierul de informații al modulului în cazul în care ar trebui să fie adăugate pe fiecare pagina. Acest lucru permite agregarea lui Javascript într-un mod optim.
files (opționale). Atunci când un modul este activat, Drupal va scana toate fișierele declarate și indexează toate clasele și interfețele pe care le găsește. Clasele vor fi încărcate în mod automat de către PHP atunci când sunt accesate prima dată.
dependencies (opționale). O serie de alte module pe care modul necesită. Dacă aceste module nu sunt prezente, modulul nu poate fi activat. Dacă aceste module sunt prezente, dar nu sunt activate, administratorului se va afișa o listă cu module suplimentare. În plus, test_dependencies[] poate fi utilizat pentru a indica dependențe, care sunt opționale, dar recomandată. Atunci, ele sunt susținute doar de către sistemul automat de testare.
package (opțional). În cazul în care modulul vine cu alte module sau ar trebui să fie folosit cu alte module, aici trebuie introdus numele pachetulu. Dacă este lăsat gol, modulul va fi listat în categoria “Others”. În general, această proprietate ar trebui să fie utilizat numai de pachete mari multi-modul, cum ar fi “Fields”, “Views”, “Commerce”, “Organic Groups” sau altele. Toate celelalte module ar trebui să lase acest gol. Ca orientare, patru sau mai multe module care depind între ele sau toate pe un singur modul, atunci modulele sunt candidați buni pentru un pachet. O excepție de la această regulă este pachetul de “Development”, care ar trebui să fie folosit pentru orice modul care sunt module pentru dezvoltare. Capitalizarea este important, deoarece stringul este case sensitive și folosind package = fields într-un singur modul și package = Fields într-un alt modul s-ar produce două pachete diferite pe pagina de administrare a modulului.
alte proprietăți sunt: php, version, configure, required, hidden, project și project status url.
Drupal 7 utilizează fișiere .install pentru a crea tabele în baze de date și câmpuri, și pentru a introduce datele. Drupal 7 fișiere .install pot oferi, de asemenea, actualizări pentru a schimba structura bazei de date și conținutul.
Un fișier .install este rulat când un modul este activat pentru prima dată, și este folosit pentru a rula procedurile de configurare, în conformitate cu modulul. Cea mai obișnuită sarcină este crearea tabelor în baze de date și câmpuri. Fișierul .install nu are nicio sintaxă specială. Este pur și simplu un fișier PHP cu o extensie diferită.
Instrucțiuni de instalare sunt închise într-o funcție _install(). Acest hook va fi apelat atunci când modulul este activat pentru prima dată. Orice funcție poate să fie apelată aici. Tabele în baze de date sunt create folosind Schema API. Schema API permite modulelor să declare tabelele lor în baze de date într-o matrice structurată, similar cu Form API.
O schemă este definită de hook_schema(), care trebuie să existe în fișierul de instalare a modulului. Acest hook este apelat la instalarea și dezinstalarea modulului. Tabelele declarate de acest hook va fi create în mod automat atunci când modulul este activat, și le șterge atunci când modulul este dezinstalat. Acest lucru se întâmplă înainte de hook_install() să fie apelat, iar după hook_uninstall() a fost apelat.
Sistemul de hook-uri
Un modul Drupal este o colecție de fișiere care conțin unele funcționalități și este scris în PHP. Deoarece codul modulului se execută în contextul site-ului, se pot folosi toate funcțiile și are acces la toate variabilele și structurile de nucleu Drupal. De fapt, un modul nu este diferit de la un fișier obișnuit PHP, care poate fi creat și testat în mod independent și apoi folosit pentru a conduce mai multe functionalități. Această abordare permite nucleului apelarea la anumite locuri anumite funcții definite în module și de a spori funcționalitatea de bază. Locurile unde cod pot fi executate se numesc “hook” și sunt definite printr-o interfață fixă.
Sistemul modular al Drupal-ului este bazat pe conceptul de hook-uri. Un hook este o funcție care este denumit foo_bar, unde “foo” este numele modulului (care are un fișier foo.module), iar “bar” este numele hook-ului. Fiecare hook are un set de parametri și un rezultat definit.
Hook-uri reprezită modul în care module pot interacționa cu codul de bază Drupal. Ele fac posibil ca un modul să definească noi URL-uri și pagini în cadrul site-ului (hook_menu), să adăuge conținut la pagini (hook_block, hook_footer, etc), să configureze tabelele bazei de date personalizate (hook_schema) și așa mai departe. De exemplu, modulul CCK definește hook_field_info, care poate fi utilizată de module care doresc să definească un nou tip de câmp. Cele mai multe module care definesc hook-uri va oferi o documentație despre ele.
Hook-uri apar la diferite puncte în firul de execuție, în cazul în care Drupal urmărește contribuții de la toate modulele activate. De exemplu, atunci când un utilizator vizitează o pagină de ajutor pe un site Drupal, Drupal-ul construiește pagina de ajutor se va da fiecărui modul șansa de a contribui documentare despre sine. El face acest lucru prin scanarea codului modulelor pentru funcții care au numele mymodule_help($path, $arg), în cazul în care "MyModule" este numele modulului, de exemplu, hook-ul de ajutor al modulului de bloc se numește block_help și hook-ul de ajutor al modulului de nod este numit node_help. Hook-ul poate furniza parametrii. Parametrii $path și $arg permite dezvoltatorului determinarea pe ce pagină sau pagini vor apărea mesajele de ajutor.
Un hook poate fi considerat ca un ascultător eveniment, în sensul că un eveniment declanșează o acțiune. Evenimentul în Drupal, cum ar fi ștergerea unui nod, ar declanșa hook-ul “hook_delete”. În cazul în care modulul a implementat hook_delete, funcția ar fi rulată atunci când a avut loc ștergerea unui nod. Ca un exemplu, funcția ar putea reduce numărul total de noduri, astfel încât atunci când un nod a fost șters, funcția ar fi rulat și reduce numărul de 1.
Drush
Drush este o interfață shell pentru gestionarea Drupal-ului chiar din linia de comandă. Este un instrument foarte util, deoarece ajută la efectuarea activităților diverse de admin folosind doar o sau două comenzi în terminal, înlocuind nevoia mai multor clicuri și reîncărcării paginii.
Drush Project Manager permite descărcarea, activarea, dezactivarea, dezinstalarea și actualizarea modulelor, temelor, profilelor și traducerilor din linia de comandă într-un mod foarte simplu. De exemplu comanda “drush dl views” descarcă modulul “Views”, iar comanda “drush pm-enable views” sau “drush en views” activează modulul “Views”. Tot așa se poate și dezactiva un modul, în cazul aceasta comanda ar fi “drush pm-disable views” sau versiunea mai scurtă ar fi “drush dis views”.
Se poate șterge cache-ul cu ajutorul unei comande. Cu “drush cc all” se poate șterge tot, cache-ul, dar se poate șterge și o parte numai, de exemplu meniurile cache-uite cu comanda “drush cc menu”. Alte comande pentru ștergerea cache-ului sunt: “drush cc registry”, “drush cc theme_registry”, “drush cc css-js” și altele.
Sarcinile cron a lui Drupal sunt adesea înființate pentru rulare prin intermediul unui apel wget în cron.php. Aceeași sarcină poate fi realizată și prin intermediul comandei “drush cron”, care evită necesitatea interfeței pentru cron.
În plus, Drush Package Manager permite actualizarea tuturor modulelor și chiar nucleului Drupal, cu doar o singură comandă: “drush pm-update”.
Bootstrap 3
Bootstrap include un sistem de grilă responsivă care scalează în mod corespunzător până la 12 de coloane când dimensiunea dispozitivului sau viewport-ului crește. Acesta include clase predefinite de opțiuni pentru a crea ușor un layout nou. Sisteme de grilă sunt utilizate pentru crearea layout-urilor de pagină dintr-o serie de rânduri și coloane în care este așezat conținutul site-ului.
Rânduri trebuie să fie plasate într-un container cu clasa .container care are o lățime fixă sau într-un container cu clasa .container-fluid care are lățime întreagă pentru alinierea corectă. Rânduri sunt utilizate pentru a crea grupuri orizontale de coloane. Conținutul ar trebui să fie plasată în coloane și numai coloanele pot fi copii imediate ale rândurilor. Clasele predefinite ale grilei, cum ar fi de exemplu .row și .col-xs-4 sunt disponibile pentru a crea rapid leyout-uri de acest tip. Coloanele creează locuri goale între conținut cu ajutorul unui padding. Coloanele sistemului sunt create prin specificarea numărului acelor douăsprezece coloane disponibile. De exemplu, trei coloane egale pot fi create cu trei .col-xs-4.
Containerul și coloanele au diferite lățimi și prefixe pentru clase:
dispozitive foarte mici, de obicei telefoane, care sunt mai mici decât 768px: nici containerul, nici coloanele nu au o lățime fixă, iar prefixul clasei este .col-xs-.
dispozitive mici, de obicei tablete, care sunt mai mari sau egale cu 768px: lățimea containerului este 750px, lățimea coloanelor este 60px, iar prefixul clasei este .col-sm-.
dispozitive medii, care sunt mai mari sau egale cu 992px: lățimea containerului este 970px, lățimea coloanelor este 78px, iar prefixul clasei este .col-md-.
dispozitive mari, care sunt mai mari sau egale cu 1200px: lățimea containerului este 1170px, lățimea coloanelor este 95px, iar prefixul clasei este .col-lg-.
Clasele se aplică pe dispozitive cu lățimi de ecran mai mari sau egale cu dimensiunile specificate și suprascriu clasele dispozitivelor mai mici. Prin urmare, aplicarea oricărei clase .col-md- pe un element va afecta nu numai stilul pe dispozitive medii, dar și pe dispozitive mai mari în cazul în care clasa .col-lg- nu este prezent.
Crearea website-ului
Pentru a crea site-ul pentru rezervarea biletelor an folosit CMS-ul Drupal, mai multe module contribuite, dar am implementat și un modul custom pentru formularul multi-pas.
Layoutul site-ului era făcută cu ajutorul Bootstrap-ului, am folosit versiunea a treia.
Adăugarea filmelor
Pentru filme am creat un tip de conținut nou, numit “Movie”, care are mai multe câmpuri:
titlu (title), titlul filmului
tip (genre), tipurile filmului; este un textfield, se poate introduce mai multe tipuri unul lângă altul separate cu o virgulă
durată (duration), durata filmului; este un textfield, deci se poate introduce durata în orice formă
director (director), directorul filmului; este un textfield
scriitori (writers), scriitorii filmului; este un textfield, dar se poate introduce mai mulți scriitori separate cu o virgulă
actori (stars), actorii filmului; este un textfield, dar se poate introduce mai mulți actori separate cu o virgulă
descriere (description), descrierea scurtă a filmului; acesta este un textarea
poster, o imagine despre posterul filmului; acesta este un câmp de tip “image”, deci se poate selecta, și apoi încărca o imagine
slide, o imagine mai mare despre film; acesta este un câmp de tip “image”, deci se poate selecta, și apoi încărca o imagine; acesta este necesar numai în cazul în care câmpul “coming soon” este bifat, pentru că filmele acestea sunt puse într-un slideshow
link IMDb (IMDb link), un link simplu spre profilul IMDb a filmului; este un textfield
trailer, un link simplu spre trailerul filmului pe YouTube; este un textfield
data (date), date și ore când filmul este în program; acesta este un câmp de tip “date”; se poate introduce mai multe date, pentru că se poate adăuga mai multe instanțe a câmpului
coming soon, trebuie să fie bifat dacă filmul nu este încă în program, dar urmează să fie; este un câmp de tip checkbox
Pagina principală
Pagina principală este alcătuită din trei reguini: prima regiune conține un meniu principal și un slideshow, a doua regiune conține un buton foarte mare cu textul “Online reservation” și filmele care sunt în program, iar a treia regiune conține un meniu cu niște linkuri: “About us”, “Contact”, “Snacks and Drinks” și “Prices”.
Meniul principal conține un logo poziționat absolut, un link către pagina principală și un link către o pagina, care listează toate filmele.
Butonul care duce la pagina de rezervare este de fapt un bloc cu HTML.
Pentru filmele care sunt în program am creat un view. Am folosit formatarea de tip “Responsive grid”, pentru că tot site-ul este responsiv. Am adăugat câmpurile Id,care conține ID-ul filmului, Path, care conține linkul către pagina de prezentare a filmului, Poster, ca să am o imagine și Title, pentru titlul filmului. Am mai adăugat un câmp special “Global: Custom text”, care conține butoanele “Reserve Seats” și “Details”. Primul buton ne duce la formular, iar al doilea buton ne duce la pagina de prezentare a filmului.
Mai sunt setate și niște criterii de filtrare: avem numai noduri publicate de tip “Movie” fără să fie bifată câmpul “Coming Soon” și datele să fie în viitor.
Pagina era creată cu “Page maganer” din modulul “Chaos tools suite”.
Slideshow-ul
Slideshow-ul era creat în mod similar cu view-ul pentru filme în program. Am folosit un view cu alte filtre. Nu m-a interesat data filmelor, dar am schimat filtrul pentru checkbox-ul “Coming Soon”. Câmpurile folosite sunt imaginea încărcată pentru slide și titlul filmului. Am folosit formatarea de tip “Unformatted list”, pentru că am creat un fișier “views-view–coming-soon.tpl.php”. Folosind un anumit markup slideshow-ul este generat automat de către Bootstrap 3.
Slideshow-ul este un bloc, care este pusă în regiunea “header”.
Pagina de prezentare a unui film
Pentru a crea pagina de prezentare a filmelor am creat un view și am folosit “Page manager”-ul. View-ul conține câmpurile nodului, în afară de câmpul “Coming Soon”. Am mai folosit câmpurile speciale “Global: Custom text” pentru a customiza modul în care sunt afișate elementele și pentru a adăuga clasele necesare pentru layout-ul paginii. Linkul către profilul IMDb arată ca un buton, dar este de fapt un anchor cu atributul target: “_blank”. Butonul “Trailer” deschide un dialog modal, care conține trailer-ul filmului.
Butoanele de rezervare ne duc la formularul de rezervare, dar completează câmpurile “Movie”, “Days” și “Hours” a formularului și ne duce direct pe pasul doi.
Pentru a crea pagina de prezentare am activat și am suprascris pagina pentru noduri. Aceasta pagina era deja creată în cod, eu am activat-o numai pentru suprascriere.
Pe pagina de prezentare se poate scrie și comentarii la filme. Apar și comentarii și un form pentru a scrie un comentariu nou.
În “Selection Rules” este setat o criterie pentru pagina respectivă. Criteria este că nodul vizualizat să fie un nod de tip “Movie”.
Pe această pagină am nevoie de mai multe contexte. Un context este un obiect, în cazul acesta contextele necesare sunt nodul care este vizualizat și comentariile nodului. Acest luru se poate seta pe pagina “Contexts” în “Page manager”.
Listarea tuturor filmelor
Pentru listarea filmelor tot am folosit modulele “Views” și “Page manager”. În “Page manager” am creat a pagină nouă și am inserat un view. Pagina este accesibilă din meniul principal și este de fapt o listă. Pe o pagină apar 20 de filme maxim.
Ca și formatare am selectat “Table” ca să am o tabelă cu filme. Am listat într-o coloană titlurile filmelor, iar într-o altă coloană tipul lor. Am folosit mai multe filtre, nodurile listate trebuie să fiu publicate și să au tipul “Movie”. Filtrul pentru title și tipul filmului este expusă pentru utilizator, deci ei pot să introduc texte în input-uri și să caute între filme. Nu trebuie introdus tot titlul filmului, ajunge numai o parte din el.
Formularul pentru rezervarea biletelor
Pentru formular am creat un modul custom, numit “Reservation form”. Formularul conține 3 pasuri. Pe primul pas trebuie introdus datele despre filmul dorit, adică titlul, data și ora.
Avem două butoane, “Continue” și “Cancel”. Apăsând pe primul buton ajungem la pasul următor, iar apăsând pe butonul al doilea ajungem pe pagina principală.
Pasul 2 conține scaunele, care pot să fie ocupate și un input cu atributul “disabled”, unde utilizatorul poate vedea cât va costa biletele. Scaunele ocupate sunt marcate cu roșu, iar scaunele selectate sunt marcate cu galben.
Butoanele de pe pagina aceasta sunt: “Back”, “Continue” și “Cancel”. Primul buton ne duce înapoi la pasul întâi.
Pasul al treilea conține câmpuri pentru infomațiile despre utilizator: numele, prenumele, numărul de telefon și adresa de e-mail. Mai este pe pagină și un captcha, ca să nu avem spemmeri. Captcha-ul era setat cu modulul contribuit “CAPTCHA”.
Butoanele de pe pagina aceasta sunt: “Back”, “Finish” și “Cancel”. Butonul “Finish” ne duce pe pagina de success.
După ce a fost completat formularul putem ajunge pe o pagină de success. În afară de mesajul de success mai vedem și informațiile introduse utilizatorul respectiv: numărul scaunilor selectate, filmul selectat, data și ora selectată, numele, prenumele, numărul de telefon și adresa de e-mail.
Utilizatorul primește un e-mail, care conține un cod.
Implementarea modulului
Prima dată am creat un fișier .info, care conține informațiile de bază despre modulul meu.
name = Reservation Form
Numele formului este “Reservation Form”.
description = Multi step form for reservations.
Am adăugat o descriere, care specifică, că modulul creează un formulat multi-pas pentru rezervările biletelor.
core = 7.x
Am specificat versiunea nucleului Drupal-ului, care este 7.x în cazul acesta.
package = "Cinema"
Am adăugat un pachet pentru acest modul, ca să știu că modulul este un modul custom și ca să-l găsesc mai repede.
dependencies[] = field
dependencies[] = entity
Modulul are două dependințe, primul este modulul “Field”, iar a doua este modulul “Entity API”.
După ce am terminat cu fișierul .info, am creat fișierul .install și am impementat hook-ul reservation_form_schema(). Am creat a tabelă pentru entitatea “reservation”. Aceasta entitate va conține informațiile salvate. Tabela are mai multe coloane:
rid, care este un ID, generat automat, fiindcă tipul lui este “serial”.
started, care conține un timestamp și indică timpul când a fost început rezervarea.
seats, care conține o matrice codificată cu funcția drupal_json_encode().
movie_id, care conține ID-ul filmului selectat. Acesta este un ID de nod.
timestamp, care conține data și ora selectată a filmului.
firstname, care conține prenumele utilizatorului.
lastname, care conține numele utilizatorului.
telephone, care conține numărul de telefon al utilizatorului.
email, care conține adresa de e-mail al utilizatorului.
codes, care conține codul generat, care este trimis utilizatorului într-un e-mail.
finished, care este o valoare booleană și indică dacă procesul a fost terminată.
Fișierul .module conține hook-urile implementate. Am implementat hook-ul reservation_form_permission() pentru a crea o permisiune pentru gestionarea rezervărilor. Numai administratorul site-ului are dreptul de a gestiona rezervările.
Am implementat hook-ul reservation_form_menu(), care creează URL-urile, unde se poate accesa formularul.
Hook-ul reservation_form_entity_info() conține informații despre entitatea “reservation”.
function reservation_form_entity_info() {
$info['reservation'] = array(
'label' => t('Reservation Entity'),
'entity class' => 'Entity',
'controller class' => 'EntityAPIController',
'base table' => 'reservation',
'fieldable' => FALSE,
'static cache' => TRUE,
'entity keys' => array(
'id' => 'rid'
)
);
return $info;
}
Numele entității este “Reservation Entity”, clasele folosite sunt specificate, tabela de bază este “reservation”, nu se poate atașa câmpuri acestei entități. Cheia specificată este coloana “rid”.
Am implementat hook-ul reservation_form_form($js = NULL, $step = NULL), care construiește formul multistep:
$form_info = array(
'id' => 'reservation',
'path' => "reservation/" . ($js ? 'ajax' : 'nojs') . "/form/%step",
'show trail' => TRUE,
'show back' => TRUE,
'show cancel' => TRUE,
'show return' => FALSE,
'next callback' => 'reservation_form_wizard_next',
'finish callback' => 'reservation_form_wizard_finish',
'cancel callback' => 'reservation_form_wizard_cancel',
'order' => array(
'start' => t('Step 1'),
'second' => t('Step 2'),
'third' => t('Step 3')
),
'forms' => array(
'start' => array(
'form id' => 'reservation_form_form_start'
),
'second' => array(
'form id' => 'reservation_form_form_second'
),
'third' => array(
'form id' => 'reservation_form_form_third'
)
),
);
Matricea specifică ID-ul și URL-ul formularului, specifică ce butoane să fie active, specifică ordinea pasurilor și callback-urile pasurilor. Callback-urile pasurilor conțin formulare simple implementate cu ajutorului “Form API”-ului.
Când un utilizator ajunge pe pagina de rezervare o entitate nouă este creată ca să obțin un ID pentru procesul respectiv. Acest ID este stocat într-un cookie, care este ștearsă după 5 minute. Acesta înseamnă că utilizatorul are 5 minute ca să completeze formularul. Dacă formularul nu este completat, atunci coloana “Finished” în tabela “reservation” este NULL.
Am implementat hook-ul reservation_form_cron(), care șterge rezervările necompletateși mai vechi decât 5 minute.
function reservation_form_cron() {
$query = new EntityFieldQuery();
$time = REQUEST_TIME – (60 * 5);
$query->entityCondition('entity_type', 'reservation')
->propertyCondition('finished', NULL)
->propertyCondition('started', $time, '<');
$result = $query->execute();
foreach ($result['reservation'] as $id => $reservation) {
entity_delete('reservation', $reservation->rid);
}
}
Select-urile din primul pas folosesc AJAX:
$form['movie'] = array(
'#title' => t('Movie'),
'#type' => 'select',
'#options' => $movie_titles,
'#required' => TRUE,
'#ajax' => array(
'callback' => '_ajax_populate_dates_callback',
'wrapper' => 'date-days-div',
'method' => 'replace',
'effect' => 'fade',
),
'#default_value' => $form_state['object']->movie
);
Acest lucru înseamnă că conținutul select-ului al doilea și al treilea depind de primul select, iar conținutul select-ului al treilea depinde și de valoarea selectată în al doilea select.
Pasul doi al formularului conține niște span-uri formatete cu CSS. Am inclus un fișier JavaScript, în care calculez prețul și pun ID-urile spanurilor într-un hidden input. Schimbarea culorilor este făcută cu adăugarea și ștergerea claselor de pe span-uri. Când utilizatorul apasă pe butonul “Continue” inputul pentru scaune este validate, nu cumva să fie un sau mai multe scaune rezervate între timp de un alt utilizator. Dacă nu, atunci scaunele selectate sunt salvate.
function _validate_seats_field($element, &$form_state) {
if (!empty($element['#value'])) {
$seats = drupal_json_decode($element['#value']);
$success = _reservation_form_lock_seats($form_state['object']->rid, $seats, $form_state['object']->hours, $form_state['object']->movie);
if ($success == FALSE) {
form_set_value($element, '', $form_state);
form_error($element, t('Someone already reserved one of these seats.'));
}
}
}
Pasul 3 al formularului este un formular simplu cu niște inputuri de tip “text”. Câmpurile pentru numărul de telefon și adresă de e-mail sunt validate. Singurul câmp, care nu este un input simplu de text, este captcha-ul.
$form['captcha'] = array(
'#type' => 'captcha',
'#captcha_type' => 'image_captcha/Image',
);
Când utilizatorul ajunge pe pagina de succes atunci se generează codul, care este de fapt un hash format dintr-un string, care este alcătuit din adresa de e-mail, filmul, data și ora și un timestamp:
$codes[] = md5($object->email . $object->movie . $object->hours . REQUEST_TIME);
Am implementat hook-ul reservation_form_mail($key, &$message, $params), care este necesar pentru trimiterea e-mailului.
function reservation_form_mail($key, &$message, $params) {
switch($key){
case 'reservation':
$message['subject'] = t('Reservation successful!');
$body_text = implode(', ', $params['codes']);
$body = array();
$body[] = 'Here are your codes:';
$body[] = $body_text;
$message['body'] = $body;
break;
}
}
Pagina pentru gestionarea rezervărilor
Pagina pentru gestionarea rezervărilor este un view. Trebuia să implementez niște handler-e speciale pentru câmpurile “Seats” și “Codes”, pentru ca să arate mai frumos. Trebuia să implementez hook-ul reservation_form_views_api(), în care specific API-ul folosit și path-u lunde se află fișierul în care se află handler-ul. Am mai implementat hook-ul reservation_form_views_data() ca să specific ce handler-e să fie folosite.
'field' => array(
'handler' => 'views_handler_field_list',
'click sortable' => TRUE,
),
Numele handler-ului meu este views_handler_field_list, care nu face altceva, dacât formatează matricea codificată și returnează o listă.
Am mai implementat un handler pentru câmpul “delete”. Am implementat hook-urile reservation_form_delete_form și reservation_form_delete_form_submit pentru ștergerea entităților.
Alte pagini
Site-ul are și pagini simpli, care sunt noduri, dar nu de tip “Movie”, ci au tipul “Page”. Aceste pagini sunt “About us”, “Contact”, “Snacks and Drinks” și “Prices”.
Pagina de contact
Pagina de contact conține un Google Map, datele de contact și un formular de contact. Acest formular este creată de un modul din nucleul Drupal-ului.
Crearea API-ului
Am avut nevoie de modulul “Services” și modulul “REST Server”. Aceste sunt module contribuite. Pentru a crea URL-urile pentru API-ul meu trebuia să implementez hook-ul reservation_form_services_resources().
Am implementat mai multe funcții, de care API-ul are nevoie. Acestea sunt:
_reservation_form_get_movies($in_theather = NULL)
_reservation_form_get_content($id = NULL)
_reservation_form_create_reservation()
_reservation_form_get_seats($time, $movie, $id = NULL)
_reservation_form_reserve_seats($rid, $firstname, $lastname, $telephone, $email, $codes)
_reservation_form_lock_seats($rid, $seats, $time, $movie)
_reservation_form_unlock_seats($rid)
_reservation_form_get_reservations($email)
_reservation_form_access()
Pentru a accesa aceste funcții implementarea hook-ului reservation_form_services_resources() ar trebui să arate așa:
'getseats' => array(
'operations' => array(
'index' => array(
'help' => 'Retrieves the seats.',
'callback' => '_reservation_form_get_seats',
'access callback' => '_reservation_form_access',
'access arguments append' => FALSE,
'args' => array(
array(
'name' => 'time',
'optional' => FALSE,
'source' => array('param' => 'time'),
'type' => 'int',
'description' => t('The date and time of the movie.'),
),
array(
'name' => 'movie',
'optional' => FALSE,
'source' => array('param' => 'movie'),
'type' => 'int',
'description' => t('The ID of the movie.'),
)
),
),
),
),
Hook-ul returnează o matrice în care este specificat callback-ul și callback-ul pentru acces. Mai sunt specificate niște informații despre parametrii. În exemplul acesta URL-ul va arăta astfel: http://cinema/api/getseats.json?time=1403702100&movie=4. URL-ul returnează un obiect JSON. Endpoint-ul conține toate resursele și este configurat astfel:
Concluzie
Datorită avantajelor serverului LAMP, cuprinzând toate programele necesare pentru a rula un web server și sistemului de administrarea conținutului Drupal 7, aveam tot ce este necesar pentru a realiza un astfel de website.
Avantajul cel mai mare a acestui sistem este că rulează pe un web server și poate fi accesat cu un simplu browser web.
În ziua de azi dispozitivele portabile joacă un rol important în viața noastră. Website-ul poate fi accesat de pe orice tabletă sau smartphone cu acces internet pentru a rezerva locuri, pentru că era creată layout-ul site-ului cu Bootstrap 3.
Bibliografie
http://en.wikipedia.org/wiki/PHP
https://www.drupal.org/about
http://en.wikipedia.org/wiki/Drupal
https://www.drupal.org/project/token
https://www.drupal.org/project/captcha
https://www.drupal.org/project/date
https://www.drupal.org/project/ctools
https://www.drupal.org/project/entity
https://www.drupal.org/project/views
https://www.drupal.org/project/panels
https://www.drupal.org/project/services
https://www.drupal.org/project/pathauto
https://www.drupal.org/developing/modules
http://www.drush.org/
http://getbootstrap.com/css/
http://getbootstrap.com/javascript/
Bibliografie
http://en.wikipedia.org/wiki/PHP
https://www.drupal.org/about
http://en.wikipedia.org/wiki/Drupal
https://www.drupal.org/project/token
https://www.drupal.org/project/captcha
https://www.drupal.org/project/date
https://www.drupal.org/project/ctools
https://www.drupal.org/project/entity
https://www.drupal.org/project/views
https://www.drupal.org/project/panels
https://www.drupal.org/project/services
https://www.drupal.org/project/pathauto
https://www.drupal.org/developing/modules
http://www.drush.org/
http://getbootstrap.com/css/
http://getbootstrap.com/javascript/
Copyright Notice
© Licențiada.org respectă drepturile de proprietate intelectuală și așteaptă ca toți utilizatorii să facă același lucru. Dacă consideri că un conținut de pe site încalcă drepturile tale de autor, te rugăm să trimiți o notificare DMCA.
Acest articol: Website Pentru Rezervarea Biletelor (ID: 150787)
Dacă considerați că acest conținut vă încalcă drepturile de autor, vă rugăm să depuneți o cerere pe pagina noastră Copyright Takedown.
