HUOM! Voit itse lisätä ja muuttaa sisältöä muokkaa-painikkeiden avulla

 Olet itse vastuussa tämän teoksen käytöstä aiheutuvista vahingoista Lue lisää.

Drupal ohjelmointi moduuli

Kohteesta Wikikko - kansan taitopankki
Siirry navigaatioon Siirry hakuun

Yleistä[muokkaa]

Tämän sivun tarkoitus on esittää perusteita Drupalmoduulien ohjelmointiin. Sivulla tehdään osa kerrallaan yksi moduuli, jota tehtäessä selviää moduulin tekemisen periaatteet Drupalin versiossa 7. Versioon 8 sivu ei tällä hetkellä ota kantaa. Tällä sivulla käytetyt käännökset eivät ole vakiintuneita termejä.

Drupal ohjelmointi -sivulla on neuvottu ohjelmointiympräistön asettamisesta ja Drupalkoodin standardit. Standardeihin on syytä tutustua ensimmäisenä, koska niitä tulee noudattaa.

Moduuli[muokkaa]

Drupal sisältää kolmenlaisia moduuleita. Ydinmoduulit (core) muodostavat Drupalin itsessään ja joista Drupalin kehittäjät ja yhteisö huolehtivat. Contributed-moduuleja kirjoittaa myös drupalyhteisö ja ne jaetaan saman lisenssin alaisuudessa kuin Drupalin ydin. Muokatut moduulit (custom) joita kehittäjät luovat ovat tarkoitettu johonkin erityiseen toimintoon. Ohjelmoinnissa korostuu PHP-ohjelmointikielen osaaminen olioineen ja Drupalin ominaispiirteet kuten esimerkiksi "koukut" (hooks). Tässä ohjeessa tehdään alkuperäisen moduulin ohjelmointiohjesivun mukainen moduuli. Moduuli tulostaa äskettäin sivustoon lisättyjä kirjoituksia lohkossa ja sivuna. Ohje on kirjoitettu tammikuussa 2014 ja se on testattu Drupalin versiossa 7.26. Ohje on tarkoitettu seurattavaksi järjestyksessä, koska alussa kirjoitettuihin koodeihin tehdään muutoksia ohjeen edetessä. Aivan lopusta löytyy myös linkki, jossa koko ohjelmakoodi on kokonaisuudessaan.

  1. Nimetään moduuli
  2. Liitetaan moduuli drupaliin
  3. Lisätään ohjetoiminto
  4. Muodostetaan lohko johon haetaan tiedot tietokannasta
  5. Tehdään asetukset sivu ja arvontarkastustoiminto
  6. Lisätään enimmäismäärätoiminto
  7. Lisätään käyttöoikeuksien asetus
  8. Muodostetaan sivu
  9. Lisätään Lisää-linkki lohkoon

Moduulin nimeäminen[muokkaa]

Moduulin kehittäminen alkaa tietysti ideasta, jätetään se tässä sivumpaan ja siirrytään suoraan moduulin nimeämiseen. Drupalissa moduulilla on kaksi nimeä, drupalin käyttämä ja käyttäjien käyttämä.

  • käyttäjien näkemä nimi on enintään pari sanaa ja voi sisältää välejä ja alkaa isolla kirjaimella. Tässä esimerkissä Current Posts
  • drupalin käyttämä nimi on lyhyt, alkaa kirjaimella ja sisältää vain pieniä kirjaimia ja tarvittaessa alaviivoja. Se voi kyllä myös sisältää numeroita ja isojakin kirjaimia. Lähtökohtaisesti sen tulee olla sama kuin käyttäjien käyttämä. Tässä esimerkissä current_posts
  • varmista että moduuli ei ole saman niminen kuin mitä jo käytät tai tulet käyttämään Drupalissa tai on yleisesti käytössä.
  • moduulia EI sekoiteta ytimen moduuleihin vaan luo oma hakemisto moduulille /sites/default/modules/moduulin_nimi eli tässä current_posts joka on drupalin käyttämä nimi.
    • moduulit voidaan asettaa myös muihin hakemistoihin, mutta niissä saattaa olla ylikirjoituksen vaara päivitettäessä. Edellä mainitun hakemiston ongelma saattaa ilmetä lähinnä monisivustoississa asennuksissa. Tällöin moduuli tulee sijoittaa /sites/all/modules/custom/moduulin_nimi
  • moduuli tarvitsee aina .info tiedoston ja yleensä jotain tehdäkseen .module tiedoston. Palvelimen tulee pystyä lukemaan näitä tiedostoja, mutta sen ei tarvitse päästä kirjoittamaan niihin.
  • tee hakemistoon tiedosto current_posts.module joka sisältää rivin <?php

Moduulin liittäminen Drupaliin[muokkaa]

Tehdään moduulinnimi.info -tiedostoa käyttäen. Info-tiedosto saa moduulin näkymään moduuliluettelossa, kertoo moduulin käyttäjälle suunnatun nimen, kuvailee moduulia lyhesti, kertoo mitä muita moduuleita se tarvitsee toimiakseen ja mitä kooditiedostoja moduuli tarjoaa muille. Pakollisia ovat name ja description. Sen sijainti on moduulin hakemisto.

  • muuttuja = arvo tai muuttuja[] = arvo1 tai ;Tämä on kommenttirivi.
  • package kertoo minkä otsikon alle moduuli sijoitetaan moduulisivulla. Core kertoo minkä drupalin pääversion moduuli tarvitsee. Php kertoo mikä php-versio on ?vähintään? oltava käytössä. Files kertoo mitkä moduulin tiedostot sisältävät php-tiedostoja, luokkia tai interfaces. Tähän ei tarvitse sisällyttää siis JavaScript, CSS, kuvatiedosto tai php-tiedostoja joissa ei ole funktioita. Files siis kertoo drupalille mitkä tiedostot sen pitää tutkia ja kirjata koodirekisteriin. Dependencies kertoo drupalille mitkä moduulit täytyy olla kytkettynä myös päälle.
  • varmista että kuvauskenttä ei sisällä mitään rivinvaihtoja. Lisätietoa info-tiedostosta.
