PDO, Abstraction Layer

16 Giugno 2008

Finalmente con la versione 5.1 PHP ha un nuovo livello di astrazione per la connettività con i database veramente valido.
PDO, PHP Data Objects

Ho deciso di studiarlo un po’:

Creo un Database di prova:

DROP TABLE IF EXISTS first_table;


--CREATE TABLE first_table (
--id INT(10) NOT NULL AUTO_INCREMENT,
--name VARCHAR(255) NOT NULL,
--surname VARCHAR(255) NOT NULL,
--PRIMARY KEY (id)
--) TYPE=MyISAM;


CREATE TABLE first_table (
id INT(10) NOT NULL AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
surname VARCHAR(255) NOT NULL,
PRIMARY KEY (id)
) TYPE=innoDB;


INSERT INTO first_table (name,surname) VALUES ('matteo','magni');
INSERT INTO first_table (name,surname) VALUES ('john','starks');
INSERT INTO first_table (name,surname) VALUES ('michael','jordan');
INSERT INTO first_table (name,surname) VALUES ('kobe','bryant');
INSERT INTO first_table (name,surname) VALUES ('earvin','johnson');
INSERT INTO first_table (name,surname) VALUES ('larry','bird');
INSERT INTO first_table (name,surname) VALUES ('patrick','ewing');
INSERT INTO first_table (name,surname) VALUES ('reggie','miller');
INSERT INTO first_table (name,surname) VALUES ('ron','harper');
INSERT INTO first_table (name,surname) VALUES ('anfernee','hardaway');
INSERT INTO first_table (name,surname) VALUES ('tim','hardaway');
INSERT INTO first_table (name,surname) VALUES ('mitch','richmond');
INSERT INTO first_table (name,surname) VALUES ('jason','williams');
INSERT INTO first_table (name,surname) VALUES ('allen','iverson');
INSERT INTO first_table (name,surname) VALUES ('dwayne','wade');

Lo importo così dopo aver creato il DB pdo

mysql -p -D pdo < pdo.sql

Per le prove utilizzerò sia la versione con tabella MyISAM che quella con tabella InnoDB, la differenza è che per la prima non sono disponibili le transazioni.

Usiamo le eccezzioni per connetterci al DB

//USO le eccezzioni
$string_dsn = 'mysql:host=localhost;dbname=pdo'; // mysql
$string_username = 'user';
$string_password = 'password';
try {
$mypdo = new PDO($string_dsn, $string_username, $string_password);
}
catch(PDOException $e) {
echo 'Errore di connessione: '.$e->getMessage();
}

Query fatta con errore, mi restituisce il numero dell’errore:

$mypdo->exec('SELECT * FROM SELECT'); // errore generato appositamente
echo 'Errore N: '.$mypdo->errorCode();

Se la uso così è molto utile, mando io il messaggio che voglio:

if($mypdo->errorCode() !== '' || !$mypdo->exec('SELECT * FROM SELECT'))
echo 'errore nella query SELECT * FROM SELECT';

Così mi ritorna un array di tre elementi con le notizie sull’errore:

var_dump($mypdo->errorInfo());
//array di tre elementi
if(count($mypdo->errorInfo()) == 1) // ... tutto ok
if(count($mypdo->errorInfo()) > 1) { // ... ci sono errori
$errorinfo = $mypdo->errorInfo();
echo $errorinfo[2]; // stringa con l' errore
}

QUERY semplice senza preparare niente,
Mi ritorna i dati accessibili sia con il numero della colonna (partendo da 0) che con il nome della colonna
Query senza parametri aggiuntivi per stabilire che Fetch usare:


foreach($mypdo->query('SELECT * FROM first_table') as $row)
{
echo '--------------<br />';
echo '1: '.$row[0].' - 2: '.$row[1].'<br />';
echo 'id: '.$row['id'].' - name: '.$row['name'].'<br />';
}

mi ritorna i dati accessibili sia con il numero della colonna (partendo da 0) che con il nome della colonna.

Esplicito il tipo di Fetch con il parametro PDO_FETCH_*
PDo::FETCH_BOTH #usatelo come mysql fetch_array, risultato duplicato, quello di default

