lunedì 10 ottobre 2011

Drupal - Un semplice Select

Mi risulta davvero fastidioso perdere tempo per fare cose che normalmente richiederebbero tre minuti ma tanté che Drupal devo impararmelo e così me lo tengo.

Magari uno si trova a dover fare una query su una tabella, magari quella inserita nel post precedente.
Non vi spiegherò quanto è contorto Drupal. Mi limiterò a farvi vedere un esempio.

Premessa: In Drupal 7 le query al DB vengono fatte tramite funzioni apposite che si chiamano come la tipologia di query da fare. Avremo quindi:

db_select;
db_insert;
db_update;
db_delete;

Mettiamo che abbiamo una tabella chiamata png_creator_races e vogliamo fare l'equivalente di:

SELECT * FROM png_creator_races as n ORDER BY id_race ASC

Useremo la seguente sintassi:

<?php
public function loadAllRaces(){
        $result = db_select('png_creator_races', 'n')->fields('n')->orderBy('id_race', 'ASC')->execute();
        while ($field = $result->fetchAssoc()){
            $race = new race();
            $race->race_name = $field['race_name'];
            $race->mod_for = $field['mod_for'];
            $race->mod_dex = $field['mod_dex'];
            $race->mod_cos = $field['mod_cos'];
            $race->mod_int = $field['mod_int'];
            $race->mod_wis = $field['mod_wis'];
            $race->mod_car = $field['mod_car'];
            $race->mod_cus = $field['mod_cus'];
            $this->races[] = $race;
        }        
    }
?>

Nell'esempio sopra ho un metodo loadAllRaces dentro una classe (che ho omesso) che si occupa di fare la nostra select.

Tutto ruota sull'oggetto ritornato da db_select i cui due parametri sono "nome tabella" ed "alias tabella".
Tutti gli altri pezzi possono essere aggiunti in coda o anche sotto secondo la forma:


<?php
$query = db_select('png_creator_races', 'n');
        $query->fields('n');
        $query->orderBy('id_race','ASC');
        $result = $query->execute();
?>

Da notare che mentre prima avevo la variabile result direttamente uguale a tutto il blocco, adesso ho creato un oggetto $query su cui ho lanciato i vari metodi.
Questi metodi permettono di fare altre cose tra cui JOIN, condizioni WHERE, le ovvie LIMIT ed addirittura la paginazione. Per questo ed altro rivediamo altri esempi in futuro.

Tornando al pezzo di codice sopra, vediamo come il nostro While usi il comando fetchAssoc che restituisce la nextRow per associazione. La parte sotto è solo una mappatura della riga della tabella su un oggetto di tipo race.

Drupal - Custom Tables per un Modulo

Nel post precedente abbiamo creato un modulo di base molto semplice.
Io però vengo da una storia di programmazione spinta quindi la domanda 2 che mi sono fatto è stata?

Come creo tabelle personali per il mio bel modulo?


Drupal ha ovviamente un hook apposito chiamato modulo_schema()


Per prima cosa cosa creiamo un nuovo file nella dir del modulo chiamato modulo.install ed andiamo ad aggiungerlo all'array files[] dentro il file .info.



name = PNG Cretgor
description = Modulo per la creazione di un PNG
package = Pathfinder
version = "0.1"
core = 7.x
files[] = png_creator.test
files[] = png_creator.install


Non è strettamente necessario ma è meglio metterlo.

Ora andiamo a riempire il .install. Qua dentro occorre mettere lo schema della/e tabelle che però non possono, ovviamente, essere scritte con un sql standard (sarebbe troppo facile). Occorre passare per una struttura array specifica di drupal piuttosto complessa.

Per crearla però possiamo passare per un modulo drupal fatto apposta chiamato SCHEMA

Dopo averlo installato quello che dovete fare è creare la/le tabelle sul DB manualmente con il vostro strumento preferito (es. phpmyadmin).
Assicuratevi che il nome della tabella inizi con: drupal_nomemodulo_nometabella.
Quel drupal_ è in realtà il prefisso che avete deciso di mettere, eventualmente, durante l'installazione di drupal.

Una volta create le vostre tabelle, andate nel modulo SCHEMA che trovate nella scheda STRUTTURA dopo averlo installato. Questo modulo farà un'analisi automatica di tutte le tabelle del DB producendo anche l'array schema che si aspetta lo stesso drupal.
Trovate tutti gli schemi nella scheda INSPECT.

Nel mio esempio ho creato due tabelle, una delle quali si chiama drupal_png_creator_races.