; Esimerkkejä mitä voidaan sisällyttää .info -tiedostoon
name = Käyttäjän näkemä nimi
description = Kuvaus moduulin toiminnasta enintään parilla lauseella.
package = Development
core = 7.x
files[] = moduulinnimi.module
dependencies[] = toisenmoduulinnimi
php = 5.4
tags[] = 
configure = admin/config/content/current_posts
Lisää seuraava tiedosto nimellä current_posts.info
name = Current Posts
description = A block module that lists links to recent posts.
core = 7.x
  • Tarkista että tiedosto ilmestyy moduulien luetteloon ryhmään Other.

Teoriaa koukuista (hook)[muokkaa]

Moduuli eli .module -tiedosto kirjoitetaan php-ohjelmointikielellä. Se sisältää kaikki tärkeimmät moduulin koukut. Moduuli suoritetaan drupalympäristössä, mikä tarkoittaa että se voi hyödyntää muita funktioita, muuttujia yms. ja sitä voidaan hyödyntää yhtä lailla. Moduuli on PHP-tiedosto, joka voidaan suorittaa itsenäisesti. Kutsuttaessa moduulia, se tehdään niin kutsutulla hook-toiminnolla, joista tällä sivulla käytetään nimitystä koukku. Koukkujen avulla moduuli keskustelee ytimen tai muiden moduulien kanssa. Tällaisia ovat esimerkiksi hook_menu, hook_block, hook_footer, hook_schema jne. Ytimeen liittyvien koukkujen lista löytyy tältä sivulta. Moduulit voivat myös sisältää omia koukkuja. Koukku on toisin sanoen funktio ja sillä on omat parametrit ja määritelty toiminta. Koukku voi olla esimerkiksi "tarkkailija", joka odottaa jonkun toimenpiteen tapahtumista. Tällainen voisi olla esimerkiksi hook_delete joka odottaa että jossain sivustossa tapahtuu noden poistaminen. Tällöin koukku aktivoituu ja aloittaa aliohjelman suorittamisen.


Koukku toimii myös toisella tavoin, esimerkkinä ohjetoiminto. Käyttäjän avatessa ohjesivua, sivu muodostetaan sen hetkisestä tilanteesta niin että jokaiselle moduulille annetaan mahdollisuus antaa oma ohjeensa yhteiselle ohjesivulle. Drupal tekee tällöin skannauksen kaikkien päälle kytkettyjen moduulien koodeihin ja etsii niistä funktiota moduulinnimi_help($path, $arg). Se etsii vain niistä moduuleista jotka on kytketty päälle. Funktion parametrit kertovat missä ohjeet sijaitsevat. Ymmärtämistä voi kenties helpottaa mielikuva jossa yksittäiseen moduuliin asetetaan moduulinnimi_help -koukku odottamaan. Se tarttuu ohimenevään Drupalin tekemään skannaukseen kun se etsii ohjekoukkuja muodostaessaan ohjesivua. Muutoin koukku ei reagoi mitenkään muihin skannauksiin. Kun koukku tarttuu, yhdistyvät kutsuva ja kutsuttu moduuli toisiinsa ja toiminnot rullaavat eteenpäin.


Kytkettäessä current_posts -moduuli päälle, ilmoitetaan drupalille lisäämällä moduuli koorirekisteriin, että se "skannatessaan" huomioi moduulin sisällön. Tässä moduulissa, kun katsotaan ainoastaan lohkon tulostamiseen tarvittavia funktioita, nähdään että käyteään seuraavia koukkuja: current_posts_help, current_posts_block_info ja current_posts_block_view. Käytämme myös funktiota current_posts_contents, mutta sitä kutsutaan vain current_posts_block_view -funktion sisältä. Kytkemme lohkon päälle lohkot-sivulla ja näin drupal saa tietää että etsiessään hook_block_view() -koukkuja moduuleista ja osuessaan sellaiseen arvolla current_posts se käynnistää kyseisen funktion joka antaa teemalle tiedoksi viimeisimmät julkaisut.


Jos noustaan askel ylemmäksi katsomaan mitä tapahtuu, voidaan nähdä ytimen suorittavan pyydettäessä skannauksia kaikkiin moduuleihin ja joihin päälle kytkemissämme moduuleissa olevat koukut sopivissa olosuhteissa reagoivat. Ytimen löydettyä sopivan koukun sopivilla parametreilla, se suorittaa koukun vaatiman toiminnon ja jatkaa skannaamistaan eteenpäin. Meidän siis tarvitsee a) ilmoittaa moduulimme olemassaolosta, b) ohjelmoida moduuli joka asettaa koukut odottamaan skannauksia c) odottaa että käyttäjä, cron-ajo tms. pyytää jotain sellaista mihin koukkumme reagoivat. Moduuli herää eloon vain kun siinä on koukkuja joihin drupal voi tarrata.

  • koukku, funktio on nimettävä moduulinnimi_koukkunimi.
  • valmiit koukut joita drupalissa on käytettävissä ilmaistaan ohjeluetteloissa sisältän hook-sanan. Korvaa hook-sana moduulin nimellä.
  • jos funktion on oltava yksityinen eikä muut moduulit saa käyttää sitä, aloita alaviivalla eli _moduulinimi_
  • varmista ettei oma moduulisi nimi ole jo olemassaoleva drupalkoukku.

Koodirekisteri[muokkaa]