foreach($mypdo->query('SELECT * FROM first_table', PDO::FETCH_BOTH) as $row)
{
echo '--------------<br />';
echo '1: '.$row[0].' - 2: '.$row[1].'<br />';
echo 'id: '.$row['id'].' - name: '.$row['name'].'<br />';
}

PDO::FETCH_ASSOC #usatelo come mysql_fetch_assoc

foreach($mypdo->query('SELECT * FROM first_table', PDO::FETCH_ASSOC) as $row)
{
echo '--------------<br />';
echo 'id: '.$row['id'].' - name: '.$row['name'].'<br />';
}

PDO::FETCH_NUM #analogo a mysql_fetch_row

foreach($mypdo->query('SELECT * FROM first_table', PDO::FETCH_NUM) as $row)
{
echo '--------------<br/>';
echo '1: '.$row[0].' - 2: '.$row[1].'<br/>';
}

PDO::FETCH_OBJ #ritorna un oggetto con le proprieta’ che hanno il nome dei campi

foreach($mypdo->query('SELECT * FROM first_table', PDO::FETCH_OBJ) as $row)
{
echo '--------------<br />';
echo 'id->'.$row->id.' - name-> '.$row->name.'<br />';
}

PDO::FETCH_LAZY #combina *_BOTH e *_OBJ

foreach($mypdo->query('SELECT * FROM first_table', PDO::FETCH_LAZY) as $row)
{
echo '--------------<br />';
echo '1: '.$row[0].' - 2: '.$row[1].'<br />';
echo 'id: '.$row['id'].' - name: '.$row['name'].'<br />';
echo 'id->'.$row->id.' - name-> '.$row->name.'<br />';
}

PDO::FETCH_BOUND #Lo vediamo con bindColumn,
restituiti come attributi alle variabili PHP

Per Evitare problemi con DB case sensitive e non case sensitive
Setto che i nomi delle colonne siano restituiti sempre minuscoli

$mypdo->setAttribute(PDO::CASE_LOWER);
/*
* Psso usare anche
* PDO::CASE_UPPER
* PDO::CASE_NATURAL come sono fornite dal driver, metodo di default
*/

oppure si usa sempre FETCH_NUM

Utilizzo delle Transazioni

inizio la transazione

Su Mysql devo usare tabelle InnoDB perchè MyIsam non supportano le transazioni

Però…
The following example begins a transaction and issues two statements that
modify the database before rolling back the changes.
On MySQL, however, the DROP TABLE statement automatically commits the
transaction so that none of the changes in the transaction are rolled back.

Quindi niente drop per una transazione.

$mypdo->beginTransaction();
$mypdo->exec('DROP TABLE first_table');
$mypdo->rollBack(); // la tabella mytable rimarra' invariata :-)

come detto su MySQL la cancella lo stesso.


$mypdo->beginTransaction();
$mypdo->exec("INSERT INTO first_table (name,surname) VALUES ('gianni','morandi')");
$mypdo->rollBack(); // la tabella mytable rimarra' invariata :-)


$mypdo->beginTransaction();
$mypdo->exec("INSERT INTO first_table (name,surname) VALUES ('gianni','morandi')");
$mypdo->commit(); // la tabella mytable rimarra' invariata :-)

mi inserisce il nuovo valore.

Prepared Statement

Metodo Fetch
Metodo implementato nello statement che è in grado di spostare il cursore dei risultati di una query in un ciclo.
Gli posso passare i parametri come a query.
/*
* PDO::FETCH_ASSOC, PDO::FETCH_BOTH, PDO::FETCH_BOUND, PDO::FETCH_LAZY,
* PDO::FETCH_OBJ, PDO::FETCH_NUM
*/

$mypdo->beginTransaction();
// preparo la query
$stpdo = $mypdo->prepare('UPDATE first_table SET name = "pippo" WHERE id = 17');
// eseguo la query
$stpdo->execute();
$mypdo->commit();
echo 'SELECT';
$mypdo->beginTransaction();
// preparo la query
$stpdo = $mypdo->prepare('SELECT * FROM first_table');
// eseguo la query
$stpdo->execute();
//stampo a video il contenuto dell'array che mi crea fetch
while ($row=$stpdo->fetch())
{
echo 'id: '.$row['id'].' - name: '.$row['name'].'<br />';
}
$mypdo->commit();

