poEdit e i file .ctp

Se si tenta di utilizzare poEdit per la traduzione di file con estensione .ctp inizialmente si ottiene un messaggio del tipo:
“Poedit non ha trovato alcun file nelle directory analizzate”
Se si va in File > Preferenze > Parser e si modifica PHP si può aggiungere una estensione e si avrà una lista del tipo
“*.php;*.ctp”
Ma questo non basta perchè si otterrebbe un messaggio del tipo:
“xgettext: warning:file `users/login’ extension `ctp’ is unknown;will try C”

Per far processare correttamente i file .ctp da poEdit è sufficente aggiungere una riga nel comando del parser.

  1. Aprire le preferenze di poEdit
  2. Selezionare Parsers e scegliere PHP
  3. Modificare il setup del parser PHP e alla fine del comando del parser aggiungere:
    --language=php

Riavviare il programma

FormHelper: creare una select automagicamente

Nella creazione di un form con l’helper è sufficente assegnare il giusto nome ad una variabile affinchè venga utilizzata come options in una select, senza dover specificare altri parametri. Mi spiego con un esempio.

Devo gestire dei gruppi di utenti con la possibilità di avere dei sotto-gruppi, quindi ho il model Group che agisce come un albero (beahvior Tree) e in fase di inserimento devo specificare il gruppo parent, popolando il campo parent_id con l’id del gruppo padre.
Il form di inserimento deve quindi contenere una select da dove poter scegliere il gruppo padre.

Controller: groups_controller
$groups = $this->Group->findAll(null,'id,groupname','groupname ASC',null,null,-1);
$groups = Set::combine($groups, "{n}.Group.id","{n}.Group.groupname");
$this->set('parents',$groups);

Nel controller ho ricavato l’elenco dei gruppi e lo assegno alla variabile ‘parents’. Questo è il passaggio determinante.

View: add.ctp
input('Group.parent_id', array('label'=>false));?>

La chiave di questo comportamento è l’assegnazione del giusto nome alla variabile che contiene le options, ovvero deve essere un nome che risponde alle regole delle inflessioni di CakePHP, infatti il nome della variabile giusto è definito dalla seguente espressione

$varName = Inflector::variable(Inflector::pluralize(preg_replace('/_id$/', '', $this->field())));

Ma poichè sto utilizzando un TreeBehavior è sicuramente conveniente avere una select organizzata appunto come un albero sfruttando la funzione

$groups = $this->Group->generatetreelist (null,"{n}.Group.id","{n}.Group.groupname",'-- ');

Auth Component: pieno controllo dell’autenticazione

Come visto negli appunti precedenti, con la semplice attivazione il componente ha dei comportamenti predefiniti durante la fase di autenticazione che potrebbe essere necessario cambiare.
Inoltre vengono messi a disposizione metodi e proprietà utili, oltre che per la gestione dei permessi, in varie occasioni.

Personalizzare l’autenticazione
Impostando alcuni attributi, si determinano i comportamenti del componente.
Di seguito riporto la descrizione di alcune impostazioni di interesse legate all’autenticazione.

$autoRedirect = true
Determina se dopo l’avvenuta autenticazione AuthComponent redireziona automaticamente alla pagina cercata o no.

$fields = array('username' => 'username', 'password' => 'password')
Permette di specificare il nome dei campi usati nell’$userModel diversi da quelli di default necessari all’identificazione.
Ad esempio: array(‘username’ => ‘login_name’, ‘password’ => ‘passwd’).

$loginError = null
Si può impostare il messaggio di errore che viene utilizzato per comunicare la mancata corrispondenza di userid e password.
Questo è l’unico messaggio che viene visualizzato per una questione di sicurezza, così non vengono fornite indicazioni circa l’errore di autenticazione occorso.
Il messaggio qui impostato non viene visualizzato automaticamente nella session Flash, ma deve essere impostato nella view nel seguente modo
if ($session->check(‘Message.auth’)) $session->flash(‘auth’);

$authError = null
Messaggio di errore che appare quando si tenta di accedere a un’area per la quale è richiesta l’autenticazione.

$loginRedirect = null
Quando si richiede l’accesso a una pagina e si viene ridirezionati alla pagina di login $loginAction, dopo l’autenticazione l’utente viene rimandato alla pagina inizialmente richiesta, senza doverla richiedere nuovamente dopo il login.
Se $loginAction non è impostata, l’utente viene ridirezionato alla pagina specificata in $loginRedirect

$logoutRedirect = null
L’azione di defautl alla quale viene ridiretto l’utente dopo il logout. L’URL del redirect viene fornita da AuthComponent::logout() che di default restituisce $loginAction.

$loginAction = null
E’ una stringa o un array che definisce l’URL per la richiesta di login.
Se non impostata, AuthComponent la imposta come (pluralize) $userModel / login , a meno che non venga impostata $loginRedirect