Drupal 7 sisältää koodirekisterin, luettelon kaikista luokista, moduuleista ja ydintiedostoista. Rekisterissä on polku em. kohteisiin ja tarpeen mukaan, pyydettäessä, niitä toteutetaan. Tässä käytetään avuksi php:n automaattista lataustoimintoa. .module tiedoston täytyy sisältää kaikki se koodi joka on oltava aina käytössä. Tarvittaessa käytettävä koodi voidaan sisällyttää muihin tiedostoihin jotka löytyvät rekisterin avulla. Rekisteri rakennetaan aina uudelleen kun moduuleita kytketään tai kytketään pois käytöstä. Jos ohjelmoit moduuliisi luokkia, varmistu että uudet resurssit ovat käytettävissä. Tämän voi tehdä tyhjentämällä välimuistin tai kutsumalla registry_rebuild(). Uudelleenrekisteröinti tekee vain ne muutokset jotka ovat muuttuneet edellisen kerran jälkeen, joten se ei ole kovin raskastoiminen. Files that do not contain classes and interfaces that might be put into use at any time by your module file do not need to be listed with the files[] property in your .info file. Instead, such code can continue to be loaded when you need it, such as through the hook_menu()'s file property. If your module introduces hooks of its own, consider implementing hook_hook_info() to allow other modules' hook implementations to be autoloaded[1]

Ohjetoiminnon lisääminen ja kielen käännökset[muokkaa]

Seuraavaksi kirjoitetaan toimintoja jo aloitettuun tiedostoon current_posts.module Moduulia rakennettaessa se alkaa ohjetoiminnon lisäämisellä käyttäjälle.

  • ensimmäinen koukku on hook_help ja sitä suositellaan käytettäväksi kaikissa moduuleissa. Sillä kerrotaan ohjeet moduulin käyttämisestä käyttäjälle. hook_help voi olla vain yhden kerran moduulissa.
  • @param parametri tarkoitus on selvittää mitä kyseinen parametri tarkoittaa.
  • $path parametrilla current_posts_help -koukkuun lisätään polku, jonka mukaan drupal tarttuu etsiessään moduulista koukkua current_posts ohjesivua varten. Tämän jälkeen palautetaan kutsuneelle funktiolle Displays links to... Lisätietoa aiheesta. Moduulilaajuiset ohjeet pitäisi olla saatavilla osoitteessa admin/help#koneluettavamoduulinnimi
<?php
/**
 * @file
 * Moduuli näyttää viimeisimmät blogi- ja foorumikirjoitusten aiheet linkkeinä.
 *
 * Tämä moduuli esittelee perusteet drupalohjelmointiin versiossa 7.
 */

/**
 * Implements hook_help().
 *
 * Näyttää ohje- ja moduulitiedot.
 *
 * @param path
 *   Osoitepolku jota käytetään näytettäessä ohje
 * @param arg
 *   Array that holds the current path as returned from arg() function
 */
function current_posts_help($path, $arg) {
  switch ($path) {
    case "admin/help#current_posts":
      return '<p>' . t("Displays links to nodes created on this date") . '</p>';
      break;
  }
} 
  • Tallenna moduuli, päivitä moduulisivu ja kytke moduuli päälle. Huomaat että moduulirivin loppuun ilmestyy valinta Ohje, joka sisältää tekstin Displays links... Näet Current Posts-linkin myös moduulin yläpalkista avautuvalla Ohje-sivulla.
  • TÄRKEÄÄ. Poista moduuli nyt käytöstä jos kokeilit ohjetoimintoa. Muutoin koko sivustosi saatta vaurioitua. Toimi näin myös muulloinkin kun testaat moduulin toimintaa.
Help moduulin ohje
Drupalin dokumentointiohje

Ohjetoiminto[muokkaa]

Drupal käyttää ohjetoiminnossaan Doxygen-toimintoa purkaakseen API:n ohjeet lähdekoodista. Ohje alkaa /** ja päättyy */. Tätä kutsutaan doc block eli ohjelohko. Sen sisältämä tieto voidaan näyttää kehittäjille. Ohjelohko pääohje on tiedoston alussa ja alkaa @file -rivillä, joka selventää että juuri tämä kommentti kuvailee koko tiedostoa, ei vain osaa siitä. Jokaisen tiedoston tulisi alkaa @file -riveillä. Itse ohje sisältää aluksi yhden lauseen kuvauksen tiedostosta yhdellä rivillä. Tämän jälkeen tulee tyhjä rivi ja lyhyt kuvaus mikä on tiedoston tarkoitus. Standardien mukaan lauseiden tulee olla kokonaisia. Ohjelohko sisältyy siis jokaisen funktion alkuun ja kertoo ytimekkäästi kehittäjälle mikä on funktion tarkoitus. Syntaksi on Implements hook_nimi(). Yhden rivin kuvaus riittää kun funktio on yksinkertainen ja kehittäjät voivat yksinkertaisesti vilkaista lisätietoa yleisistä koukun API-ohjeista. Tarpeen mukaan kuvauksen jälkeen voidaan myös lisätä tietoa parametreista.

Kielenkääntäminen[muokkaa]

  • t("English text here.") -funktiolla saadaan teksti käännöstoimintojen huomioimaksi. Toisin sanoen moduulien ilmoitukset kirjoitetaan englanniksi ja käännetään myöhemmin drupalissa toisille kielille. Kaikki käyttäjälle tarkoitetut viestit tulisi olla t() funktiolla.
  • funktio ei reagoi mitenkään jos kielitukimoduulia ei ole otettu käyttöön ja mitään toista argumenttia ei anneta. Jos muita kieliä on otettu käyttöön ja käyttäjän käyttämä kieli on muu kuin englanti, drupal yrittää korvata tekstin kyseisellä kielellä.
  • teksti voidaan ilmoittaa ainoastaan muodossa t("English text here.") jotta kääntäminen on mahdollista. Teksti ei voi olla esimerkiksi muuttujassa. Tämä on myös turvallisuustekijä, jossa muuttujaa ei sisällytetä tulosteeseen. Tämä voidaan turvallisesti toteuttaa sisällyttämällä funktiokutsuun toinen argumentti, paikanpitäjä joka sisältää muuttujan arvon. Jos paikanpitäjä alkaa @ -merkillä, drupal käyttää sisäistä check_plain() -funktiota.