La potenza prepare e execute
Potenza del metodo prepare

$mypdo->beginTransaction();
$stpdo = $mypdo->prepare('UPDATE first_table SET name = ? WHERE id = ?');
//i punti interrogativi saranno sostituiti da execute
$stpdo->execute(array('gianni', 17));
$mypdo->commit();
echo 'SELECT';
$mypdo->beginTransaction();
// preparo la query
$stpdo = $mypdo->prepare('SELECT * FROM first_table');
// eseguo la query
$stpdo->execute();
//stampo a video il contenuto dell'array che mi crea fetch
while ($row=$stpdo->fetch())
{
echo 'id: '.$row['id'].' - name: '.$row['name'].'<br />';
}
$mypdo->commit();

Posso preparare la query una volta e fare poi i vari inserimenti.
potenza prepare e execute ancora

$mypdo->beginTransaction();
$stpdo = $mypdo->prepare('UPDATE first_table SET name = :name WHERE id = :id');
//i punti interrogativi non sempre sono chiari, così lo è di più
$stpdo->execute(array(':name'=>'marcello',':id'=>17));
$mypdo->commit();
echo 'SELECT';
$mypdo->beginTransaction();
// preparo la query
$stpdo = $mypdo->prepare('SELECT * FROM first_table');
// eseguo la query
$stpdo->execute();
//stampo a video il contenuto dell'array che mi crea fetch
while ($row=$stpdo->fetch())
{
echo 'id: '.$row['id'].' - name: '.$row['name'].'<br />';
}
$mypdo->commit();

Metodo fetchAll
ritorna un array le righe del resultset

$mypdo->beginTransaction();
// preparo la query
$stpdo = $mypdo->prepare('SELECT * FROM first_table');
// eseguo la query
$stpdo->execute();
$row=$stpdo->fetchAll();
//stampo a video il contenuto dell'array che mi crea fetch
var_dump($row);
$mypdo->commit();

Metodo fetchAll

$mypdo->beginTransaction();
// preparo la query
$stpdo = $mypdo->prepare('SELECT * FROM first_table');
// eseguo la query
$stpdo->execute();
$row=$stpdo->fetchAll(PDO::FETCH_OBJ);
//così ho un array di oggetti
//stampo a video il contenuto dell'array che mi crea fetch
var_dump($row);
$mypdo->commit();

Metodi bind

bindParam

$id=10;
$mypdo->beginTransaction();
// preparo la query
$stpdo = $mypdo->prepare("SELECT * FROM first_table WHERE id = ? ");
$stpdo->bindParam(1,$id, PDO::PARAM_INT);
$stpdo->execute();
while ($row=$stpdo->fetch())
{
echo 'id: '.$row['id'].' - name: '.$row['name'].'<br />';
}
$mypdo->commit();

Oppure:

$id=10;
$mypdo->beginTransaction();
// preparo la query
$stpdo = $mypdo->prepare("SELECT * FROM first_table WHERE id = :id ");
$stpdo->bindParam(':id',$id, PDO::PARAM_INT);
$stpdo->execute();
while ($row=$stpdo->fetch())
{
echo 'id: '.$row['id'].' - name: '.$row['name'].'<br />';
}
$id=13;
$stpdo->bindParam(':id',$id, PDO::PARAM_INT);
$stpdo->execute();
while ($row=$stpdo->fetch())
{
echo 'id: '.$row['id'].' - name: '.$row['name'].'<br />';
}
$mypdo->commit();

Così ho preparato la query una volta sola, ed ho legato :id al valore della variabile $id.

bindValue

$id=10;
$mypdo->beginTransaction();
$stpdo = $mypdo->prepare('SELECT * FROM first_table WHERE id < ? ');
$stpdo->bindValue(1, $id, PDO::PARAM_INT);
$stpdo->execute();
while ($row=$stpdo->fetch())
{
echo ‘id: ‘.$row[’id’].’ - name: ‘.$row[’name’].’<br />’;
}
$mypdo->commit();

