Iniciándose

En este capitulo, iremos a través de todos los pasos necesarios para ajustar y utilizar la aplicación "de libro alamacenado" empezaremos con un vistazo a la disposición del directorio, entonces usted sabrá donde esperar encontrar los archivos.

Estructura del generador propel

Antes de que empesemos con nuestra "construcción de un libro de almacenamiento" por ejemplo, usted debería tomese un momento para autofamiliarisarse con la estructura del directorio generador de Propel. Para empezar, usted debería observar el diredctorio projects/bookstore/ como desea personalizar los archivos en este directorio. También, después de que haya completado la construcción, habrá un directorio projects/bookstore/build/ que contendrá los archivos generados que usted necesitara.

propel/generator  
  |-- classes
  |    +-- propel
  |         |-- engine
  |         |    |-- database
  |         |    |    |-- model
  |         |    |    +-- transform
  |         |    +-- sql
  |         +-- phing    
  |-- dtd
  |-- projects
  |    +-- bookstore
  |-- templates
  +-- test
       |-- classes
       |    +-- propel
       +-- etc

La siguiente tabla describe brevemente los contenidos directorios mayores:

Fuente del árbol de directorios Propel
Directory Contents

clases

Repositorio de todas las clases usadas por Propel. Estas incluyen las clases Creole, las cuales proveen una API ligera de bases de datos unificada.

dtd

Esto almacena un simple archivo DTD para el esquema XML de validación de archivos de bases de datos.

projects

Este es un repositorio para todos los archivos de proyecto(un directorio por proyecto). Propel lee el esquema & de los archivos de configuración desde este directorio y crea todas las salidas en este directorio.

Plantillas

Hay plantillas PHP (capsula) que crea las clases PHP y archivos de descarga SQL basados en el modelo de datos.

Prueba

PHPUnit2 casos de prueba y el script bookstore-test.php que usted puede ejecutar después de completar este ejercicio de instalación.

Describiendo su base de datos en XML

En orden de crear clases que exactamente represente sus tablas -- y las relaciones entre estas en su base de datos -- necesita proveer una representación en XML de la base de datos. Avanzaremos a través del archivo projects/bookstore/schema.xml la cual encontrara en su distribución de Propel.

Note: si quiere usar Propel con una base de datos existente, Propel puede usar las clases metadato de Creole para que construya el archivo XML por usted. Aún necesitará - en la mayoría de las veces -observar cómo propel produce el XML (ej. especificar autoincremento para las columnas, o personalizar los nombres en PHP para las columnas, adicionar llaves foraneas relaciones para bases de datos no soportadas etc.). revise el apéndice A de las Operaciones de propel para más información.

Aquí hay una parte del archivo provisto schema.xml.Como puede ver, las definiciones del modelo de datos de propel es muy cercano a la estructura actual de las bases de datos. (Nosotros constantemente adicionamos cosas, por ello la versión en su código puede lucir un poco diferente.)

<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>
<database name="bookstore" defaultIdMethod="native">
 <table name="book" description="Book Table">
  <column
    name="book_id"
    required="true"
    primaryKey="true"
    type="INTEGER"
    description="Book Id"/>
  <column
    name="title"
    required="true"
    type="VARCHAR"
    size="255"
    description="Book Title"/>
  <column
    name="isbn"
    required="true"
    type="VARCHAR"
    size="24"
    phpName="ISBN"
    description="ISBN Number"/>
  <column
    name="publisher_id"
    required="true"
    type="INTEGER"
    description="Foreign Key Publisher"/>
  <column
    name="author_id"
    required="true"
    type="INTEGER"
    description="Foreign Key Author"/>
  <foreign-key foreignTable="publisher">
   <reference
     local="publisher_id"
     foreign="publisher_id"/>
  </foreign-key>
  <foreign-key foreignTable="author">
   <reference
     local="author_id"
     foreign="author_id"/>
  </foreign-key>
 </table>

 <table name="publisher" description="Publisher Table">
  <column
    name="publisher_id"
    required="true"
    primaryKey="true"
    type="INTEGER"
    description="Publisher Id"/>
  <column
    name="name"
    required="true"
    type="VARCHAR"
    size="128"
    description="Publisher Name"/>
 </table>

 <table name="author" description="Author Table">
  <column
    name="author_id"
    required="true"
    primaryKey="true"
    type="INTEGER"
    description="Author Id"/>
  <column
    name="first_name"
    required="true"
    type="VARCHAR"
    size="128"
    description="First Name"/>
  <column
    name="last_name"
    required="true"
    type="VARCHAR"
    size="128"
    description="Last Name"/>
 </table>