$schema['drupal_png_creator_races'] = array(
  'description' => 'TODO: please describe this table!',
  'fields' => array(
    'id_race' => array(
      'description' => 'TODO: please describe this field!',
      'type' => 'serial',
      'size' => 'small',
      'not null' => TRUE,
    ),
    'race_name' => array(
      'description' => 'TODO: please describe this field!',
      'type' => 'varchar',
      'length' => '100',
      'not null' => TRUE,
    ),
    'mod_for' => array(
      'description' => 'TODO: please describe this field!',
      'type' => 'int',
      'size' => 'small',
      'not null' => TRUE,
      'default' => 0,
    ),
    'mod_dex' => array(
      'description' => 'TODO: please describe this field!',
      'type' => 'int',
      'size' => 'small',
      'not null' => TRUE,
      'default' => 0,
    ),
    'mod_cos' => array(
      'description' => 'TODO: please describe this field!',
      'type' => 'int',
      'size' => 'small',
      'not null' => TRUE,
      'default' => 0,
    ),
    'mod_int' => array(
      'description' => 'TODO: please describe this field!',
      'type' => 'int',
      'size' => 'small',
      'not null' => TRUE,
      'default' => 0,
    ),
    'mod_sag' => array(
      'description' => 'TODO: please describe this field!',
      'type' => 'int',
      'size' => 'small',
      'not null' => TRUE,
      'default' => 0,
    ),
    'mod_car' => array(
      'description' => 'TODO: please describe this field!',
      'type' => 'int',
      'size' => 'small',
      'not null' => TRUE,
      'default' => 0,
    ),
    'mod_cus' => array(
      'description' => 'TODO: please describe this field!',
      'type' => 'int',
      'size' => 'small',
      'not null' => TRUE,
      'default' => 0,
    ),
  ),
  'primary key' => array('id_race'),
);


Nel mio caso sto creando la tabella equivalente a questo codice.

CREATE TABLE IF NOT EXISTS `drupal_png_creator_races` (
  `id_race` smallint(6) NOT NULL AUTO_INCREMENT COMMENT 'TODO: please describe this field!',
  `race_name` varchar(100) NOT NULL COMMENT 'TODO: please describe this field!',
  `mod_for` smallint(6) NOT NULL DEFAULT '0' COMMENT 'TODO: please describe this field!',
  `mod_dex` smallint(6) NOT NULL DEFAULT '0' COMMENT 'TODO: please describe this field!',
  `mod_cos` smallint(6) NOT NULL DEFAULT '0' COMMENT 'TODO: please describe this field!',
  `mod_int` smallint(6) NOT NULL DEFAULT '0' COMMENT 'TODO: please describe this field!',
  `mod_sag` smallint(6) NOT NULL DEFAULT '0' COMMENT 'TODO: please describe this field!',
  `mod_car` smallint(6) NOT NULL DEFAULT '0' COMMENT 'TODO: please describe this field!',
  `mod_cus` smallint(6) NOT NULL DEFAULT '0' COMMENT 'TODO: please describe this field!',
  PRIMARY KEY (`id_race`)
)

A questo punto apriamo il file .install e inseriamo l'hook per fargli leggere 'sta roba.



function png_creator_schema() {
      $schema['png_creator_races'] = [...]
}


Dentro l'hook schema inserirete tutti gli array $schema che avrete ricavato da quel modulo.

INSERIRE GIAQQUALCOSA!


Ci sono molti casi in cui vorrete pre-inserire dei dati nella/e tabelle appena create in fase di installazione. Per farlo dobbiamo andare a fare queste insert manuali, dentro l'hook chiamato nomemodulo_install().

Per rendere le cose più belle, nel mio esempio ho creato un file .inc con un array di tutte i dati da inserire:

<?php 

$races[] = array ('race_name'=>'human',
                    'mod_cus'=>2);

$races[] = array ('race_name'=>'half-elven',
                    'mod_cus'=>2);

$races[] = array ('race_name'=>'half-orc',
                    'mod_cus'=>2);

$races[] = array ('race_name'=>'dwarf',
                    'mod_cos'=>2,
                    'mod_sag'=>2,
                    'mod_car'=>-2);

$races[] = array ('race_name'=>'elf',
                    'mod_dex'=>2,
                    'mod_cos'=>-2,
                    'mod_int'=>2);

$races[] = array ('race_name'=>'gnomes',
                    'mod_car'=>2,
                    'mod_for'=>-2,
                    'mod_cos'=>2);

$races[] = array ('race_name'=>'halfing',
                    'mod_car'=>2,
                    'mod_for'=>-2,
                    'mod_dex'=>2);

$GLOBALS['pathfinder_races'] = $races;

?>

Purtroppo includerlo direttamente nel file .install non basta a dare lo scope alla variabile quindi occorre per forza metterlo in una global. L'alternativa è scrivere tutto questo codice, direttamente nell'hook _install.

L'hook install diventa quindi:

<?php
function png_creator_install() {
        global $pathfinder_races;
      foreach ($pathfinder_races as $oneRace)
          $result =  drupal_write_record ('png_creator_races',$oneRace);
  }
?>

Da notare l'uso di drupal_write_record. Nonostante abbia provato anche db_query, non c'è stato verso di farla funzionare quindi ho usato questa.

Questo metodo accetta due parametri fondamentali. La tabella ed un array con chiave-valore dove chiave è la colonna della tabella e valore il valore corrispondente.