bindColumn

$mypdo->beginTransaction();
// preparo la query
$stpdo = $mypdo->prepare("SELECT * FROM first_table ");
$stpdo->bindColumn(1,$id);
$stpdo->bindColumn(2,$name);
$stpdo->bindColumn(3,$surname);
$stpdo->execute();
while($row = $stpdo->fetch(PDO::FETCH_BOUND))
echo $id.' '.$name.' '.$surname.'<br />'; // stampo i nomi
$mypdo->commit();

In pratica specifico prima come devono chiamarsi i dati letti da una query e di che tipo devono essere.
a variabile $id non l’avevo mai creata, nonostante ciò non ho avuto nessun notice o warning perche’ questa viene popolata e inizializzata ( se inesistente ) automaticamente all’ interno della chiamata a bindColumn.
Poi la variabile viene automaticamente riassegnata ad ogni ciclo del while ,
permettendoci di evitare i soliti $row[N] per il fetch_row o $row[’key’] per il fetch_assoc.

bindColumn

$mypdo->beginTransaction();
// preparo la query
$stpdo = $mypdo->prepare("SELECT * FROM first_table ");
$stpdo->bindColumn(1,$id, PDO::PARAM_INT);
$stpdo->bindColumn(2,$name, PDO::PARAM_STR);
$stpdo->bindColumn(3,$surname, PDO::PARAM_STR);
$stpdo->execute();
while($row = $stpdo->fetch(PDO::FETCH_BOUND))
echo $id.' '.$name.' '.$surname.'<br />'; // stampo i nomi
$mypdo->commit();

i parametri non modificano il risultato, ma “forse” ottimizzano le query

così abbiamo visto anche come funizona PDO::FETCH_BOUND

E se volessi usare Postgres invece di Mysql?
Semplice creo il DB pgsql come quello mysql e basta che cambi queste rige con i diversi parametri di connessione:

$string_dsn = 'pgsql:host=localhost;dbname=pdo'; // pgsql
$string_username = 'user';
$string_password = 'password';

ed il gioco è fatto, bello no?!

Lo studio l’ho fatto partendo da questi link:

http://it2.php.net/pdo
Pillola PDO

Gabba Gabba Hey
Bonzo

PHP day 2008

31 Maggio 2008

Venerdì scorso ho partecipato al primo giorno del PHP day 2008.
Rispetto allo scorso anno l’evento è risultato molto più interessante, forse anche per una mia maggior predisposizione allo scambio di opinioni e battute con i partecipanti. Purtroppo non ho potuto partecipare ai workshop del sabato, speriamo nel prossimo anno.

Ecco il talk che ho apprezzato di più:
Nel canale Enterprise si è assistito a un piccolo confronto tra tre CMS tra i più diffusi.

Avendoli utilizzati tutti e tre, ho apprezzato e seguito con interesse il confronto e la mia piccola conclusione è che Drupal è il miglior compromesso tra potenza e semplicità (ovviamente grazie a views e cck), eZpublish è potentissimo ma adatto a grosse realtà (con le sue 102 tabelle e tutto il resto è forse troppo esoso di risorse per un semplice blog), mentre Joomla rimane un po’ staccato avendo una flessibilità minore rispetto agli altri due, nonostante ciò è quello con un community maggiore, quindi è sempre da tenere d’occhio.

I pochi rimasti per i talk finali del venerdì

Oltre a questo ho fatto in tempo a sentire il talk di Daniele Teti sui Design patterns e quello di Simone Carletti sullo zend framework ed i web services. Quest’ultimo è stato ricco di esempi e molto interessante, non a caso ho scaricato lo Zend il giorno dopo e penso che, almeno come libreria comicerò ad usarlo. Uno dei suoi vantaggi è proprio il fatto di poter essere usato a pezzi, non costringendo il programmatore a sapere tutto sul framework.

Dal Blog di Fullo un po’ di Link su foto, video e altro dell’evento.
Fullo Blog

Ci si vede nel 2009

Gabba Gabba Hey
Bonzo

CakePHP, Blog[2]

11 Febbraio 2008