</database>

El texto XML anterior debería ser claramente auto explicativo, pero nosotros discutiremos algunos de los atributos con un poco más de detalle. Para una total referencia de los atributos permitidos revise elApendice B - referencia de esquemas.

<table idMethod="" ... >, <database defaultIdMethod="" ... >

El elemento<table> soporta el atributo idMethod si no le es provisto nada entonces el atributo defaultIdMethod del elemento <database> es revisado. El valor válido de idMethod es "native" o "none". Ajustar este valor en "native" implica que el método nativo de la base de datos para generar IDs(identificadores)será utilizado -- ej. autoincrementar para MySQL,secuancias para PostgreSQL.

Nota: en Torque, hay también una opción llamada "id-broker" el cual utiliza una tabla de bases de datos para emular secuencias (akin para PEAR::DB o emulación de secuencias MBD). Por el momento Propel no soporta el método id-broker, como todas las bases de datos soportadas posee un soporte para construir para autoincremento o columnas de secuencia (mucho menos costo en rendimiento que en emulación).

<column type="">

El atributo type en la etiqueta <column> es usado para especificar un metatipo de propel. Estos metatipos lucen diferentes que los tipos SQL, pero eso no corresponde directamente. Esos tipos son tipos genericos que son convertidos por propel para una mejor concordancia en sus RDBMS. Por ejemplo, el tipo "TIMESTAMP" de Propel debe ser interpretado como "DATETIME" para MySQL (porque el tipo TIMESTAMP nativo de MySQL es idiosincrático y una pena para leer y clasificar). revise el capitulo Tipos de columna de Propel para más información.

<column phpName="" ... />

Cuando se crean clases, Propel automaticamente "PEAR-ifies" los nombres de las columnas cuando se crea el modelo objeto de clases. El esquema por defecto de nombramiento convierte los nombres "underscore" de las columnas a los nombre de los métodos de las clases estandard de PEAR, como book.mi_nombre_columna crea métodos Book::getMyColumnName(), Book::setMyColumnName(), etc.

Usted puede sobre-escribir el nombre resultante especificando su propio nombre usando el atributo phpName.

Ajustando las propiedades de construcción

Hay una importante distinción que se debe hacer entre propiedades de construcción y propiedades de ejecución. Las propiedades de construcción contienen información sobre su proyecto que necesita propel para construir sus clases y SQL. No todas las propiedades son requeridas: por ejemplo, Propel no necesita saber cómo conectarse a su base de datos a menos que qu usted quiera usar Propel para crear la base de datos o exportar datos desde una base de datos existente.

Propel revisará las propiedades de construcción en build.properties y default.properties en el directorio base de Propel y el directorio de proyecto actual que está siendo construido. Para ello usando Propel desde SVN: usted necesitará renombrar el archivo build.properties-sample (que es provisto) a el nombre build.properties. Usted puede desear personalizar los contenidos,pero es recomendado que cambios en proyectos específicos sean hechos en el archivo build.properties en el directorio del proyecto (ej. projects/bookstore/build.properties). Aquó hay un archivo de ejemplo de un proyectobuild.properties:

# nombre del proyecto
propel.project = bookstore
 
# controlador de la base de datos 
propel.database = mssql

# parámetros de conección (opcional)
propel.database.url = mssql://localhost/bookstore

Ajustando las propiedades de ejecución