$values = array('@user' => $username);
print t('Tervetuloa, @user', $values);
  • jos taas tieto jota tulostetaan ei sisällä arkaluontoista tietoa tai sisältää tietoa, jota ei tule kääntää, voidaan käyttää etumerkkinä huutomerkkiä (!).
$values = array('!url' => 'http://www.esimerkki.fi');
print t('Kotisivun osoite on !url', $values);
  • kolmas vaihtoehto on käyttää prosenttimerkkiä (%), joka korostaa.
$values = array('%color' => 'blue');
print t('Väri on %color.', $values);

Lohkon muodostaminen[muokkaa]

Block API:n avulla tehdään koukku jolla tekemämme lohko saadaan mukaan lohkoalijärjestelmään. Toisin sanoen kun tämä lohko on kytketty päälle ja drupalin tarvitsee tulostaa lohkoja, se tietää että current_posts moduuli pitää huomioida ja pyytää siltä lohko sisällön kanssa. Käytetään kahta eri koukkua hook_block_info() ja hook_block_view(). Ensimmäinen kertoo drupalille lohkosta jonka moduuli tuottaa tai kaikista niistä lohkoista joita moduuli tuottaa. Tätä koukkua voi käyttää vain kerran moduulissa, joten kaikki moduulin luomat lohkot on määriteltävä tässä funktiossa.

  • lähtökohta API:en kanssa on että kukin voi esiintyä vain kerran moduulissa, joten kyseiseen API funktioon pitää laittaa kaikki tarvittavat toiminnot jotka käyttävät samaa API:a. Toisin sanoen esimerkiksi block_info voi kertoa useista lohkoista mitä moduuli tuottaa.
  • tässä määritellään $blocks taulukko nimellä current_posts joka sisältää lohkoluettelossa näytettävän nimen ja välimuistitiedon. PHP:ssä taulukot ovat erittäin nopeita ja hyvin tuettuja sekä paljon drupalissa käytettyjä. Palautettava taulukko sisältää yhden syötteen per lohko ja syntaksi on $nimi => array($avain => $arvo)
  • ominaisuuksia voi olla useita, tässä käytetään vain kahta, info ja cache. Katso tarkemmin ohjeista. cache kertoo drupalille kuinka tietoa lohkosta välimuistitetaan. Esimerkiksi DRUPAL_NO_CACHE tarkoittaa että välimuisti ei ole käytössä.
/**
 * Implements hook_block_info().  Kyseessä on yleisliitos, joten tarkempaa ohjetta ei tarvita.
 */
function current_posts_block_info() {
  $blocks['current_posts'] = array(   //Määritetään lohko nimeltä current_posts
    'info' => t('Current posts'),   //Lisätään ominaisuus, nimi joka näytetään lohkolistassa.
    'cache' => DRUPAL_CACHE_PER_ROLE,   //Oletusasetus.
  );
  return $blocks;   //Palautetaan taulukko.
}
  • Voit kokeilla moduulin toimintaa, lohko löytyy nyt lohkoluettelosta. Muista taas kytkeä moduuli pois päältä.

Lohkon sisällön luonti[muokkaa]

Käytetään hook_block_view -koukkua, kerrotaan drupalille mitä tapahtuu kun lohko pyydetään näytille. Tätä koukkua kutsutaan aina kun drupal on näyttämässä lohkoa. Funktio voi ottaa yhden argumentin, joka on lohkon nimi ja palauttaa saman nimisenä taulukkona tiedon.

  • $delta parametrilla kerrotaan funktiolle mistä lohkosta on kyse. Nyt käytössä on vain yksi lohko, joten jätetään kertomatta. Se voi myös olla $block_name tai $which_block
  • käyttäjän oikeudet nähdä haettu sisältö on varmistettava. Perustarkistus tapahtuu access content. Oikeudet löytyvät käyttäjänimilistasta ja käyttäjänimeä voidaan suoraan käyttää koodissa. Oikeudet välilehden nimet eivät ole luettavissa. Toinen vaihtoehto on käyttää moduulinimi_permission, esimerkiksi node_permission.
  • Haetaan julkaisut current_posts_contents() -funktiolla tietokannasta. Palautteena saadaan taulukko, joka pitää muotoilla näyttökelpoiseksi. Drupalissa käytetään lähes aina teemalayeria. Tarkoitus on saada taulukon tiedot teemalayerille ja käännetyksi HTML-muotoon. Paääfunktio on theme(). Se voi vastaanottaa yhden tai kaksi argumenttia, teemaoperaation nimen ja muuttujien taulukon. Teema voi hallita monia Drupalin tulosteita käyttäen hyväksi CSS-tyylitiedostoja.
    • merkkijonotaulukon muuttamiseen HTML-listaksi käytetään item_list teemaa, ja annetaan taulukko sisältäen kaksi muuttujaa, kohteet jotka halutaan luetteloida ja tarvittaessa minkä tyyppisen luettelon haluamme muodostaa, mitä kylläkään tässä esimerkissä ei anneta.
    • Luettelo koukuista.
/**
 * Implements hook_block_view().
 *
 * Valmistelee lohkon sisällön teemalle näytettäväksi.
 */