$userModel = 'User'
Il nome del Model utilizzato per eseguire l’autenticazione degli utenti, ovvero l’oggetto che detiene username e password degli utenti. Come visto, il valore di default è il model User.

$userScope = array()
Si possono aggiungere delle condizioni aggiuntive per la verifica dell’utente.
Ad esempio se si vuole permettere l’accesso ai soli utenti che abbiano il campo “attivato” abilitato allora si può definire array(‘User.attivato’ => 1). In questo modo, anche se l’utente inserisce la giusta userid e password gli verrà permesso l’accesso solo se il suo stato è “attivato”.

$sessionKey = null
Definisce il nome della chiave di sessione che contiene i dati sull’utente autenticato.
Se non è specificato il valore di default è “Auth.{$userModel}”.

Queste impostazioni devono essere definite nel controller

function beforeFilter(){
		$this->Auth->authError = "Per accedere alla pagina richiesta bisogna autenticarsi";
		$this->Auth->loginError = 'Tentativo di accesso fallito. Controllare username e password.';
	}

Auth Component: creare un utente, eseguire il login e il logout

Una volta attivato il component, creata la tabella degli utenti e la maschera per il login, è il momento di creare un utente per verificare il corretto funzionamento dell’autenticazione. Ecco due modi di farlo.

Inserimento manuale nella tabella users

Posso inserire i dati nella tabella attraverso il client MySQL o un altro tool grafico (io uso phpMyAdmin ) tenendo presente che la password deve essere converita con la funzione hash utilizzata da Cake, la seguente:

hashpwd = sha1 ( salt + plain_password )

dove salt è la stringa di sicurezza configurata durante l’installazione di CakePHP presente nel file \app\config\core.php.
sha1 è l’algoritmo utilizzato per default da Cake per la funzione hash, ma è possibile cambiare metodo con MD5 e SHA256

Gestione utenti

Creo una gestione completa degli utenti sulla tabella users usando il bake da riga di comando così da poter inserire il primo utente.
A questo punto, seguendo il naming canonico, accedo alla mia gestione degli utenti http://mywebspace/users/ e…. vengo rimandato alla pagina di login !!
Per accedere, almeno temporaneamente alle azioni di users, si interviene su app_controller.php, dove avevamo attivato $authComponent e si inserisce


function beforeFilter()	{
     $this->Auth->allow();
}

A questo punto cake concede l’accesso a qualsiasi azione e possiamo andare a creare l’utente che ci interessa.
Finito l’inserimento, rimuoviamo la riga con il metodo allow() e proviamo a d accedere di nuovo a http://mywebspace/users/.
Ci dovrebbe chiedere nuovamente la userdi – password, ma questa volta si può inserire l’utente inserito e accedere alla sezione della gestione utenti.

Da notare due cose: quando inserisce ad esempio l’URL http://mywebspace/articles/view/234 l’utente viene rimandato a http://mywebspace/users/login e dopo aver effettuato il login, viene reindirizzato sull’URL da lui richiesta in precedenza.
L’altra cosa da notare è che sulla password immessa in fase di inserimento utente, viene automaticamente eseguito l’hash prima del salvataggio in tabella, senza bisogno di aggiungere alcun codice nel controller, nel model o altrove.

Il log out
Per chiudere la sessione è sufficente creare un’action nel controller nel quale invocare il metodo logout di Auth

function logout(){
		$this->Session->setFlash("L\'utente è uscito regolarmente!");
		$this->redirect($this->Auth->logout());
	}

Auth Component: attivazione e quickstart

Attivazione del component Auth

Ho appena installato CakePHP e configurato il database completamente vuoto.
Mi appare la pagina iniziale di Cake, con le indicazioni canoniche.

Creo il file /app/app_controller.php e dichiaro come componente Auth

class AppController extends Controller {
	var $components = array('Auth');
}

Il component è subito attivato e ricaricando la pagina si ottiene un errore perchè si è stati reindirizzati all’URL /users/login.
In pratica essendo attivato in ogni pagina richiesta, il sistema riconosce che l’utente non è autenticato e considera necessaria l’autenticazione per accedere a qualsiasi pagina del sito.
Quindi avviene il reindirizzamento verso l’indirizzo di default /users/login per far si che l’utente si possa autenticare.

Chiaramente si riceve un messaggio di errore se la pagina ancora non esiste, ovvero il controller e la view relativa.

La struttura necessaria

Servono quindi:

  • un model che permetta di conservare e confrontare i dati dell’utente per l’accesso (userid e password)
  • un controller per le azioni relative all’utente (login, logout)
  • una view per il form di autenticazione

La tabella