Las propiedades de ejecución pueden a menudo ser las mismas como en propiedades de conección para construir sus bases de datos, pero estas no son asumidas para ello. Esto significa que usted necesitará editar el archivo runtime-conf.xml para especificar los ajustes. Note que para las propiedades de ejecución usted debe especificar infrmación para la conexión a la base de datos. También note que actualmente usted debe especificar la información de conección que sea conforme al estilo de arreglo de PEAR, antes de que el DSN URL usado para construir los parámetros build.properties de conección.

<?xml version="1.0" encoding="ISO-8859-1"?>

<config>
 <log>
  <ident>propel-bookstore</ident>
<level>7</level> </log> <propel> <datasources default="bookstore"> <datasource id="bookstore"> <!-- el adaptador Propel (usualmente igual como el tipo php de conecció de DSN) --> <adapter>sqlite</adapter> <connection> <phptype>sqlite</phptype> <hostspec>localhost</hostspec> <database>./bookstore.db</database> <username></username> <password></password> </connection> </datasource> </datasources> </propel> </config>

Durante el proceso de construcción este archivo será convertido en un arreglo PHP en projects/bookstore/build/conf/runtime-conf.php , es por ello que no es necesario clasificación de ejecución. Note que el actual arreglo generado no concuerda con el formato de un archivo XML. Esto es por compatibilidad de anteriores con el formato del antiguo archivo .properties.

<?php
// This file generated by Propel convert-props target on 09/08/05 20:23:27
// from XML runtime conf file .\projects\bookstore\runtime-conf.xml
return array (
'log' =>
array (
'ident' => 'propel-bookstore',
'level' => '7',
),
'propel' =>
array (
'datasources' =>
array (
'bookstore' =>
array (
'adapter' => 'sqlite',
'connection' =>
array (
'phptype' => 'sqlite',
'hostspec' => 'localhost',
'database' => './bookstore.db',
'username' => '',
'password' => '',
),
),
'default' => 'bookstore',
),
),
);

La clase Propel puede ahora leer las propiedades desde el archivo. Usted verá más tarde usted pasa la ruta de este archivo a Propel::init() para completar el inicio.

Construyendo

Hasta este punto Propel ha sido installado, todas las opciones de configuración han sido ajustadas y ahora usted está listo para construir. La construcción requiere que usted tenga instalado y configurado Phing.


Construyendo con propel PEAR instalados

Para construir sus clases y SQL, simplemente ejecute el script empaquetado propel-gen:

$> propel-gen /path/to/bookstore 

El procedimiento en Windows es exactamente el mismo:

C:\> propel-gen C:\path\to\bookstore
La aplicación de ejmplo bookstore (tienda de libros) en su directorio de data PEAR, dependera de su plataforma y de su instalación.

construyendo en una instalación tradicional(o SVN) de Propel

Para construir sus clases y SQL, simplemente ejecute Phing usando el archivo build-propel.xml :

$> cd /usr/local/propel/generator
$> phing -Dproject=bookstore

El procedimiento en Windows es exactamente el mismo:

C:\> cd C:\PHP\apps\propel\generator
C:\PHP\apps\propel\generator> phing -Dproject=bookstore

El archivo build.xml provee una envoltura conveniente para el script build-propel.xml, y también le permite usar archivos build.properties por proyecto. Si usted prefiere llamar al escript build-propel.xml directamente, debera estar seguro de que todos las propiedades de sus proyectos esten especificadas en la parte inicial del archivo build.properties.


Esto construira los archivos SQL y el objeto por clase basado en cualquier esquema XML en el directorio projects/bookstore/ --para este caso, hay justo un archivo de esquema schema.xml.

El archivo resultante será colocado en el directorio projects/bookstore/build.

La salida deberóa parecerse o en algo a lo siguiente (con sus rutas desde luego, y algunas otras diferencias relacionadas con versiones más actuales de Propel y Phing):

C:\sandbox\propel-generator>phing -Dproject=bookstore
Buildfile: C:\sandbox\propel\generator\build.xml