function current_posts_block_view($delta = '') {
  switch ($delta) {
    case 'current_posts':    //Kun kyseessä on current_posts -lohko, tehdään seuraava.
      $block['subject'] = t('Current posts');   //Asetetaan lohkon nimi $block:iin.
      if (user_access('access content')) {   //Jos käyttäjällä on oikeus sisältöön tehdään tiedon käsittely.
        $result = current_posts_contents(); //Haetaan tiedot funktiolta Itse tehty sisällönnoutofunktio.
        $items = array(); // Varastoidaan seuraavaksi tiedot muuttujaan taulukkona.
        foreach ($result as $node) {   //Käydään tiedot läpi ja muutetaan otsikot linkeiksi l() -funktiolla.
          $items[] = array(
            'data' => l($node->title, 'node/' . $node->nid),
          );
        }
        if (empty($items)) {   //Jos ei uutta sisältöä viikkoon.
          $block['content'] = t('No posts available.');
        }
        else {
          $block['content'] = theme('item_list', array(   //Sisällytetään tiedot teemafunktiolle ja lopulta $block:iin.
            'items' => $items));
        }
      }
    return $block;   //Palautetaan tiedot $block -muuttujassa eli lohkon nimi ja sisältö tekstinä tai HTML:nä.
  }
}
Node object reference

Esimerkkejä[muokkaa]

  • $result = module_list(); //Hakee taulukon päälle kytkettyjen moduulien nimistä.

Tiedon haku tietokannasta[muokkaa]

Tiedot haetaan tietokannasta funktiolla, joka tehdään seuraavassa. Tässä esimerkissä tiedot haetaan kun funktio current_posts_block_view() sitä pyytää. Kun sivustoon lisätään sisältöä, siitä tallennetaan sisällön luontihetki tietokantaan. Tässä esimerkissä tämän kentän perusteella kerätään tietoa.

  • drupalissa käytetään drupalin Tietokanta API:a (Database API), jolla voidaan huomioida useat erilaiset tietokannat. Tätä käytetään läpi drupalin.
  • condition metodi käyttää kolmea argumenttia: ensimmäinen on kenttä, toinen on arvo ja kolmas operaattori.
  • Lisätietoa condition käytöstä.Lisätietoa Query käytöstä. Lisätietoa db_select käytöstä.
  • tietokannan taulusta node haetaan nid-tunniste, aihe ja luontipäivämäärä. Sisällön pitää olla julkaistu ja tietyllä aikavälillä. Lajitellaan myös samalla. Lopputuloksena funktiosta palautetaan lajitellut haut (conditions) täyttävät tiedot.
/**
 * Itse tehty sisällönnoutofunktio.
 *
 * Asetetaan alkamis- ja päättymisajankohta ja 
 * noudetaan tiedot tietokannasta kyseiseltä ajanjaksolta.
 */
function current_posts_contents(){
  $today = getdate();  //Asetetaan $today arvoksi tämä päivä.
  $start_time = mktime(0, 0, 0,$today['mon'],($today['mday'] - 7), $today['year']);   //Lasketaan yksi viikko taaksepäin aloitusajaksi.
  $end_time = time();   //Asetetaan päättymisajaksi tämä hetki.
  $query = db_select('node', 'n')   //Taulun nimi on node ja n on argumentti
    ->fields('n', array('nid', 'title', 'created'))   //Fields-metodi käyttää taulua aliaksella n ja siinä määrättyjä sarakkeita.
    ->condition('status', 1)   //Vain julkaistut.
    ->condition('created', array($start_time, $end_time), 'BETWEEN')   //Vain tällä ajanjaksolla.
    ->orderBy('created', 'DESC')   //Uusin ensimmäiseksi created mukaan.
    ->execute();   //Toimeenpannaan haku
  return $query;   //Palautetaan haetut tiedot muille funktioille.
}
  • kytke nyt moduuli päälle ja aseta lohko esille. Jos et ole luonut vielä sisältöä sivustolle, tee se nyt. Näet lohkon ja siellä viimeisimmän julkaisemasi sisällön linkin. Valmis!
  • jos koodissa on jotain vikaa ja et löydä ongelmaan ratkaisua, viimeinen keino on siirtää moduulin kansio pois moduulihakemistosta. Tämä ei ole hyvä tapa, mutta tämä moduuli ei ole tehnyt mitään muutoksia tietokantaan tms., joten tässä moduulissa tällaista tapaa voidaan soveltaa.
  • on hyvä muistaa että välimuistit voi tarvittaessa tyhjentää Asetukset > Suorituskyky ja Tyhjennä välimuistit

Moduulin asetukset -sivu[muokkaa]

Lisätään linkkejä[muokkaa]

Lisätään linkit asetukset-sivulle ja moduulisivulle. Käytetään hook_menu() -funktiota, joka tarkistaa myös pääsyoikeudet.

  • URL-polku admin/config/content/current_posts -asetussivulle kirjoitetaan ilman alku- ja loppu / -merkkejä. Tässä /content/ -sijoittaa asetussivun yhteenvetosivulla Content authoring otsikon alle. Sen voi korvata tarpeen mukaan seuraavilla: content/date/development/media/people/regional/search/services/system/user-interface
  • page callback ilmaisee mitä kutsutaan kun linkkiä kysytään. Tässä tapauksessa drupal_get_form
  • page arguments ilmaisee että arvot välitetään current_posts_form funktiolle.
/**
 * Implements hook_menu().
 */