Andiamo avanti con la realizzazione del blog scritto con CakePHP.

Devo creare il meccanismo la creazione, modifica e eliminzaione dei post.

Aggiungere i Post
/app/controllers/posts_controller.php

class PostsController extends AppController
{
var $name = 'Posts';
function index()
{
$this->set(’posts’, $this->Post->findAll());
}
function view($id = null)
{
$this->Post->id = $id;
$this->set(’post’, $this->Post->read());
}
function add()
{
if (!empty($this->data))
{
if ($this->Post->save($this->data))
{
$this->flash(’Your post has been saved.’,'/posts’);
}
}
}
}
?>

Il controller guarda che i dati inviati via POST non siano vuoti, se non lo sono utilizza il metodo per salvare i dati. Con il metodo flash è possibile visualizzare un messaggio che dice se i dati sono stati salvati.

Creo la vista add

/app/views/posts/add.thtml

<<h1>Add Post</h1>
<form method="post" action="url(’/posts/add’)?>”>
<p>
Title:
input(’Post/title’, array(’size’ => ‘40′))?>
tagErrorMsg(’Post/title’, ‘Title is required.’) ?>
</p>
<p>
Body:
textarea(’Post/body’, array(’rows’=>’10′)) ?>
tagErrorMsg(’Post/body’, ‘Body is required.’) ?>
</p>
<p>
submit(’Save’) ?>
</p>
</form>

ecco come si visualizza la pagina:
http://localhost/cake/posts/add
creazione post

Modifico il modello Post
/app/models/post.php
aggiungo la validazione dei dati.


class Post extends AppModel
{
var $name = 'Post';
var $validate = array(
'title' => VALID_NOT_EMPTY,
‘body’ => VALID_NOT_EMPTY
);
}
?>

L’array $validate dice a Cake come validare i dati quando è chiamato il metodo save(). I valori per queste chiave si possono vedere in /cake/libs/validators.php.


/**
* Not empty.
*/
define('VALID_NOT_EMPTY', '/.+/');
/**
* Numbers [0-9] only.
*/
define('VALID_NUMBER', '/^[-+]?\\b[0-9]*\\.?[0-9]+\\b$/');
/**
* A valid email address.
*/
define('VALID_EMAIL', '/\\A(?:^([a-z0-9][a-z0-9_\\-\\.\\+]*)@([a-z0-9][a-z0-9\\.\\-]{0,63}\\.(com|org|net|biz|info|name|net|pro|aero|coop|museum|[a-z]{2,4}))$)\\z/i');
/**
* A valid year (1000-2999).
*/
define('VALID_YEAR', '/^[12][0-9]{3}$/');

Ecco cosa succede se si prova ad inserire un post senza il titolo:

title request

Cancellare i post, azione delete
/app/controllers/posts_controller.php


class PostsController extends AppController
{
var $name = 'Posts';
function index()
{
$this->set(’posts’, $this->Post->findAll());
}
function view($id = null)
{
$this->Post->id = $id;
$this->set(’post’, $this->Post->read());
}
function add()
{
if (!empty($this->data))
{
if ($this->Post->save($this->data))
{
$this->flash(’Your post has been saved.’,'/posts’);
}
}
}
function delete($id)
{
$this->Post->del($id);
$this->flash(’The post with id: ‘.$id.’ has been deleted.’, ‘/posts’);
}
}
?>

Aggiungo il link delete nella vista index
/app/views/posts/index.thtml


echo $html->link(
‘Delete’,
“/posts/delete/{$post[’Post’][’id’]}”,
null,
‘Are you sure?’
)
?>

se clicco mi si apre un alert javascript che mi chiede se sono sicuro.
Se disabilito javascript nel browser il post viene cancellato senza richiesta di conferma.

Modificare i post, azione edit
/app/controllers/posts_controller.php


function edit($id = null)
{
if (empty($this->data))
{
$this->Post->id = $id;
$this->data = $this->Post->read();
}
else
{
if ($this->Post->save($this->data['Post']))
{
$this->flash('Your post has been updated.','/posts');
}
}
}

Creo la vista edit
/app/views/posts/edit.thtml


<h1>Edit Post</h1>
<form method="post" action="url(’/posts/edit’)?>”>
hidden(’Post/id’); ?>
<p>
Title:
input(’Post/title’, array(’size’ => ‘40′))?>
tagErrorMsg(’Post/title’, ‘Title is required.’) ?>
</p>
<p>
Body:
textarea(’Post/body’, array(’rows’=>’10′)) ?>
tagErrorMsg(’Post/body’, ‘Body is required.’) ?>
</p>
<p>
submit(’Save’) ?>
</p>
</form>

aggiungo il link edit nella vista index
/app/views/posts/index.thtml


link(’Edit’, ‘/posts/edit/’.$post[’Post’][’id’]);?>

Modifica pagina di home
/app/config/routes.php

Nel file routes.php ci sono le configurazioni per i controller e le relative viste che si devono aprire per i vari indirizzi.

Modifico commentando

//$Route->connect('/', array('controller' => 'pages', 'action' => 'display', 'home'));

e settando:

/**
* Collegamento alla pagina index
*
*/
$Route->connect ('/', array('controller'=>'posts', 'action'=>'index'));

Così andando a http://localhost/cake mi apre direttamente la vista index del controller posts.

Ecco fatto, ora il sistema di gestione dei Post è finito, il prossimo obbiettivo è implementare un sistema di gestione degli utenti che possono inviare i post.

Gabba Gabba Hey
Bonzo

CakePHP, Blog [1]

5 Febbraio 2008

Comincio a fare “sul serio” con l’uso di CAkePHP, ora proverò a creare un blog.

Creazione database

Per prima cosa
Ecco alcuni accorgimenti sulle regole che devono seguire le tabelle (naming convention):