propel-project-builder > projectcheck:

propel-project-builder > main:
    [phing] Calling Buildfile 'C:\sandbox\propel\generator\build-propel.xml' wit
h target 'main'

propel > main:
[phingcall] Calling Buildfile 'C:\sandbox\propel\generator\build-propel.xml' wit
h target 'sql'

propel > check-run-only-on-schema-change:

propel > sql-check:

propel > sql:
     [echo] +------------------------------------------+
     [echo] |                                          |
     [echo] | Generating SQL for YOUR Propel project!  |
     [echo] |                                          |
     [echo] +------------------------------------------+
[phingcall] Calling Buildfile 'C:\sandbox\propel\generator\build-propel.xml' wit
h target 'sql-template'

propel > sql-template:
[propel-sql] Processing: schema.xml
[propel-sql] Target database type: sqlite
[propel-sql] Target package:
[propel-sql] Using template path: C:\sandbox\propel\generator\templates
[propel-sql] Output directory: C:\sandbox\propel\generator\projects\bookstore\bu
ild\sql
[propel-sql] Generating SQL tables for database: bookstore
[propel-sql] Writing to SQL file: C:\sandbox\propel\generator\projects\bookstore
\build\sql\schema.sql
[propel-sql]     + book
[propel-sql]     + publisher
[propel-sql]     + author
[propel-sql]     + review
[propel-sql]     + media
[phingcall] Calling Buildfile 'C:\sandbox\propel\generator\build-propel.xml' wit
h target 'om'

propel > check-run-only-on-schema-change:

propel > om-check:

propel > om:
     [echo] +------------------------------------------+
     [echo] |                                          |
     [echo] | Generating Peer-based Object Model for   |
     [echo] | YOUR Propel project!                     |
     [echo] |                                          |
     [echo] +------------------------------------------+
[phingcall] Calling Buildfile 'C:\sandbox\propel\generator\build-propel.xml' wit
h target 'om-template'

propel > om-template:
[propel-om] Target database type: sqlite
[propel-om] Target package: bookstore
[propel-om] Using template path: C:\sandbox\propel-generator\templates
[propel-om] Output directory: C:\sandbox\propel\generator\projects\bookstore\bui
ld\classes
[propel-om] Processing: schema.xml
[propel-om] Processing Datamodel : schema.xml
[propel-om]   - processing database : bookstore
[propel-om]     + book
[propel-om]             -> BaseBookPeer
[propel-om]             -> BaseBook
[propel-om]             -> BookMapBuilder
[propel-om]             -> BookPeer
[propel-om]             -> Book
[propel-om]     + publisher
[propel-om]             -> BasePublisherPeer
[propel-om]             -> BasePublisher
[propel-om]             -> PublisherMapBuilder
[propel-om]             -> PublisherPeer
[propel-om]             -> Publisher
[propel-om]     + author
[propel-om]             -> BaseAuthorPeer
[propel-om]             -> BaseAuthor
[propel-om]             -> AuthorMapBuilder
[propel-om]             -> AuthorPeer
[propel-om]             -> Author
[propel-om]     + review
[propel-om]             -> BaseReviewPeer
[propel-om]             -> BaseReview
[propel-om]             -> ReviewMapBuilder
[propel-om]             -> ReviewPeer
[propel-om]             -> Review
[propel-om]     + media
[propel-om]             -> BaseMediaPeer
[propel-om]             -> BaseMedia
[propel-om]             -> MediaMapBuilder
[propel-om]             -> MediaPeer
[propel-om]             -> Media
[phingcall] Calling Buildfile 'C:\sandbox\propel\generator\build-propel.xml' wit
h target 'convert-props'

propel > convert-props:
     [echo] +------------------------------------------+
     [echo] |                                          |
     [echo] | Converting project properties file to an |
     [echo] | array dump for run-time performance.     |
     [echo] |                                          |
     [echo] +------------------------------------------+
  [capsule] Using templatePath: C:\sandbox\propel\generator\templates
  [capsule] Generating to file C:\sandbox\propel\generator\projects\bookstore\bu