function current_posts_menu() {
  $items = array();
  $items['admin/config/content/current_posts'] = array(
    'title' => 'Current posts',   //Asetussivun otsikko.
    'description' => 'Configuration for Current posts module',   //Kuvaus joka näkyy asetusten yhteenvetosivulla.
    'page callback' => 'drupal_get_form',
    'page arguments' => array('current_posts_form'),
    'access arguments' => array('access administration pages'),   //Tarkistetaan oikeudet asetusten muuttamiseen.
    'type' => MENU_NORMAL_ITEM,   //Lisätään Current posts linkki.
  );
  return $items;
}
  • jotta moduulisivulla näkyy myös linkki moduulin asetuksiin, lisätään current_posts.info tiedostoon seuraava.
; NEW LINE
configure = admin/config/content/current_posts

Lisätään asetukset sivu[muokkaa]

Lisätään moduuliin asetukset -sivu, jossa voidaan muokata moduulin asetuksia. Tässä esimerkissä asetussivulla voidaan asettaa kuinka monta viimeisintä julkaisua näytetään. Edellisessä kohdassa määritettiin page arguments, joka ohjaa tähän funktioon.

  • asetuksetlomakkeen eli funktion current_posts_form luominen tapahtuu form API:a apuna käyttäen. Aiheesta lisää.
  • osa tiedoista, kuten järjestelmäasetukset ja käyttäjän omat asetukset ovat tallennettuna tietokantaan persistent variables -muuttujina, josta ne haetaan tarpeen mukaan. Funktio variable_get() noutaa näitä ja variable_set() asettaa. Arvo noudetaan ja otetaan käyttöön jos se on asetettu, muutoin käytetään koodissa annettua arvoa, joka seuraavassa on 3. Elementtinä käytetään current_posts_max.
  • lisätään elementit $form taulukkoon #avaimien kanssa.
  • lomakkeen tiedot voidaan tallentaa funktiolla system_settings_form() jolloin drupal lisää lähetä-painikkeen ja tallentaa tiedot peristent variables -muuttujiin käyttäen variable_set() funktiota. Lisäksi tallennettaessa ilmestyy automaattisesti vahvistusviesti.
/**
 * Vastaus sivupyyntöön: Current posts asetukset
 *
 * @see current_posts_menu()
 */
function current_posts_form($form, &$form_state) {
  $form['current_posts_max'] = array(
    '#type' => 'textfield',   //Lisätään sivulle tekstikenttä.
    '#title' => t('Maximum number of posts'),   //Otsikoidaan tekstikenttä.
    '#default_value' => variable_get('current_posts_max', 3),   //Etsitään oletusarvoa tietokannasta ja jos sitä ei ole, annetaan 3.
    '#size' => 2,   //Kentän koko.
    '#maxlength' => 2,   //Kenttään syötettävän arvon enimmäispituus.
    '#description' => t('The maximum number of links to display in the block.'),   //Kuvaus kentän alapuolelle.
    '#required' => TRUE,   //Pakollinen arvo, lisää automaattisesti * -merkin ja antaa tarvittaessa virheilmoituksen.
  );
  return system_settings_form($form);   //Lisätään lähetä-painike ja tallennetaan arvo tietokantaan.
}

Lisäätään enimmäismäärän arvon tarkastustoiminto[muokkaa]

Varmistetaan että annettu numero on suurempi kuin nolla tekemällä siihen itse tehty funktio. Lisää tämä normaalisti tiedoston loppuun edellisten jatkoksi. Myös tämän koukun drupal huomaa automaattisesti ja osaa liittää nimen perusteella sen current_posts_form funktioon.

  • $form_state is passed by reference along through each stage of form processing to capture information about the form's workflow and its current state. Lue lisää aiheesta.
/**
 * Itse tehty arvontarkastusfunktio
 * Liitetään varmistus Form API:iin.
 *
 * @param $form
 *   A structured array containing the elements and properties of the form.
 * @param $form_state
 *   An array that stores information about the form's current state during processing.
 */
function current_posts_form_validate($form, &$form_state){
  $max_num = $form_state['values']['current_posts_max'];
  if (!is_numeric($max_num)){
    form_set_error('current_posts_max', t('You must enter a number for the maximum number of posts to display.'));
  }
  else if ($max_num <= 0){
    form_set_error('current_posts_max', t('Maximum number of posts to display must be positive.'));
  }
}

Muutetaan funktio huomioimaan enimmäismäärä[muokkaa]

Lisätään aikaisempaan itse tehtyyn sisällönnoutofunktioon eli current_posts_contents() funktioon muuttuja jotta asetukset tulevat voimaan. Eli korvaa aikaisemmin tehty funktio seuraavalla funktiolla tai lisää siihen vain kaksi riviä, jotka on merkitty UUSI RIVI.

/**
 * Itse tehty sisällönnoutofunktio.
 *
 * Asetetaan alkamis- ja päättymisajankohta ja 
 * noudetaan tiedot tietokannasta kyseiseltä ajanjaksolta.
 */