  • I nomi devono essere in plurale inglese (posts ad esempio), in modo che i modelli corrispondenti abbiano nomi in singolare;
  • tutte le tabelle devono avere una chiave primaria chiamata id;
  • le chiavi esterne utilizzate per costruire le relazioni tra le tabelle devono essere nomiate utilizzando il singolare della tabella a cui fanno riferimento seguito da _id (post_id per esempio);
  • è possibile includere i campi created e modified che verranno automaticamente aggiornati da CakePHP quando si opererà sui record.

Cake contiente una classe inflections che si occupa di ottenere i plurali dei vari nomi.

Creo il database blog_cake.

Creo la tabella posts.

/* First, create our posts table: */
CREATE TABLE posts (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(50),
body TEXT,
created DATETIME DEFAULT NULL,
modified DATETIME DEFAULT NULL
);


/* Then insert some posts for testing: */
INSERT INTO posts (title,body,created)
VALUES ('il titolo', 'Questo è il contenuto di un post.', NOW());
INSERT INTO posts (title,body,created)
VALUES ('secondo titolo', 'Altro contenuto di un post.', NOW());
INSERT INTO posts (title,body,created)
VALUES ('Divetimento', 'Divertiamoci.', NOW());

Imposto i dati di connessione al database nel file /app/config/database.php

var $default = array('driver' => 'mysql',
'connect' => 'mysql_pconnect',
'host' => 'localhost',
'login' => '‘,
‘password’ => ‘ ‘,
‘database’ => ‘blog_cakel’ );

Cake contiene una Classe AppModel da cui si parte per ottenere i nuovi modelli, estendendo tale classe di partenza.

Creo il modello Post:

/app/models/post.php


class Post extends AppModel
{
var $name = 'Post';
}
?>

Creo il controller Post
Dato che abbiamo deciso di seguire le convenzioni sui nomi sarà possibile accedere ai modelli implementati direttamente attraverso $this->NOME_MODELLO.
/app/controllers/posts_controller.php

class PostsController extends AppController
{
var $name = 'Posts';
}
?>

Ci aggiungo l’azione index


class PostsController extends AppController
{
var $name = 'Posts';
function index()
{
$this->set(’posts’, $this->Post->findAll());
}
}
?>

Il metodo index registra un array con tutti i post inseriti utilizzando il metodo set, che rende disponibile questo array alla vista.

Creo la vista index

/app/views/posts/index.thtml


<h1>Blog</h1>

<dl>
<dt>
<h3>link($post[’Post’][’title’], “/posts/view/”.$post[’Post’][’id’]); ?></h3>
echo $post['Post']['id'];
echo '<br/>';
echo $post['Post']['created'];
echo '<br/&gt';
echo '<br/>';
?>
</dt>
<dd>
echo $post['Post']['body'];
?>
</dd>
</dl>

Vado con il browser all’indirizzo:
http://localhost/cake/posts/
ed ecco il risultato:

cakePHP blog

Ora aggiungo l’azione view al controller, per gestire la visualizzazione di un singolo post.


class PostsController extends AppController
{
var $name = 'Posts';
function index()
{
$this->set(’posts’, $this->Post->findAll());
}
function view($id = null)
{
$this->Post->id = $id;
$this->set(’post’, $this->Post->read());
}
}
?>

Creo la vista view
/app/views/posts/view.thtml


<h2></h2>
<p><small>Created: </small></p>
<p></p>

Ora se clicco sul titolo del primo post, mi sposto all’indirizzo:
http://localhost/cake/posts/view/1

e vedo la vista view di questo post.

post singolo

Così ho completato tutte le pagine per visualizzare il blog, la prossima volta passo alle pagine per inserimento, modifica e cancellazione dei post.

Gabba Gabba Hey
Bonzo

CakePHP, installazione

28 Gennaio 2008

Visto che conosco e lavoro soprattutto con PHP ma mi affascina molto Ruby on Rails ho deciso di provare CakePHP, framework web PHP da molti paragonato al celebre framework scritto in Ruby.

cakePHP

Installazione di cakePHP:

Manuale cakePHP

Requisiti:

  • An HTTP server (like Apache) with the following enabled: sessions, mod_rewrite (not absolutely necessary but preferred)
  • PHP 4.3.2 or greater. Yes, CakePHP works great in either PHP 4 or 5.
  • A database engine (right now, there is support for MySQL 4+, PostgreSQL and a wrapper for ADODB).

Userò Apache, PHP 5 e MySQL.

Scaricare la versione stabile e scompattarla

cake_1.1.19.6305.tar.gz

Esistono due tipi di configurazione per lo sviluppo e per la produzione.

Produzione
In ambiente di produzione è meglio installare CakePHP in una directory indipendente configurando poi il Web server in modo che la cartella di root corrisponda a /path/di/cakephp/app/webroot.

Sviluppo
In ambiente di sviluppo è sufficiente scompattare i sorgenti nella directory di root, all’interno della directory cake.

Io utilizzerò la configurazione per lo sviluppo.

Schema applicazione
/app
   /config
   /controllers
      /components
   /models
   /plugins
   /tmp
   /vendors
   /views
      /elements
      /errors
      /helpers
      /layouts
      /pages
   /webroot
      /css
      /files
      /img
      /js
   /index.php
/cake
/docs
/vendors
/index.php

Configurazione Apache
attivo il modulo mod_rewrite ed ed utilizzo il file .htaccess fornito all’interno dell’installazione standard per poter utilizzare URL puliti e chiari da leggere che non facciano uso di query string.
riscrivere gli url con il modulo modrewrite di apache

Configurazione database
E’ necessario configurare l’accesso al database. Per fare questo bisogna modificare il file app/config/database.php.default e rinominarlo in database.php, modificando i valori dell’array $default.

var $default = array('driver' => 'mysql',
'connect' => 'mysql_connect',
'host' => 'localhost',
'login' => 'user',
'password' => 'password',
'database' => 'project_name',
'prefix' => '');

Creo il database cake

Se vado a http://localhost/cake vedo:

CakePHP Rapid Development

Your database configuration file is present.

Cake is able to connect to the database.

CakePHP release information is on CakeForge
Read the release notes and get the latest version
Editing this Page

To change the content of this page, create: /app/views/pages/home.thtml.
To change its layout, create: /app/views/layouts/default.thtml.
See the views section of the manual for more info
You can also add some CSS styles for your pages at: app/webroot/css/.

Ora sono pronto per scrivere la mia prima applicazione con CakePHP.

Gabba gabba hey
Bonzo