Dezvoltarea Unei Aplicatii Pentru Ghidarea Utilizatorilor Asupra Atractiilor Turistice
DEZVOLTAREA UNEI APLICAȚII PENTRU GHIDAREA UTILIZATORILOR ASUPRA ATRACȚIILOR TURISTICE
Cuprins
Cuprins
1. Considerații
1.1 Rezumat
1.2 Descrierea aplicației
1.2.1 Conținutul site-ului
1.2.2 Utilizatorii
1.2.3 Design-ul site-ului
1.3 Alegerea tehnologiilor
1.3.1 Despre Drupal
1.3.2 Alte tehnologii folosite
2.1 Alegerea modulelor necesare
2.2 Alegerea unui design
2.3 Crearea tipurilor de conținut
2.4 Crearea paginilor folosind modulul views
3. Crearea unui modul de listare a punctelor de interes
3.1 Structura fișierului .info
3.2 Structura fișierului .install
3.3 Fișierul .module
4. Sitemul de template-uri din Drupal
5. Administrarea site-ului
5.1 Administrarea utilizatorilor
5.2 Administrarea conținutului
5.3 Administrarea meniului
5.4 Administrarea termenilor de taxonomie
5.5 Administrarea view-urilor
5.6 Administrarea temelor și a modulelor
5.8 Administrarea altor componente
5.9 Rapoarte
6. Finalizarea și publicarea site-ului
6.1 Imagini din site
Bibliografie
1
1. Considerații
1.1 Rezumat
Lucrarea este împărțită în șase capitole:
prezintă date generale despre aplicație și tehnologiile folosite
cuprinde dezvoltarea site-ului folosind module existente în Drupal
tratează crearea modulelor si interacțiunea lor cu Drupal
explică sistemul de template-uri din Drupal
descrie modalitatea de administrare a site-ului
prezintă site-ul final
Descrierea aplicației
Lucrarea prezintă dezvoltarea unui director web care cuprinde principalele puncte de interes ale minicipiului Oradea: obiective turistice, restaurante, hoteluri, etc. Site-ul este util îndeosebi turiștilor care vizitează Oradea, având posibilitatea de a-și exprima părerea referitor la punctele de interes.
Aplicația web poate fi descompusă în mai multe părți individuale, prezentăm în continuare cele mai importante aspecte.
1.2.1 Conținutul site-ului
Având în vedere natura site-ului se pot distinge câteva tipuri de conținut:
articol
permite crearea unei pagini având titlu, descriere și imagini
folosit pentru diverse informații pe site
obiectiv
permite crearea unei pagini care conține detalii despre obiectivul turistic, imagini, locația pe harta
2
permite comentarii
permite clasificarea obiectivului într-o anumită categorie
utilizatorii pot să evalueze obiectivul (de la 1 la 5 stele)
Obiectivele turistice pot fi găsite cu ajutorul căutarilor pe site. Sunt necesare două tipuri de căutari:
listare
fiecare obiectiv va fi listat sub o formă minimală
lista poate avea filtre pe categorie sau pe text
lista are paginare în cazul în care numărul de obiective pe o pagină este prea mare
pe hartă
fiecare obiectiv va apărea pe hartă în locația lui exactă
poate avea filtre pe categorie sau text
adițional, pe hartă va apărea și locația curentă a utilizatorului (cu aproximație)
Utilizatorii
Utilizatorii pot fi împărțiți în diferite categorii, fiecare având roluri si permisiuni diferite:
utilizatorul cu rolul de administrator
nu are nicio restricție
poate administra orice aspect al site-ului
utilizatorul înregistrat în site-ul web
are acces la propriul profil
poate adăuga conținut
poate adăuga comentarii
poate evalua obiective
utilizatorul anonim
poate vizualiza conținutul publicat pe site
poate să își creeze cont pe site devenind astfel utilizator înregistrat
3
Având în vedere rolurile prezentate mai sus se poate subînțelege existența formularelor de conectare la site (login), înregistrare în site (register) sau recuperare parolă (password request).
1.2.3 Design-ul site-ului
Design-ul unui site web este o componentă foarte importantă. Având în vedere că noile tendințe sunt telefoanele și tabletele este esențial ca design-ul să fie unul responsiv, în acest fel site-ul poate fi vizualizat cu ușurință atât de pe laptop/desktop cât și de pe dispozitivele mobile telefon/tabletă.
1.3 Alegerea tehnologiilor
Pentru a alege tehnologiile potrivite trebuie să evaluăm problemele sau necesitățile noastre în crearea aplicației. În mare parte aplicația trebuie să fie un CMS (Content Management System) dar și un CMF (Content Management Framework) pentru a o putea extinde ușor. De asemenea limbajul de programare trebuie sa fie unul specific pentru web, astfel pentru acest site am ales Drupal 7 având ca bază de date MySQL.
1.3.1 Despre Drupal
Drupal este un proiect open source scris în PHP care permite crearea și administrarea conținutului în numeroase moduri. A început în anul 1999 ca un simplu forum, iar pe parcursul anilor s-a extins foarte mult, fiind folosit de companii și instituții de nivel global (AOL, Twitter, Examiner.com, White House, MTV, Harvard, MIT, etc.)[1]. Numeroasa comunitate din spatele Drupal aduce mereu îmbunătățiri prin intermediul modulelor, repară și previne erorile de securitate. Sistemul din spatele Drupal este unul abstractizat și permite multe configurări folosind doar interfața de administrare a site-ului.
Alte tehnologii folosite
Design site
HTML
CSS (incluzând un sistem de grid)
Adobe Photoshop (elemente de design + logo)
4
Module Drupal
PHP
JavaScript + jQuery
Baze de date
MySQL + phpMyAdmin
Server web
Apache 2
Editor text
Komodo Edit
Sistem versionare
Git
5
Dezvoltarea aplicației folosind module existente
Alegerea modulelor necesare
Drupal oferă în nucleul său numeroase module standard, dar de cele mai multe ori comunitatea pune la dispoziție module ce extind functionalitățile site-ului.
Pentru a ușura dezvoltarea site-ului sunt necesare anumite module create special pentru programator sau administrator:
admin_menu – https://drupal.org/project/admin_menu
oferă un meniu de administrare mai ușor de folosit decât meniul Drupal standard
module_filter – https://drupal.org/project/module_filter
oferă posibilitatea de a căuta în timp real un modul existent în site
devel – https://drupal.org/project/devel
numeroase instrumente pentru dezvoltator în scopul depanării site-ului
drush
nu este un modul, este un program ce permite descărcarea și instalarea automată a modulelor folosind comenzi scurte în linia de comandă
Pentru a abstractiza cât mai mult componentele site-ului și pentru a folosi metode standard adoptate de întreaga comunitate Drupal se folosesc modulele:
entity – https://www.drupal.org/project/entity
oferă un API central pentru a lucra cu entitățile din Drupal
ctools – https://www.drupal.org/project/ctools
oferă un API pentru a crea plugin-uri, contexte, pagini cu AJAX, formulare, ferestre modale, etc.
libraries – https://www.drupal.org/project/libraries
permite adăugarea de biblioteci externe în Drupal
jquery_update – https://www.drupal.org/project/jquery_update
oferă posibilitatea de a folosi diverse versiuni ale bibliotecii jQuery (JavaScript)
6
Având în vedere că site-ul trebuie să prezinte locația obiectivului pe hartă sunt necesare anumite module ce oferă această posibilitate. Așadar, vom folosi următoarele module ce țin de geolocație:
addressfield – https://www.drupal.org/project/addressfield
definește un nou tip de câmp ce poate fi atașat entităților prin care se poate introduce o adresă
geofield – https://www.drupal.org/project/geofield
ajută la stocarea datelor de tip geo (punct, linie, poligon, etc.)
oferă diferite moduri de formatare
geofield_gmap – https://www.drupal.org/project/geofield_gmap
oferă widget și stil de formatare pentru Google Maps
integrat cu modulul geofield
geocoder – https://www.drupal.org/project/geocoder
transformă orice adresă sau locație într-o geolocație
integrat cu modulele addressfield și geofield
ip_geoloc – https://www.drupal.org/project/ip_geoloc
integrat cu numeroase API-uri pentru geolocație (Leaflet, Google)
oferă posibilitatea de a găsi geolocația utilizatorului după adresa IP
leaflet – https://www.drupal.org/project/leaflet
serviciu open source ce oferă hărți interactive fără a avea nevoie de API key
integrat cu browserele mobile
leaflet_more_maps – https://www.drupal.org/project/leaflet_more_maps
conține numeroase versiuni de hărți
Pentru a permite evaluarea punctelor de interes de către utilizatori vom folosi modulul fivestar (https://www.drupal.org/project/fivestar). Acest modul este scris peste modulul votingapi (https://www.drupal.org/project/votingapi) ce ofera o modalitate standard de evaluare a conținutului de pe site.
Crearea de pagini dinamice folosind tipuri de conținut existente se face cu ajutorul modulului views (https://www.drupal.org/project/views). O interfață de administrare a paginilor ne este oferită de către sub-modulul views_ui. Cu ajutorul modulului views putem configura în cele
7
mai mici detalii modul în care este afișat un conținut sau o listare de conținut. Avem chiar și posibilitatea de a filtra, grupa sau sorta conținutul.
2.2 Alegerea unui design
Drupal oferă un sistem ce permite schimbarea design-ului unui site prin aplicarea de teme (themes). Fiecare temă oferă regiuni – locuri unde diferite bucăți din conținutul site-ului (blocks) pot fi plasate (fig. 2.2.1).
Fig. 2.2.1 – Demonstrarea regiunilor pentru tema Corporate Clean
Cu toate că putem oricând schimba tema site-ului este bine ca aceasta să fie utilizată chiar de la început pentru a putea vizualiza mai ușor dezvoltarea site-ului. Ca temă de bază pentru acest site am ales Corporate Clean (https://www.drupal.org/project/corporateclean) deoarece este responsivă (fig. 2.2.2 și 2.2.3), culorile ei pot fi configurate ușor (fig 2.2.4) și oferă multe alte setări, toate disponibile în interfața de administrare a site-ului.
8
Fig. 2.2.2 – Varianta desktop Fig. 2.2.3 – Varianta mobile
Fig. 2.2.4 – Configurarea culorilor pentru tema Corporate Clean
9
2.3 Crearea tipurilor de conținut
Aproape orice conținut din Drupal este abstractizat de entități: utilizatori, termeni de taxonomie, articole, etc. La baza lor, entitățile sunt formate din proprietăți și câmpuri (field-uri) de diverse tipuri. O proprietate poate avea o singură valoare scalară, pe când field-urile pot avea multiple valori compuse. Fiecare tip de entitate poate oferi diferite variante (bundles) ce contin diferite field-uri. Cele mai importante setări pentru un field sunt:
tipul de widget – modul in care datele sunt introduse în field
formatter – modul în care datele sunt afișate pe pagină într-un anumit view mode – fiecare bundle poate avea diverse moduri de vizualizare (view modes)
numărul de valori acceptate
Entitatea de bază pentru conținut în Drupal este node-ul, el oferă implicit două bundle-uri:
basic page – conține doar proprietatea de titlu și field-ul pentru descriere
article – conține titlu, descriere, imagini și termeni de taxonomie pentru a categoriza articolul
Adițional la node-uri se pot atașa comentarii dacă se dorește.
În continuare vom crea un nou bundle pentru node ce va conține field-urile necesare unui punct de interes:
Fig. 2.3.1 – Widget field Location
10
Term
Category Select list reference
Fig. 2.3.3 – Widget field Category
Fig. 2.3.4 – Widget field Body
11
Field-ul Location salvează informații despre locația punctului de interes: țară, adresă, oraș, cod poștal. Toate aceste câmpuri pot fi configurate cu ajutorul interfeței de administrare.
Field-ul Geofield salvează informații despre geolocația punctului de interes: latitudine și longitudine. Deoarece pentru utilizatorii normali este dificilă introducerea acestor informații, ele se autocompletează cu ajutorul modulului geocoder folosind valorile field-ului Location.
Field-ul Images poate conține un număr nelimitat de imagini ale punctului de interes. În mod obligatoriu, orice punct de interes trebuie să conțină cel puțin o imagine.
Field-ul Vote stochează rating-ul dat de utilizatori punctului de interes. Valoarea lui este actualizată în mod automat atunci când un utilizator acordă un rating.
Field-ul Category referențiază diverși termeni de taxonomie pentru a specifica din ce categorie face parte punc1
Field-ul Location salvează informații despre locația punctului de interes: țară, adresă, oraș, cod poștal. Toate aceste câmpuri pot fi configurate cu ajutorul interfeței de administrare.
Field-ul Geofield salvează informații despre geolocația punctului de interes: latitudine și longitudine. Deoarece pentru utilizatorii normali este dificilă introducerea acestor informații, ele se autocompletează cu ajutorul modulului geocoder folosind valorile field-ului Location.
Field-ul Images poate conține un număr nelimitat de imagini ale punctului de interes. În mod obligatoriu, orice punct de interes trebuie să conțină cel puțin o imagine.
Field-ul Vote stochează rating-ul dat de utilizatori punctului de interes. Valoarea lui este actualizată în mod automat atunci când un utilizator acordă un rating.
Field-ul Category referențiază diverși termeni de taxonomie pentru a specifica din ce categorie face parte punctul de interes. Pentru acest lucru am creat un nou vocabular numit Categories în care se pot adăuga termeni de taxonomie. Valorile ce le poate avea acest câmp pot fi doar din vocabularul Categories.
Fig. 2.3.5 – Administrarea termenilor de taxonomie pentru vocabularul Categories
12
Field-ul Body salvează descrierea obiectivului. Widget-ul său este de tip WYSIWYG (what you see is what you get), acesta permițând stilizarea textului.
Proprietate Title salvează titlul paginii punctului de interes, fiind implicită în entitatea de tip node.
Acum că avem definit tipul nostru de conținut puteam adăuga câteva obiective de test, deoarece pasul următor este crearea a diferite moduri de vizualizare pentru node. Drupal vine cu două view mode-uri prestabilite pentru node: default (pagina node-ului) și teaser (o bucată reprezentativă din node ce este folosită de obicei în listări).
În view mode-ul default vom afișa toate câmpurile entității împreună cu setăriile din fig. 2.3.6:
Fig. 2.3.6 – Default view mode
Observăm că pentru field-ul Vote s-a folosit formatter-ul As Stars ce ne va arăta media rating-ului dat de utilizatori, pentru Geofield s-a folosit o hartă cu diverse setări de control, pentru Images o galerie jQuery, iar pentru Category un link către termenul de taxonomie.
În view mode-ul teaser vom ascunde doar câmpul Geofield, setările sunt prezente în fig. 2.3.7:
Fig. 2.3.7 – Teaser view mode
13
2.4 Crearea paginilor folosind modulul views
Prima pagină creată cu views va fi o hartă ce conține toate punctele de interes înregistrate în sistem, iar acestea vor putea fi filtrate după titlu. Începem prin a crea un nou view:
navigăm pe pagina /admin/structure/views
alegem opțiunea “Add new view”
ca și nume folosim “Obiective turistice”
alegem “Show Content of type Obiectiv sorted by Newest first”
bifăm opțiunea “Create a page” și setăm titlul paginii “Obiective turistice Oradea”
path-ul va fi obiective-turistice
display format-ul va fi “Map (Leaflet API, via IPGV&M)”
numarul de itemi afișați va fi 100 și se debifează opțiunea de a crea paginare
Fig. 2.4.1 – Crearea unui view folosind interfața
după salvare, adăugăm trei field-uri în view:
Content: Title – titlul obiectivului, la setări alegem opțiunea “Link this field to the original piece of content” pentru a crea o legătură către pagina obiectivului și debifăm opțiunea “Create a label”
14
Content: Geofield – acest field nu va fi afișat dar este necesar pentru a extrage geolocația, astfel vom alege opțiunea “Exclude from display” iar ca formatter “Well Known Text (WKT)”
Content: Location – adresa obiectivului
modificăm configurația de formatare “Map (Leaflet API, via IPGV&M)” a view-ului:
Map – Google roadmap 0..18 (tipul de hartă)
Map height – 400px (dimensiune hartă)
Name of latitude field in Views query – Content: Geofield (preluare geolocație din field-ul Geofield al node-ului)
Name of longitude field in Views query – <none>
Default location marker – blue (culoarea marker-ului care indică obiectivul)
Map centering options – Center the map on the visitor's current location (harta va fi centrată în funcție de locația utilizatorului detectată cu ajutorul modulului ip_geoloc)
Visitor marker – orange (culoarea marker-ului care indică locația utilizatorului)
adăugăm filtre pentru conținut
Content: Published = Yes (afișăm doar conținut publicat)
Content: Type = Obiectiv (se afișează doar node-urile care au bundle Obiectiv)
Content: Title (exposed) – pune acest filtru la dispoziția utilizatorului care va putea introduce text pentru a căuta puncte de interes
se bifează opțiunea “Expose this filter to visitors, to allow them to change it”
se alege ca și operator “contains”
se pune la dispoziția oricărui utilizator
se salvează setările pentru field apoi în views se alege “Exposed form style” ca fiind “basic” fără a folosi “Expose sort order”
se salvează view-ul și se testează pagina
Pe lângă această pagină se vor crea și altele în mod similar.
15
Fig. 2.4.2 – Configurația finală a view-ului
Fig. 2.4.3 – Harta creată cu ajutorul modulului views
16
3. Crearea unui modul de listare a punctelor de interes
Pentru a crea un modul compatibil cu Drupal trebuie urmate câteva reguli simple și clare:
directorul în care se află modulul are același nume ca și modulul și se va pune în directorul sites/all/modules
fiecare modul are un fișier .info unde se descrie pe sine
opțional, codul de instalare se pune în fișierul .install
codul principal al modulului va fi într-un fișier .module
codul trebuie scris respectând standardele
În următoarele pagini vom descrie fiecare pas pentru crearea unui modul de listare a punctelor de interes având două tipuri de filtre. Numele modulului va fi licenta.
3.1 Structura fișierului .info
Exemplu de fișier .info:
name = Super Modul description = Descriere modul core = 7.x
package = Module licenta
configure = admin/config/super_module
dependencies[] = module_x dependencies[] = module_y
files[] = path/NumeClasa.inc files[] = path/NumeClasaX.inc
scripts[] = path/javascript.js scripts[] = path/javascript2.js
stylesheets[all][] = path/style.css stylesheets[all][] = path/style2.css
php = 5.3
; nu este indicată scrierea manuală a versiunii version = 1.0
17
Proprietăți ce se pot folosi în fișierul .info[2]:
name (obligatoriu)
numele modulului care dorești să apară în pagina de administrare a modulelor
fiecare cuvând din nume trebuie să înceapă cu majuscule
trebuie să fie cât mai sugestiv și să fie ușor de citit
description (obligatoriu)
o scurtă descriere de maximum 255 de caractere care explică utilitatea modulului
trebuie să fie pe o singură linie
poate conține link-uri
core (obligatoriu)
versiunea de Drupal pentru care este acest modul
pentru Drupal 7 aceasta trebuie să fie 7.x (7.2 nu este corect)
package (opțional, implicit este Others)
categoria din care face parte modulul
modulele ce sunt în aceeași categorie servesc un scop comun
configure (opțional)
calea către pagina de configurare a modulului
dependencies (opțional)
modulele de care depinde acest modul
files (opțional)
fișiere PHP folosite cu auto-loading (se încarcă automat doar atunci când este nevoie de ele)
stylesheets (opțional)
fișiere CSS care trebuie încărcate pe fiecare pagină
scripts (opțional)
fișiere JavaScript care trebuie încărcate pe fiecare pagină
atât fișierele JavaScript cât și cele CSS pot fi agregate dacă se folosește această metodă
php (opțional)
versiunea minimă de PHP în care modulul funcționează corect
version (descurajat)
versiunea modulului – aceasta se poate obține automat folosind git deploy
18
Având aceste informații putem crea fișierul licenta.info în interiorul directorului licenta.
name = Listarea Obiectivelor
description = Listarea obiectivelor folosind filtre pe titlu si pe categorie package = Licenta
core = 7.x
3.2 Structura fișierului .install
Fișierul .install conține un număr limitat de hook-uri ce ajută la instalare/dezinstalarea, activarea/dezactivare și actualizarea modulului.
Un hook este o funcție în PHP care extinde funcționalitatea Drupalului sau a altor module. Hook-urile începe cu numele modulului în care se implementează urmat de numele hook-ului, iar fiecare hook are un set specific de parametri precum și o valoare specifică de return.
Hook-uri utile în fișierul .install:
hook_install()
apelat atunci când modulul se instalează
hook_uninstall()
apelat la dezinstalarea modulului
hook_schema()
apelat la instalarea modulului
returnează o schemă ce definește tabelele SQL necesare modulului
hook_enable()
apelat la activarea modulului
hook_disable()
apelat la dezactivarea modulului
hook_update_N()
ajută la actualizarea modulelor
19
Exemplu de hook_schema()[3] care creează două tabele cu diverse câmpuri, indecși și legături:
/**
* Implemeents hook_schema() */
function mymodule_schema() { $schema = array();
$schema['people'] = array(
'description' => 'Table containing users', 'fields' => array(
'id' => array(
'description' => 'Primary key for user', 'type' => 'serial', //auto-increment 'unsigned' => TRUE,
'not null' => TRUE,
),
'name' => array(
'description' => 'User name', 'type' => 'varchar',
'length' => 255, 'not null' => TRUE, 'default' => '',
),
'age' => array(
'description' => 'User age', 'type' => 'int',
'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0,
),
),
'primary key' => array('id'),
);
$schema['friends'] = array(
'description' => 'Friendship relations among people', 'fields' => array(
'pid' => array(
'description' => 'User id from {people} table', 'type' => 'int',
'unsigned' => TRUE, 'not null' => TRUE,
),
'fid' => array(
'description' => 'Friend id from {people} table', 'type' => 'int',
'unsigned' => TRUE, 'not null' => TRUE,
20
),
'since' => array(
'description' => 'Timestamp indicating when users became friends', 'type' => 'int',
'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0,
),
),
'indexes' => array(
'user_id' => array('pid'), 'friend_id' => array('fid'),
),
'foreign keys' => array( 'people' => array(
'table' => 'people', 'columns' => array(
'pid' => 'id', 'fid' => 'id',
),
),
),
);
return $schema;
}
În acest mod putem avea aceeași structură de tabele pe diferite sisteme de gestiune a bazelor de date (MySQL, PostgreSQL, SQLite, etc.) fără a fi nevoiți să schimbăm codul.
Modulul licenta nu are nevoie de un fișier de install.
3.3 Fișierul .module
În fișierul .module se scrie cea mai mare parte din logica modulului. Începem prin a defini o rută deniumită list către pagina de listare folosind hook_menu().
/**
* Implements hook_menu(). */
function licenta_menu() { $items['list'] = array( 'title' => '',
'description' => '',
21
'page callback' => 'licenta_list_render', 'access callback' => TRUE,
'type' => MENU_CALLBACK, );
return $items;
}
Page callback definește funcția ce va fi apelată atunci când se accesează ruta list, în cazul nostru funcția va fi licenta_list_render(). Access callback specifică faptul ca ruta poate fi accesată de oricine.
/**
* Menu callback for /list path. */
function licenta_list_render() {
$category = (int) @$_GET['categ']; $title = trim(@$_GET['item']);
// Get results.
$data = licenta_list($title, $category, 5);
// No results.
if (!$data['count']) {
return t('Sorry! There are no results for your search!');
}
Get category name. if ($category) {
$category = $category->name;
}
Render each result.
foreach ($data['results'] as &$node) {
Get the renderable array of teaser view mode. $node = node_view($node, 'teaser');
Keep only the first image.
$one_img = $node['field_images']['#items'][0]; unset($node['field_images']['#items']); $node['field_images']['#items'][] = $one_img; // Render the node.
$node = drupal_render($node);
}
// Get the safe page title. if ($title) {
if ($category) {
22
$safe_title = t("@count results for '@search' in @category", array( '@count' => $data['count'],
'@search' => $title, '@category' => $category, ));
}
else {
$safe_title = t("@count results for '@search'", array( '@count' => $data['count'],
'@search' => $title, ));
}
}
elseif ($category) {
$safe_title = t("@count results in @category", array( '@count' => $data['count'],
'@category' => $category, ));
}
else {
$safe_title = t("@count results", array( '@count' => $data['count'],
));
}
// Add page title.
$output = "<h1 class='list-ob-title'>"; $output .= $safe_title;
$output .= "</h1>";
// Add result list.
$output .= theme('item_list', array( 'items' => $data['results'],
'type' => 'ul',
'attributes' => array('id' => 'menu_bar_links'), ));
// Add pager.
$output .= theme('pager');
return $output;
}
Această funcție prezintă modul în care sunt tratate textele ce pot fi traduse cu ajutorul funcției t(), modul în care putem randa node-uri folosind un view mode specific dar și diverse funcții de tema oferite de Drupal (cum ar fi item_list) sau crearea unui paginator. Un alt lucru notabil este
23
faptul ca Drupal lucrează cu așa numitele array-uri randabile, permițând astfel stilizarea lor într-un mod foarte granularizat.
De asemenea, observăm ca am folosit o nouă funcție denumită licenta_list(), scopul acesteia este de a returna numărul total de rezultate ce l-a avut căutarea și primele N node-uri având bundle-ul Obiectiv.
Acest lucru este posibil datorită abstractizării modului în care se pot căuta entități având diverse proprietați folosind clasa EntityFieldQuery. Cu EntityFieldQuery[4] putem adăuga filtre pentru tipul și bundle-ul entității sau pentru proprietăți și field-uri. Evident, avem posibilitatea de a sorta rezultatele după diferite proprietăți sau field-uri sau de a limita numărul lor oferindu-ne totodată și posibilitatea de a crea o paginare pentru această interogare.
/**
Returns all nodes using category and title filter.
@param string $title Title filter
@param int $category Taxonomy term id
@param int $limit Maximum number of results
@return array An array containing the result count and entities. */
function licenta_list(&$title = NULL, &$category = 0, $limit = 5) {
Create a new EntityFieldQuery in order to find entities. $query = new EntityFieldQuery();
Filter by entity type and bundle.
$query->entityCondition('entity_type', 'node') ->entityCondition('bundle', 'obiectiv');
// Search only published nodes. $query->propertyCondition('status', 1);
Add title filter if any. if ($title) {
$query->propertyCondition('title', '%' . $title. '%', 'like');
}
Add category filter if any.
if ($category > 0 && $category = taxonomy_term_load($category)) { $query->fieldCondition('field_categorie', 'tid', $category->tid, '=');
24
}
else {
$category = NULL;
}
// Sort results by creation time descending. $query->propertyOrderBy('created', 'DESC');
// Create pager. $query->pager($limit);
// Count the results.
$count = $query->count()->execute();
if ($count > 0) { // Get the results.
$query->count = FALSE; $nodes = $query->execute(); unset($query);
$nodes = reset($nodes);
$nodes = node_load_multiple(array_keys($nodes));
}
else {
$nodes = array();
}
return array( 'count' => $count, 'results' => $nodes, );
}
În acest moment avem o pagină funcțională dar problema este că trebuie să adăugăm parametri manual în URL pentru a vedea filtrarea în acțiune. Următorul pas este cel de a crea un formular de căutare și de a-l expune utilizatorului.
Crearea de formulare se face cu ajutorul Drupal Form API[5], acesta fiind bazat pe array-uri randabile. Form API oferă o mulțime de elemente: textbox, textarea, selectbox, checkbox, radio, file upload, etc. dar permite și definirea de noi elemente implementând hook_element_info().
25
/**
* Search form for /list route. */
function licenta_search_form($form, &$form_state) {
// Use the GET method. $form['#method'] = 'GET';
Set the action to our list router. $form['#action'] = '/list';
Add a css class to form.
$form['#attributes']['class'][] = 'input-append';
Create the title filter. $form['item'] =array(
'#type' => 'textfield', '#title' => '',
'#default_value' => trim(@$_GET['item']), '#attributes' => array('class' => array('grid_3'))
);
Create a hidden category which will be populated in other way. $form['categ'] =array(
'#type' => 'hidden', '#title' => '',
'#default_value' => @$_GET['categ'],
);
Add a custom submit button.
$form['search'] = array( '#type' => 'markup',
'#markup' => '<div class="search-abs grid_3"><i class="btn hidden-phone add-on icon-search"></i></div>',
);
return $form;
}
Deoarece Drupal securizează formularele cu ajutorul unor token-uri, URL-ul rezultat este destul de lung, prin urmare putem elimina aceste măsuri de securitate deoarece funcția licenta_list() tratează problemele de securitate. Așadar, vom implementa hook_form_FORM_ID_form_alter() pentru a șterge elementele nedorite din formular.
26
/**
* Implements hook_form_FORM_ID_form_alter(). */
function licenta_form_licenta_search_form_alter(&$form, &$form_state) { $remove = array('form_build_id', 'form_token', 'form_id', 'op');
foreach ($remove as $property) { unset($form[$property]);
}
}
Afișarea formularului și a filtrelor pentru categorie se va face folosind block-uri. După cum precizam anterior, block-urile sunt bucăți de conținut ce se pot plasa în diferite regiuni ale temei.
Pentru a crea block-uri trebuie să informăm Drupalul de existența lor, utilizând hook_block_info():
/**
* Implements hook_block_info(). */
function licenta_block_info() {
// Search form block. $blocks['licenta_search_item'] = array(
Info about block, shown in blocks manager. 'info' => t('Search form'),
Desired theme region, can be changed from UI. 'region' => 'search_area',
Block is active.
'status' => 1,
);
// Category filter block. $blocks['licenta_categories_facet'] = array(
'info' => t('Categories'), 'region' => 'sidebar_first', 'status' => 1,
);
return $blocks;
}
27
Conținutul propriu-zis al block-urilor se creează folosind hook_block_view(). Acest hook primește ca parametru numele block-ului, astfel fiecare block din hook_block_info() trebuie tratat separat.
Cea mai indicată soluție în acest caz este folosirea instrucțiunii switch din PHP.
/**
* Implements hook_block_view(). */
function licenta_block_view($block_name) {
// Treat each block individually. switch ($block_name) {
// Category filter block.
case 'licenta_categories_facet': // Get the vocabulary id.
$vocabulary = taxonomy_vocabulary_machine_name_load('categorie'); // Load all taxonomy terms from vocabulary.
$terms = taxonomy_term_load_multiple(array(), array('vid' =>
$vocabulary->vid));
Here will be added all term links. $items = array();
Add All as first filter, like a reset. $items[] = l(t('All'), '/list');
Add each term as a filter. foreach ($terms as $term) {
$items[] = l($term->name, '/list', array( 'query' => array('categ' => $term->tid),
));
}
return array(
// Block title.
'subject' => t('Categories'), // Block content.
'content' => theme('item_list', array( 'items' => $items,
'type' => 'ul',
'attributes' => array('id' => 'categories-facet'),
)),
);
// Form filter block.
case 'licenta_search_item': // Get form by name.
$form = drupal_get_form('licenta_search_from');
return array(
28
No title. 'subject' => '',
Render the form.
'content' => drupal_render($form)
);
}
}
Cu acestea am încheiat procesul de creare a modulului licenta. În următorul capitol vom analiza partea de template-uri a sistemului de teme din Drupal. Rezultatul obținut ar trebui să fie ca în fig. 3.3.1.
Fig. 3.3.1 – Listarea creată de modulul licenta
29
4. Sitemul de template-uri din Drupal
Temele din Drupal permit editarea fiecărei părți din site prin fișiere de template. Fișiere de template au extensia .tpl.php, iar numele lor este legat de numele entităților, a view mode-urilor, a block-urilor sau a altor elemente. De obicei temele sunt salvate în directorul sites/all/themes, având o structură asemănătoare modulelor. Figura 4.1 ne prezintă într-un mod detaliat structura de fișiere și corespondența lor în pagina web.
Fig. 4.1 – Structura unei teme Drupal
30
În următoarele pagini vom arăta două exemple de fișiere de template, restul fișierelor având o structură asemănătoare. Tema aleasă este Corporate Clean, deci fișierele de template se vor afla în directorul sites/all/themes/corporateclean.
Template-ul page.tpl.php cuprinde tot corpul site-ului mai puțin partea de head unde se declară titlul pagini, dependințe de stil, scripturi sau alte meta-informații. Acest template este foarte important deoarece aici se vor randa regiunile pe care tema le pune la dispoziție prin declararea lor în fișierul .info. Un exemplu simplu al acestui template poate fi găsit în interiorul temei Garland oferită de Drupal 7:
<?php print render($page['header']); ?> <div id="wrapper">
<div id="container" class="clearfix">
<div id="header">
<div id="logo-floater">
<?php if ($logo || $site_title): ?> <?php if ($title): ?>
<div id="branding"><strong><a href="<?php print $front_page ?>"> <?php if ($logo): ?>
<img src="<?php print $logo ?>" alt="<?php print $site_name_and_slogan ?>" title="<?php print $site_name_and_slogan ?>" id="logo" />
<?php endif; ?>
<?php print $site_html ?> </a></strong></div>
<?php else: /* Use h1 when the content title is empty */ ?>
<h1 id="branding"><a href="<?php print $front_page ?>"> <?php if ($logo): ?>
<img src="<?php print $logo ?>" alt="<?php print $site_name_and_slogan ?>" title="<?php print $site_name_and_slogan ?>" id="logo" />
<?php endif; ?>
<?php print $site_html ?> </a></h1>
<?php endif; ?> <?php endif; ?> </div>
<?php if ($primary_nav): print $primary_nav; endif; ?> <?php if ($secondary_nav): print $secondary_nav; endif; ?>
</div> <!– /#header –>
<?php if ($page['sidebar_first']): ?>
<div id="sidebar-first" class="sidebar"> <?php print render($page['sidebar_first']); ?> </div>
31
<?php endif; ?>
<div id="center"><div id="squeeze"><div class="right-corner"><div class="left-corner">
<?php print $breadcrumb; ?>
<?php if ($page['highlighted']): ?><div id="highlighted"><?php print render($page['highlighted']); ?></div><?php endif; ?>
<a id="main-content"></a>
<?php if ($tabs): ?><div id="tabs-wrapper" class="clearfix"><?php endif; ?> <?php print render($title_prefix); ?>
<?php if ($title): ?>
<h1<?php print $tabs ? ' class="with-tabs"' : '' ?>><?php print
$title ?></h1>
<?php endif; ?>
<?php print render($title_suffix); ?>
<?php if ($tabs): ?><?php print render($tabs); ?></div><?php endif; ?> <?php print render($tabs2); ?>
<?php print $messages; ?>
<?php print render($page['help']); ?> <?php if ($action_links): ?>
<ul class="action-links"><?php print render($action_links); ?></ul> <?php endif; ?>
<div class="clearfix">
<?php print render($page['content']); ?> </div>
<?php print $feed_icons ?>
<?php print render($page['footer']); ?>
</div></div></div></div> <!– /.left-corner, /.right-corner, /#squeeze, /#center –>
<?php if ($page['sidebar_second']): ?>
<div id="sidebar-second" class="sidebar"> <?php print render($page['sidebar_second']); ?> </div>
<?php endif; ?>
</div> <!– /#container –> </div> <!– /#wrapper –>
Se poate observa că în interiorul template-urilor sintaxa PHP este puțin diferită, într-un mod natural și nu cu acolade. Acest lucru este foarte util deoarece permite adăugarea de wrappere elementelor foarte ușor. Diferențele se pot observa în următoarele două exemple:
<?php foreach ($items as $item) { ?> <div class="wrapper-big">
<?php if ($item != $except) { ?> <div class="wrapper-small">
32
<?php echo $item;?>
</div> <?php}?>
</div> <?php}?>
Problema cu această variantă e ca nu se distinge foarte clar care instrucțiune este închisă de acolade. Datorită faptului că PHP are și o sintaxă specială pentru aceste cazuri problema noastră se rezolvă foarte simplu:
<?php foreach ($items as $item): ?> <div class="wrapper-big">
<?php if ($item != $except): ?> <div class="wrapper-small">
<?php echo $item;?>
</div> <?phpendif;?>
</div>
<?phpendforeach;?>
Pentru a adapta după bunul plac un view mode al unui node se poate crea un template cu structura numelui node–[bundle]–[view-mode].tpl.php. În cazul nostru vom edita view mode-ul teaser al node-ului cu bundle Obiectiv, adică cel care se folosește în listări. Urmând tiparul descris, numele fișierului va fi node–obiectiv-teaser.tpl.php (pentru a edita template-ul pentru întreg bundle-ul se exclude numele view mode-ului: node-obiectiv.tpl.php).
În acest template trebuie tratate individual proprietățile și field-urile pentru view mode-ul teaser folosind sistemul de grid oferit de temă, deoarece putem aranja foarte ușor conținutul.
<?php
// node–obiectiv–teaser.tpl.php global $basePath;
?>
<div class="item grid_8 list-teaser">
<div id="image-teaser" class="grid_2 hidden-phone"> <?php if (!empty($content['field_images'])): ?>
<?php echo drupal_render($content['field_images']);?> <?php endif; ?>
</div>
<div id="info-teaser" class="grid_6"> <div class="border">
33
<div class="title grid_4"> <?php if (!empty($title)): ?>
<h3><a href="<?php echo $basePath . $node_url;?>"><?php echo $title;?></a></h3> <?php endif; ?>
</div>
<div class="categ grid_2 hidden-phone">
<?php if (!empty($content['field_categorie'])): ?>
<?php echo drupal_render($content['field_categorie']);?>
<?php endif; ?> </div>
</div>
<div class="row2-loc-rat"> <div class="rating grid_2">
<?php if (!empty($content['field_vote'])): ?>
<?php echo drupal_render($content['field_vote']);?>
<?php endif; ?> </div>
<div class="loc grid_3">
<?php if (!empty($content['field_location'])): ?> <?php
$location = $content['field_location']['#items'][0]; $address = $location['locality'] . $location['postal_code'];
if (!empty($location['thoroughfare'])) { $address .= ', ' . $location['thoroughfare'];
}
echo drupal_render($content['field_categorie']); ?>
<i class="icon-map-marker"> <?php echo $address; ?></i> <?php endif; ?>
</div>
<div class="desc grid_6">
<?php if (!empty($content['body'])): ?>
<?php echo drupal_render($content['body']);?> <?php endif; ?>
</div> </div> </div>
</div>
Rezultatul acestui template este asemănător cu fig. 4.2.
34
Fig. 4.2 – Teaser view mode creat cu template-ul node–obiectiv–teaser.tpl.php
Desigur, în componența site-ului sunt și alte fișiere de template, dar am ales să nu le prezentăm deoarece implementarea lor se face în mod similar.
35
5. Administrarea site-ului
Administrarea site-ului se face cu foarte mare ușurința deoarece toate componentele pot fi configurate folosind o interfață web. Evident, doar utilizatorul cu drepturi de administrare poate face acest lucru.
5.1 Administrarea utilizatorilor
Utilizatorii înregistrați pot fi administrați accesând /admin/people. Avem posibilitatea de a adăuga, șterge, modifica sau bloca utilizatori. Totodată avem posibilitatea de a adăuga diferite roluri și de a defini permisiuni pentru fiecare rol în parte.
5.2 Administrarea conținutului
Administrarea conținutului se poate face accesând /admin/content. Avem posibilitatea de a adăuga, șterge și edita conținutul sau comentariile atașate. Pentru a modifica structura un tip de conținut este necesară accesarea /admin/structure/types. Aici vom putea modifica field-urile pentru fiecare tip de conținut în parte.
5.3 Administrarea meniului
Meniul poate fi configurat accesând /admin/structure/menu. Există diferite tipuri de meniuri, cel mai important fiindmeniul principal. Putem adăuga, șterge și modifica meniul principal sau putem adăuga unii itemi din meniu în meniul secundar, precum se poate observa în fig. 5.3.1.
Fig. 5.3.1 – Administrarea meniului principal
36
5.4 Administrarea termenilor de taxonomie
Termenii de taxonomie ne ajută să clasificăm conținutul, să-l punem în diverse categorii. Termenii sunt atașați unor vocabulare care au rolul de a explica natura lor. Pentru a administra taxonomiile vom accessa /admin/structure/taxonomy apoi alegem vocabularul în care dorim să adăugăm, ștergem sau modificăm diferiți termeni. Având în vedere că și termenii de taxonomie sunt entități, le pot fi atașate diverse field-uri, editând un vocabular anume.
5.5 Administrarea view-urilor
Pentru a crea diferite pagini sau blocuri putem folosi modulul views. Acesta se poate accesa la /admin/structure/views, undeva putem alege din listă un view existăm ca sa-l edităm sau putem crea unul nou. Structura unui view poate fi destul de complexă după cum se poate observa și în capitolul 2.4.
Fig. 5.5.1 – Administrarea view-urilor
37
5.6 Administrarea temelor și a modulelor
Temele pot fi administrate accesând /admin/apperance. Putem schimba setarile temelor cum ar fi paleta de culor, dimensiunea fonturilor, etc. sau putem alege o altă tema. De reținut este faptul că administratorul are de obicei o altă temă.
Modulele pot fi instalate/dezinstalate accesând /admin/modules. Aici vedem descrierea fiecărui modul în parte precum și dependințele. Modulele care nu satisfac toate dependințele nu pot fi instalate. Pentru a dezactiva un modul trebuie întâi să dezactivăm toate modulele ce depind de el.
Dezactivarea unui modul nu implică ștergerea datelor create de modul, acest lucru se întâmplă doar la dezinstalare.
Fig. 5.6.1 – Administrarea modulelor
38
5.8 Administrarea altor componente
Pe lângă componentele menționate anterior, în Drupal mai există numeroase setări. Ele pot fi configurate accesând /admin/config. O scurtă listă a acestor setări cuprinde:
setări de performanță, caching, agregare de fișiere css sau js
setări de regiune și timp
setări pentru URL-uri
setări pentru limba site-ului sau traduceri
setări pentru fișiere sau stiluri de imagini
setări de tip firewall
Fig. 5.8.1 – Interfața de configurare Drupal
39
5.9 Rapoarte
Pentru a întreține un site web este obligatoriu nevoie de rapoarte. În Drupal aceste rapoarte conțin diverse informații: de la erori în codul PHP pâna la rapoarte ale serverului web. În mod implicit există următoarele tipuri de rapoarte:
starea site-ului – dacă modulele sunt actualizate, pentru a preveni găurile de securitate
loguri – mesaje de informare, atenționare sau erori în cod
404 – pagini inexistente
403 – pagini la care un utilizator nu are acces
top căutari – care au fost cuvintele cele mai căutate pe site
40
6. Finalizarea și publicarea site-ului
Ultimii pași în finalizarea unui site o reprezintă conținutul și traducerea acestuia în diferite limbi (dacă este cazul). Deoarece Drupal este format dintr-o comunitate foarte mare, găsim traduceri pentru aproape toate limbile, inclusiv limba română[6]. Traducerile se importă în site foarte simplu folosind modulul i18n (https://drupal.org/project/i18n) iar pentru textele rămase netraduse se poate folosi modulul l10n_client (https://drupal.org/project/l10n_client) care oferă o interfață de traducere a textului din pagina pe care se află utilizatorul. Acest lucru este foarte important datorită faptului că traducătorul poate vedea exact contextul în care s-a folosit o propoziție sau un cuvânt.
După ce site-ul a fost testat se poate publica pe server pentru a fi accesibil utilizatorilor. Există diferite metode de publicare: de la folosirea sistemelor de versionare până la folosirea programului drush.
6.1 Imagini din site
Prima pagină a site-ului prezintă un slideshow și un scurt istoric al orașului Oradea (fig. 6.1.1).
Fig. 6.1.1 – Prima pagină
41
Pagina unde utilizatorii pot să-și creeze un cont pe site sau să se autentifice (fig. 6.1.2). În cazul în care utilizatorul nu-și mai amintește parola, poate solicita recuperarea ei prin e-mail.
Fig. 6.1.2 – Pagina de autentificare
Profilul utilizatorului înregistrat (fig. 6.1.3). Aici utilizatorul poate modifica datele profilului său, cum ar fi avatarul.
Fig. 6.1.3 – Profilul utilizatorului
Pagina unui obiectiv (fig. 6.1.4) ne prezintă descrierea obiectivului împreună cu un slideshow de iamgini și locația lui exactă pe hartă. La apăsarea marker-ului de pe hartă se afișează adresa completă.
42
Fig. 6.1.4 – Pagina unui punct de interes
Tot pe această pagină, utilizatorii evaluează obiectivul oferind un număr de stele cuprins între unu și cinci sau lasă comentarii (fig. 6.1.5).
Fig. 6.1.5 – Adăugare comentarii
43
Bibliografie
Drupal 7 Module Development – Matt Butcher, Matt Farina, Ken Rickard, Greg Dunlap, Larry Garfield, John Albin Winkins – ISBN 1849511160
Drupal 7 Themes – Ric Shreves – ISBN 1849512760
Drupal 7 Views Cookbook – J. Ayen Green – ISBN 1849514348
Corporate Clean Theme – https://www.drupal.org/project/corporateclean
https://drupal.org/about
https://www.drupal.org/node/542202
https://api.drupal.org/api/drupal/modules!system!system.api.php/function/hook_schema/7
https://api.drupal.org/api/drupal/includes!entity.inc/class/EntityFieldQuery/7
https://api.drupal.org/api/drupal/developer!topics!forms_api_reference.html/7
https://localize.drupal.org/translate/languages/ro
44
Bibliografie
Drupal 7 Module Development – Matt Butcher, Matt Farina, Ken Rickard, Greg Dunlap, Larry Garfield, John Albin Winkins – ISBN 1849511160
Drupal 7 Themes – Ric Shreves – ISBN 1849512760
Drupal 7 Views Cookbook – J. Ayen Green – ISBN 1849514348
Corporate Clean Theme – https://www.drupal.org/project/corporateclean
https://drupal.org/about
https://www.drupal.org/node/542202
https://api.drupal.org/api/drupal/modules!system!system.api.php/function/hook_schema/7
https://api.drupal.org/api/drupal/includes!entity.inc/class/EntityFieldQuery/7
https://api.drupal.org/api/drupal/developer!topics!forms_api_reference.html/7
https://localize.drupal.org/translate/languages/ro
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: Dezvoltarea Unei Aplicatii Pentru Ghidarea Utilizatorilor Asupra Atractiilor Turistice (ID: 139126)
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.