function current_posts_contents(){
  $today = getdate();  //Asetetaan $today arvoksi tämä päivä.
  $start_time = mktime(0, 0, 0,$today['mon'],($today['mday'] - 7), $today['year']);   //Lasketaan yksi viikko taaksepäin aloitusajaksi.
  $end_time = time();   //Asetetaan päättymisajaksi tämä hetki.
  $max_num = variable_get('current_posts_max', 3); //UUSI RIVI eli haetaan tietokannasta arvo tai jos sitä ei ole annetaan 3.
  $query = db_select('node', 'n')   //Taulun nimi on node ja n on argumentti.
    ->fields('n', array('nid', 'title', 'created'))   //Fields-metodi käyttää taulua aliaksella n ja siinä määrättyjä sarakkeita.
    ->condition('status', 1)   //Vain julkaistut.
    ->condition('created', array($start_time, $end_time), 'BETWEEN')   //Vain tällä ajanjaksolla.
    ->orderBy('created', 'DESC')   //Uusin ensimmäiseksi created mukaan.
    ->range(0, $max_num)    //UUSI RIVI eli haetaan vain ilmoitettu määrä.
    ->execute();   //Toimeenpannaan haku.
  return $query;   //Palautetaan haetut tiedot muille funktioille.
  • Tallenna moduuli, päivitä moduulisivu ja kytke moduuli päälle. Tyhjennä seuraavaksi välimuisti Asetukset > Suorituskyky ja Tyhjennä välimuistit. Testaa moduulin toiminta. Muista kytkeä moduuli pois käytöstä tämän jälkeen!

Lisätään sivu jossa viimeisimmät julkaisut[muokkaa]

Nyt moduuli näyttää viimeisimmät julkaisut lohkossa ja enimmäismäärää voidaan muuttaa asetukset sivuilla. Lisätään vielä sivu, jossa voidaan nähdä enemmän muutoksia ja lohkoon linkki tähän sivuun.

Asetetaan valinta käyttöoikeudet -sivulle[muokkaa]

Lisätään käyttäjien oikeudet sivulle uusi kohta Current posts, jossa käyttäjä määrittelee mitkä roolit voivat nähdä moduulin tuottaman sisällön.

/**
 * Implements hook_permission().
 */
function current_posts_permission() {
  return array(
    'access current_posts content' => array(
      'title' => t('Access content for the Current posts module'),   //Toiminnon kuvaus.
    )
  );
}
hook_permission ohje

Lisätään linkki valikkoon[muokkaa]

Lisätään Current posts-linkki menuvalikkoon.

  • page callback on ehdottomasti hyvä ratkaisu yksityisille funktioille joita muut eivät saa käyttää. Nimetään funktio aloittamalla se alaviivalla ja päätetään page -sanaan.
  • Lisää seuraava aiemmin tehtyyn funktioon current_posts_menu() ennen return $items; riviä.
  $items['current_posts'] = array(
    'title' => 'Current posts',   //Linkin nimi.
    'page callback' => '_current_posts_page',   //Funktio johon ohjataan valittaessa.
    'access arguments' => array('access current_posts content'),   //Tarkastetaan oikeus.
    'type' => MENU_NORMAL_ITEM, //Näytetään menuvalikossa.
  );
  • Tallenna moduuli, päivitä moduulisivu ja kytke moduuli päälle. Tyhjennä välimuisti. Aseta oikeudet käyttäjärooleille ja tarkista että valikossa näkyy linkki. Muista kytkeä moduuli pois käytöstä tämän jälkeen!

Sisällön lisääminen sivulle ja lohkoon[muokkaa]

Tehdään taas uusi current_posts_contents funktio joka korvaa vanhan ja käsittelee nyt samalla sekä lohkon että sivun. Haetaan siis tietokannasta julkaisut ja jos haetaan lohkoon, haetaan vain maksimimäärän verran, muutoin kaikki kyseisenä ajanjaksona julkaistut.

function current_posts_contents($display){   //$display ON UUSI
  $today = getdate();  //Asetetaan $today arvoksi tämä päivä.
  $start_time = mktime(0, 0, 0,$today['mon'],($today['mday'] - 7), $today['year']);   //Lasketaan yksi viikko taaksepäin aloitusajaksi.
  $end_time = time();   //Asetetaan päättymisajaksi tämä hetki.
  $max_num = variable_get('current_posts_max', 3);   //Haetaan tietokannasta arvo tai jos sitä ei ole annetaan 3.
  $query = db_select('node', 'n')   //Taulun nimi on node ja n on argumentti.
    ->fields('n', array('nid', 'title', 'created'))   //Fields-metodi käyttää taulua aliaksella n ja siinä määrättyjä sarakkeita.
    ->condition('status', 1)   //Vain julkaistut.
    ->condition('created', array($start_time, $end_time), 'BETWEEN')   //Vain tällä ajanjaksolla.
    ->orderBy('created', 'DESC');   //UUSI Pysäytetään puolipisteellä tähän ja selvitetään pyydetäänkö lohkoa.
   if ($display == 'block'){   //UUSI RIVI eli rajataan alue maksimimäärään jos kutsutaan lohkoargumentilla.
    $query->range(0, $max_num);   //UUSI RIVI
  }   //UUSI RIVIJos kutsutaan sivua tulostetaan kaikki julkaisut.
  return $query->execute();   //UUSI Toimeenpannaan haku ja palautetaan haetut tiedot muille funktioille.
}
  • Muuta current_posts_block_view -funktio ohjautumaan current_posts_contents -funktioon. Lisää funktiossa jo olevaan riviin sana 'block' joka siis lähtettää funktiokutsussa arvon block.
$result = current_posts_contents('block');

Sivun julkaisu[muokkaa]

  • Kirjoitetaan sivufunktio. Pyyntö tähän funktioon tulee current_posts_menu() -funktiosta eli kun käyttäjä pyytää sivua auki.
  • Säilytetään tietoa taulukossa (array), kunnes se esitetään sivulla. Lisätietoa aiheesta.
  • #theme:ssä on kaksi alaviivaa peräkkäin, mikä tarkoittaa...
/**
 * Itse tehty sivunjulkaisufunktio.
 */
function _current_posts_page() {
  $result = current_posts_contents('page');   //Noudetaan sisältö tietokannasta sivumuodossa.
  $items = array();   //Taulukko sisällölle joka sivulla esitetään (render).
  foreach ($result as $node) {   //Toistetaan (iterate) ja muotoillaan linkeiksi.
    $items[] = array(
    'data' => l($node->title, 'node/' . $node->nid),
    );
  }
  if (empty($items)) { //Jos ei yhtään uutta sisältöä viikon aikana.
    $page_array['current_posts_arguments'] = array(
      '#title' => t('All posts from the last week'), //Sivun alaotsikko.
      '#markup' => t('No posts available.'),
    );
    return $page_array;
  }
  else {
    $page_array['current_posts_arguments'] = array(
      '#title' => t('All posts from the last week'),
      '#items' => $items,
      '#theme' => 'item_list__current_posts',  //Teemakoukku.
    );
    return $page_array;
  }
}
  • Tallenna moduuli, päivitä moduulisivu ja kytke moduuli päälle. Tyhjennä tarvittaessa välimuisti. Lohko näkyy kuten ennen ja navigointi valikosta siirryt sivulle, josta näet kaikki viimeisimmät julkaisut. Kirjaudu ulos, jolloin mikään näistä ei pitäisi näkyä jos et ole antanut vieraskäyttäjälle oikeuksia. Muista kytkeä moduuli pois käytöstä tämän jälkeen!

Lisätään Lisää-linkki[muokkaa]

Lisätään teemakoukku myös lohkolle. Lisäksi lisäätään linkki lohkoon eli lisätään block['content'] -lapsi.

  • Korvaa current_posts_block_view -funktion lopussa oleva else seuraavalla. Tee korvaus tarkasti niin että vanhasta elsestä jälkimmäinen aaltosulje } myös poistuu koska uusi tulee tässä tilalle.
