Una vez sus objetos han sido almacenados en la base de datos, usted necesitará una forma de traerlos de vuelta afuera. usted ya a visto un breve ejemplo de cómo encontrar objetos usando criterios de criterio de propel. En este capitulo revisaremos otros métodos de recuperación de objetos y examinaremos el sistema Criterio en más detalle.
Puede encontrar un registro específco (registro) usando el método retrieveByPK() de la clase Peer. Como el nombre lo implica, este método buscara un registro especifico basado en la llave primaria simple o compuesta provista.
// The book table has a single primary key column: book_id // Assuming that War & Peace was first book added to the table: $warAndPeace = BookPeer::retrieveByPK(1);
Desde luego, en algunos casos usted puede tener una tabla en donde la llave primaria este actualmente definida por los valores de varias columnas. Tomemos por ejemplo, la siguiente tabla de referencia para relaciones de muchos-a-muchos :
<table name="book_author_xref" description="Book-Author Crossreference Table"> <column name="book_id" required="true" primaryKey="true" type="INTEGER" description="Book Id"/> <column name="author_id" required="true" primaryKey="true" type="INTEGER" description="Author Id"/> </table>
En este caso, recuperando una referencia específica(claramente un ejercicio menos útil), será terminado pasando un arreglo al método retreiveByPK(). Note que el orden de las llaves es crítico y debe corresponder a el orden en que las columnas fueron definidas en el archivo XML.
// Gets the book_id=1,author_id=2 record $obj = BookAuthorXrefPeer::retrieveByPK(array(1,2));
Nota: Algunas de las ideas y ejemplos para esta sección vienen del dosumento Criteria HOWTO en la página web de Torque .
Para encontrar registros conocidos usando criterios específicos, usted usará el objeto Criterio en conjunto con el método doSelect() de la clase peer. Este es un muy poderoso significado de locación de criterios, como puede construirlo en la casi cualquier consulta SQL usando el sistema de Criterio. El método doSelect() retornará un arreglo de objetos del tipo apropiado.
$c = new Criteria(); $c->add(AuthorPeer::FIRST_NAME, "Leo"); $results = AuthorPeer::doSelect($c); foreach($results as $author) { print "Author: " . $author->getLastName() . ", " . $author->getFirstName() . "\n"; }
Tomar los resultados sellecionados es fácil, y se encontrará que con un poco de práctica representar aún una consulta muy complicada es simple usando la aproximación por Criterios .
En la forma más simple, el sistema de criterios es donde usted controla las condiciones para seleccionar registros:
$c = new Criteria(); // Find all authors with first name Karl but // last name is _not_ Marx. $c->add(AuthorPeer::FIRST_NAME, "Karl"); $c->add(AuthorPeer::LAST_NAME, "Marx", Criteria::NOT_EQUAL); // Find all authors with last name of Tolstoy, Dostoevsky, or Bakhtin $c2 = new Criteria(); $c2->add(AuthorPeer::LAST_NAME, array("Tolstoy", "Dostoevsky", "Bakhtin"), Criteria::IN);
Usted no puede combinar objetos criterios directamente, pewro puede combinar objetos criterio en orden de especificar relaciones lógocas entre clausulas.
// Find all authors with first name "Leo" OR last name of // "Tolstoy", "Dostoevsky", or "Bakhtin" $c = new Criteria(); $cton1 = $c->getNewCriterion(AuthorPeer::FIRST_NAME, "Leo"); $cton2 = $c->getNewCriterion(AuthorPeer::LAST_NAME, array("Tolstoy", "Dostoevsky", "Bakhtin"), Criteria::IN); // combine them $cton1->addOr($cton2); // add to Criteria $c->add($cton1);
En el ejemplo anterior vimos como especificar condiciones simples para una columna (ej. author.FIRST_NAME = "Leo"). Importantemente, especificando multiples condiciones para una columna sencilla, es más complicado porque Propel almacena criterios en una tabla hash (por razones de rendimiento).
Esto está MAL:
$c = new Criteria(); $c->add(AuthorPeer::FIRST_NAME, "Leo%", Criteria::LIKE); $c->add(AuthorPeer::FIRST_NAME, "Leonardo", Criteria::NOT_EQUAL); // second add() just overwrote the LIKE condition already in place!
La forma correcta de hacer esto involucra crearCriterion objetos y usar el método Criterion::addOr() para contar con ellos:
$c = new Criteria(); $criterion = $c->getNewCriterion(AuthorPeer::FIRST_NAME, "Leo%", Criteria::LIKE); $criterion->addOr($c->getNewCriterion(AuthorPeer::FIRST_NAME, "Leonardo", Criteria::NOT_EQUAL)); $c->add($criterion);
El objeto criterio puede hacer más que simplemente controlar las condiciones expresadas en la consulta SQL. El otro aspecto de la consulta que puede ser controlada incluye: el número de registros retornado, caso-sensitio, y el orden de los registros.
// find first 10 authors, alphabetically $c = new Criteria(); $c->setLimit(10); $c->addAscendingOrderByColumn(AuthorPeer::LAST_NAME); // find all authors named "max", case-insensitive $c = new Criteria(); $c->add(AuthorPeer::FIRST_NAME, "max"); $c->setIgnoreCase(true);
Nota: Algunas bases de datos soportan limitar las consultas en SQL (ej. MySQL y PostgreSQL soportan el keyword LIMIT); en esos casos la clase BasePeer usara la limitación nativa, mientras que en otros casos emulando el límite soportado(trayendo el recordset completo pero solo adicionando limites específicos para resultar en un arreglo).
El objeto criterio puede ser manejado alguna vez si desea escribir código que retorne resultados de consulta en columna (mós que objetos instantaneos ). Por ejemplo, si necesita un código más eficiente que pueda retornar una lista de todos los ISBNs en la base de datos, filtrados y especificados sobre un criterio específico:
class BookPeer extends BaseBookPeer { . . . /** * Get just the ISBN numbers for books. * @param Criteria $c Criteria to filter results. * @return array Array of ISBN numbers. */ function getJustISBN(Criteria $c) { $c->clearSelectColumns()->addSelectColumn(self::ISBN); $rs = BasePeer::doSelectRS($c); $isbns = array(); while($rs->next()) { $isbns[] = $rs->get(1); } return $isbns; }
La clase criterio está disponible para construir comodamente consultas usadas, pero esto no pretende ser capaz de construir una consulta. En casos donde necesita rendimiento particularmente en consultas complejas necesitara escribir sus propios estamentos SQL. La forma recomendada para hacer esto es usando sus clases stub. Para estar seguro de que su consulta no va a fallar si las columnas de una tabla son renombradas usted puede usar las constantes Peer::COLUMN_NAME y Peer::TABLENAME .
class BookPeer extends BaseBookPeer { . . . /** * Get just the Books that have not been reviewed. * @return array Book[] */ function getUnreviewedBooks() { $con = Propel::getConnection(DATABASE_NAME); // if not using a driver that supports sub-selects // you must do a cross join (left join w/ NULL) $sql = "SELECT books.* FROM books WHERE ". "NOT EXISTS (SELECT id FROM review WHERE book_id = book.id)"; $stmt = $con->createStatement(); $rs = $stmt->executeQuery($sql, ResultSet::FETCHMODE_NUM); return parent::populateObjects($rs); }
Nota: En el ejemplo anterior es asumido que la columna en su tabla fué definida en el mismo orden como en el esquema de colimnas del archivo XML. Esto sera generalmente en el caso que no haya modificado la tabla. Usted puede usar los criteriose Peer::addSelectColumns y Criteria->getSelectColumns() para quitar esta dependencia.
En nuestro ejemplo no usamos las columnas constantes (para mantenerlo simple), pero usted puede facilmente hacerlo en SQL para evitasr la necesidad de cambiar su SQL si cambia la columna o nombre de la tabla:
$sql = "SELECT b.* FROM ".BookPeer::TABLE_NAME." b WHERE ". "NOT EXISTS (SELECT r.".ReviewPeer::ID." FROM ".ReviewPeer::TABLE_NAME." r ". " WHERE r.".ReviewPeer::BOOK_ID." = b.".BookPeer::ID.")";
Es ciertamente su desición si la flexibilidad de SQL sobre el valor adicional de los retos de legibilidad que introduce.
En algunos casos no querra Peer para poblar todos los objetos y retornarlos en un arreglo. Particularmente, cuando se traen grandes resultados en PHP se puede correr el riesgo de falta de memoria si pregunta para retornar un arreglo de objetos hidratados. Tomarlo alrededor de esta emisión,puede interar a travées del juego de resultados y poblar objetos simples usando el método Entity->hydrate() , disponiendo de ellos cuando usted ha terminado.
// fetch entire list of books (we'll pretend this is huge) $rs = BookPeer::doSelectRS(new Criteria()); while($rs->next()) { // use Creole ResultSet methods to iterate over resultset $book = new Book(); $book->hydrate($rs); // read $book values, save $book, etc. ... }
Desde luego este trabajo si usa criterio de rendimiento SELECT (como un ejemplo) o usar los de SQL. Algo importante que notar es que el resultado es sólo retribuido desde la base de datos en el objeto hidratado cuando sea necesario.