CREATE TABLE IF NOT EXISTS `users` (
  `id` int(5) unsigned NOT NULL,
  `username` varchar(30) NOT NULL,
  `password` varchar(30) NOT NULL,
  `nome` varchar(60) NOT NULL,
  `cognome` varchar(100) NOT NULL,
  `active` tinyint(1) unsigned NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

Gli unici campi essenziali sono username e password. Si possono utilizzare anche nomi diversi per questi campi, purchè si impostino correttamente nel component (vedi sotto).

Il model

class User extends AppModel {
	var $name = 'User';
}

Il controller

class UsersController extends AppController {

	var $name = 'Users';
	var $helpers = array('Html', 'Form' );

	function login(){
	}
}

Il view (login.ctp)


Login

create('User', array('action' => 'login'));?> input('username');?> input('password');?> submit('Login');?> end(); ?>

A questo punto, accedendo a qualsiasi pagina dell’applicazione, Cake intercetta la richiesta e prima di soddisfarla, controlla che l’utente sia autenticato.
In caso negativo esegue un redirect sulla pagina di login.

AJAX semplice semplice

Si vuole creare una pagina dove è presente un link e un DIV con funzioni da contenitore.
Si vuole che alla selezione del link il DIV venga popolato con una lista di elementi, ricavati da un database, sfruttando AJAX, quindi senza ricaricare l’intera pagina.

Requisiti necessari

Sul server devono essere installate le librerie Javascript prototype e scriptaculous e devono essere richiamate nella pagina. Inoltre il charset deve essere impostato a “UTF-8″.

Il controller

Nel controller devono essere richiamati gli helper necessari: Html, Javascript e Ajax.
Richiamando anche il component “RequestHandler” si potranno sfruttare funzionalità circa il rendering di layouts e template.
Il metodo index() imposterà la variabile che sarà stampata inizialmente nel contenitore.
Il metodo listcat() (o qualsivoglia nome) ricaverà la lista da stampare (in questo caso una lista di categorie).

Le view

index.ctp conterrà l’intera pagina corredata dei vari elementi necessari quali il titolo o menu, ecc. oltre al necessario contenitore DIV che verrà aggiornato con l’inserimento dei dati ricavati.

listcat.ctp invece conterrà la sola lista da stampare poichè rappresenta il contenuto che verrà inserito nel contenitore DIV.

Quindi è necessario ricordare che il sistema aggiornerà l’oggetto DOM con ciò che viene prodotto dalla view che l’action richiamata (listcat) ha prodotto.

Di seguito il codice di esempio.

Controller

set("lista","Vuoto");
    }

    function listacat(){
$this->set('lista',$this->Category->findAll());
    }
}
?>

Da aggiungere al Layout
charsetTag('UTF-8') ?>
link('prototype') ?>
link('scriptaculous.js?load=effects') ?>

View – listacat.ctp

    {$cat['Category']['nome']}
    
    ";
    }
    ?>

View - index.ctp


Tests

link("Prova AJAX", "/tests/listacat",array("update" => "content")); ?>

Pagination nella versione 1.2

Controller

Nel controller va definita la proprietà

var $paginate
alla quale vengono assegnati dei valori in un array che definiscono lo stato iniziale della lista.
I parametri che si possono assegnare a $paginate sono quelli necessari ad eseguire il metodo findAll:

  • conditions
  • fields
  • order
  • limit
  • page
  • recursive

Il metodo del controller paginate() restituisce un array in stile risultato query del modello.
I parametri che si possono passare a paginate sono:

mixed $object
E’ usato nel caso in cui un controller usa più di un model e si vuole effettuare la paginazione per il modello che non è quello di default.
Se $object è un array, viene interpretato come $scope, poichè per default $object non è richiesto.

mixed $scope
Sono i criteri per impostare il filtro sui dati.

array $whitelist
Rappresenta la lista dei parametri per la paginazione per i quali l’utente ha il permesso di passarli attraverso l’url

$options
E’ un array che continenele relativi ai link per la paginazione
I valori che si possono specificare sono ($options['valore'])

sort = the key that the recordset is sorted.
direction = Direction of the sorting (default: ‘asc’).
format = Formato del contatore.
I formati supportati sono ‘range’, che visualizza l’intervallo dei record visualizzati sul totale e
‘pages’ che visualizza la pagina visualizzata sul totale.
Se si passa una stringa, questa viene analizzata e vengono sostituite le costanti seguenti con i rispettivi valori: %page%, %pages%, %current%, %count%, %start%, %end% .

separator = The separator of the actual page and number of pages (default: ‘ of ‘).
url = Url of the action. See Router::url().

model = The name of the model.
escape = Defines if the title field for the link should be escaped (default: true).
update = DOM id of the element updated with the results of the AJAX call. If this key isn’t specified Paginator will use plain HTML links.
indicator = DOM id of the element that will be shown when doing AJAX requests.

$paginator->link();

$paginator->link($title, $url = array(), $options = array());

$title = è obbligatorio ed è il testo che appare come link
$url = è nel formato array(‘page’=>’2′);
Restituisce il link alla pagina nel giusto formato
$options = le opzioni di visualizzazione