ild\conf\bookstore-conf.php
  [capsule] Parsing control template: conf/Control.tpl

BUILD FINISHED

Total time: 5.9279 seconds

Nota: Si encuentra algún problema, intente adicionando las opciones -verbose o -debug para obtener mas información durante el procesode construcción de Phing.

Usando los archivos SQL

El archivo de definición SQL que acabamos de crear puede ser encontrado en projects/bookstore/build/schema.sql. Este archivo contiene el SQL para crear tablas (y otros objetos) en una base de datos existente. Usted puede también usar la etiqueta "create-db" para crear la base de datos, pero tenga en cuenta que algunos controladires, ej. Microsoft SQL Server, no soportan esto.

Por ejemplo, para crear cualquier base de datos usando MySQL:

% mysqladmin -u root create bookstore
% mysql -u root bookstore < projects/bookstore/build/sql/schema.sql

O, dejar que Propel/Phing lo hagan por usted:

% phing -Dproject=bookstore -Dtarget=create-db
% phing -Dproject=bookstore -Dtarget=insert-sql

Usando el modelo de objetos

Ahora la parte interesante -- cómo usar esas clases en su aplicación PHP. Las clases han sido creadas en el directorio build/classes/bookstore; usted debe adicionar el directorio build/classes a su path (ruta) o mover el directorio completo build/classes/bookstore a su locación en su path.

Para propositos de demostración, asumiremos que está usando un sistema UNIX y que tiene /var/www/bookstore_app/classes en su ruta incluida PHP:

$> cd /usr/local/propel/generator
$> mv projects/bookstore/build/classes/bookstore /var/www/bookstore_app/classes

En Windows, desde luego, puede uar el mouse para seleccionar y arrastrar la carpeta bookstore... :)

Ahora usted puede mover el archivo "compiled" de propiedades a algún lugar en su aplicación:

$> mv projects/bookstore/conf/runtime-conf.php /var/www/bookstore_app/conf/

Windows: click .... arrastras ... soltar.

Ahora, inicializar Propel e incluir las clases que necesita -- y preocuparse por cosas más importantes:

<?php

// Initialize Propel using path to the converted
// property file that was created with the convert-props phing target
require_once 'propel/Propel.php';
Propel::init('/var/www/bookstore_app/conf/runtime-conf.php');

// these are in the build/classes subdir of your project, so 
// that needs to be on your include_path
include_once 'bookstore/Author.php';
include_once 'bookstore/Publisher.php';
include_once 'bookstore/Book.php';

$author = new Author();
$author->setFirstName("Leo");
$author->setLastName("Tolstoy");

$pub = new Publisher();
$pub->setName("Viking Press");

$book = new Book();
$book->setTitle("War & Peace");
$book->setIsbn("0140444173");
$book->setPublisher($pub);
$book->setAuthor($author);

// save (insert, in this case) the new object
$book->save(); 

// $book->save() will automatically trigger $author->save()
// and $publisher->save() since those objects don't yet exist in the db.

// -------------------------------------

// Now FIND that book!

// "peer" class is static class that handles things like queries
$c = new Criteria();
$c->add(BookPeer::TITLE, "War%", Criteria::LIKE);
$c->setLimit(10); // just in case we keep running this script :)

$books = BookPeer::doSelect($c);

if ($books) {
  print "<p><strong>Found books!</strong></p>";


  foreach($books as $book) {
    print "<br/>" . $book->getTitle() . ", by " . 
          $book->getAuthor()->getFirstName();
} } else { print "<p><strong>Did NOT find books!</strong></p>"; } ?>

Esperamos que hasta este punto usted entienda lo bósico de cómo construir y usar las clases propel. El siguiente capitulo luciró un poco más complicado -- y probablemente escenarios más común y cómo propel puede hacer cosas aún más complicadas que lo que vimos en este capítulo.