else {
  $block['content']['posts'] = array(   //Tiedot teemafunktiolle.
    '#theme' => 'item_list__current_posts__block',
    '#items' => $items,
  );
  $block['content']['more'] = array(   //Lisätään lohkoon linkki sivulle.
    '#theme' => 'more_link__current_posts',
    '#url' => 'current_posts',
    '#title' => t('See the full list of current posts.'),
  );
}

Poistetaan sivulinkki valikosta[muokkaa]

Lisäsimme aikaisemmin linkin sivulle valikkoon, nyt Lisää-linkki tekee tämän tarpeettomaksi.

  • korvaa current_posts_menu funktiossa valikkoon vaikuttava MENU_NORMAL_ITEM tekstillä MENU_CALLBACK
  • jos moduuli on ollut päällä, se pitää nyt kytkeä pois päältä ja uudestaan päälle jotta tämä muutos tulee voimaan.
  • joissain vanhemmissa drupalin versioissa sivun otsikko on yhä Home eikä Current posts. Lisää tällöin _current_posts_page() funktion alkuun rivi drupal_set_title('Current posts');

Onneksi olkoon! Jos olet tehnyt ohjeiden mukaan, sinulla on nyt moduuli, joka näyttää viimeisimmät sivustoon lisätyt julkaisut lohkossa ja sivuna. Lisäksi voit asettaa näkyvyysoikeuksia ja asetuksissa säätää montako kohdetta näkyy lohkossa. Ohjelman koodi on katsottavissa kokonaisuudessaan tästä (Ei ole verrattu onko täsmälleen sama).


API[muokkaa]

https://drupal.org/coding-standards/docs
https://api.drupal.org/api/drupal
https://api.drupal.org/api/drupal/7
https://drupal.org/node/326

Datestamp[muokkaa]

Luo esimerkiksi osoitteessa http://www.unixtimestamp.com/index.php

Esimerkkejä[muokkaa]

Esimerkkejä kehittäjille

Ohjeita[muokkaa]

Pääsivu jonka alta löytyy hyödyllistä tietoa paljon.
Kuinka jotain tehdään ohjeita.
Vinkkejä.
https://drupal.org/developing/modules
https://drupal.org/developing/modules/7
Hyviä toimintatapoja.
Hyviä ohjelmointikäytäntöjä.

Oliopohjainen ohjelmointi[muokkaa]

https://drupal.org/node/547518

Projektin luominen[muokkaa]

Oman projektin lisääminen ja ylläpitäminen
https://drupal.org/node/1068942

Riippuvuus muista moduuleista[muokkaa]

Jos moduuli on riippuvainen muista moduuleista, ota huomioon ettei toinen moduuli ole välttämättä 100 % toimiva. Alfa ja beta -vaiheissa voit tukeutua ainoastaan ydinmoduuleihin ja niihinkin varauksella. Muutoksia tehdään jatkuvasti.

Teema[muokkaa]

Katso sivu Drupal ohjelmointi teema.

Tiedon tuonti ja vienti[muokkaa]

https://drupal.org/node/1477970

Tietokanta[muokkaa]

Uusi moduuli, toisin kuin tässä esimerkissä, saattaa vaatia muutoksia tietokantaan kuten uusia tauluja. Nämä voidaan asentaa .install tiedostolla, mutta drupal 7 sisältää field-moduulin, joka korvaa osan aikaisempien versioiden install tiedoston käyttötarpeista. .install tiedostolla voidaan määritellä tietokantaan uusia tauluja, noutaa tietoa ja tehdä muutoksia päivitysten yhteydessä. Jos install tiedoston ainoa tarkoitus on lisätä ?kenttiä nodeihin tauluilla ja joillain sarakkeilla TARKASTA?, käytä Field API:a. Kenttien lisääminen tapahtuu hook_field_schema koukulla. Field moduuli, joka sisältyy drupaliin voidaan lisätä kenttiä nodeihin. Tietokannan muutokset voidaan siis toteuttaa install tiedoston sijaan .module tiedostosta. Katso esimerkiksi moduulia image/image.field.inc tai taxonomy/taxonomy.module jotka tekevät tietokantaan muutoksia. Jos käytät .install tiedostoa, drupal luo automaattisesti taulun kun asennat moduulia ja automaattisesti tuhoaa sen kun poistat moduulin käytöstä.

Turvallisuus[muokkaa]

https://drupal.org/writing-secure-code

Lähteet[muokkaa]

Tekijänoikeudet sivun ohjeisiin.
Esimerkki
http://www.packtpub.com/article/creating-your-first-module-drupal-7-module-development