Quantcast
Channel: Show me the code » ArrayCollection
Viewing all articles
Browse latest Browse all 2

Revisando la clase ArrayCollection de Doctrine – Parte 2

$
0
0

En la parte 1 hicimos un repaso de algunos de los métodos de ArrayCollection, como ya dijimos esta parte se centrará sólo en el método matching, este método permite hacer consultas sobre la propia ArrayCollection pasándole un objeto Criteria pudiendo filtrar y ordenar los elementos que contiene devolviendo un nuevo ArrayCollection.

Vamos a usar el mismo escenario que en la primera parte del artículo y añadimos un método getAverage a Person:

public function getAverage()
{
    $average = 0;
    foreach ($this->grades as $grade) {
        $average += $grade->mark;
    }

    return $average / count($this->grades);
}

Criteria

Esta clase se encuentra dentro de \Doctrine\Common\Collections y se utiliza para filtrar colecciones que implementan la interfaz Selectable que también está en el mismo namespace.

Para construir un objeto Criteria la forma más sencilla es mediante su método estático create y después ir llamando a los métodos de Criteria que queramos.

Los métodos disponibles para ir añadiendo filtros tienen el mismo nombre que los de QueryBuilder:

  • where, andWhere, orWhere: Estos métodos se utilizan para añadir condiciones, reciben una Expresion como parámetro.
  • orderBy: Recibe un array con los campos por los que ordenar y la dirección en la que lo debe hacer.
  • setFirstResult: Este método recibe un entero e indica la posición del primero resultado que debe devolver.
  • setMaxResults: Este método indica el número máximo de resultados que devolverá.

Expresion

Los métodos where, andWhere y orWhere reciben un objeto que implemente la interfaz Expresion, la forma más sencilla de crear un objeto de este tipo es mediante ExpresionBuilder de Collection.

Selectable

Es la interfaz que contiene el método matching, como ya hemos comentado se encuentra en \Doctrine\Common\Collections\Selectable , en este artículo estamos viendo ArrayCollection que implementa esta interfaz, pero no es la única clase, también la implementan PersistCollection y EntityRepository, lo que significa que los mismos objetos Criteria podríamos usarlos si nuestros modelos estuvieran en una base de datos (a excepción de si usamos en el Criteria métodos de los objetos, en los ejemplo se verá).

Ejemplos

Todo esto se ve mejor con ejemplos. Para imprimir los resultados vamos a modificar la función printPerson para que acepte un segundo parámetro que será una Closure, esto nos permitirá decidir cómo se va a representar cada persona:

function printPeople($people, \Closure $closure = null) {
    if (null === $closure) {
        $closure = function(Person $person) {
            echo sprintf("%s\n", $person->name);
        };
    }

    foreach ($people as $person) {
        $closure($person);
    }
}

Añadiremos también el use de la clase Criteria:

use Doctrine\Common\Collections\Criteria;

Obtener las personas que se llamen Bob

Empezamos por un ejemplo sencillo:

$criteria = Criteria::create()
    ->where(Criteria::expr()->eq("name", "Bob"))
;

printPeople($people->matching($criteria)); // Bob

Obtener las personas nacidas después de 1973 ordenadas ascendentemente por edad

$printPersonWithBirthday = function (Person $person) {
    echo sprintf("%-5s -> %s\n", $person->name, $person->birthday->format('d-m-Y'));
};

$criteria = Criteria::create()
    ->where(Criteria::expr()->gte("birthday", new \DateTime("1973-1-1")))
    ->orderBy(array('birthday' => 'ASC'))
;

printPeople($people->matching($criteria), $printPersonWithBirthday);
// Alice -> 11-10-1975
// Penny -> 18-12-1976
// Peter -> 10-10-1980

Obtener las personas ordenadas por media

Esto es muy interesante, porque estamos ordenando por el resultado de un método de la clase, no sólo por los atributos.

$printPersonWithAverage = function (Person $person) {
    echo sprintf("%-5s -> %.2f\n", $person->name, $person->getAverage());
};

$criteria = Criteria::create()
    ->orderBy(array('average' => 'ASC'))
;

printPeople($people->matching($criteria), $printPersonWithAverage);
// Peter -> 3.40
// Alice -> 6.67
// Penny -> 6.77
// Bob   -> 9.33

Hay que tener en cuenta la documentación del método getObjectFieldValue de la clase  ClosureExpressionVisitor que es la que se encarga de obtener el valor de un campo dado un objeto:

/**
     * Access the field of a given object. This field has to be public directly
     * or indirectly (through an accessor get* or a magic method, __get, __call).
     *
     * is*() is not supported.
     *
     * @return mixed
     */
    static public function getObjectFieldValue($object, $field)
    {
        // ...

Además de esto hay que también tener en cuenta que este Criteria no podremos usarlo si vamos a llamar al método matching de PersistCollection o EntityRepository, ya que en ese caso lo que hace es pasar el Criteria a SQL.

Obtener la tercera persona del resultado de ordenar por media

$criteria = Criteria::create()
    ->orderBy(array('average' => 'ASC'))
    ->setFirstResult(2) // Empieza en 0
    ->setMaxResults(1)
;

printPeople($people->matching($criteria), $printPersonWithAverage);
// Penny -> 6.77

Obtener las personas con media mayor que 6 y que hayan nacido antes de 1976 o se llamen Penny

No tiene mucho sentido la consulta, pero sirve para ver las posibilidades de Criteria:

$printPersonWithAverageAndBirthday = function (Person $person) {
    echo sprintf("%-5s -> %5.2f -> %s\n",
        $person->name, $person->getAverage(),
        $person->birthday->format('d-m-Y')
    );
};

$criteria = Criteria::create()
    ->where(Criteria::expr()->gt("average", 6))
    ->andWhere(Criteria::expr()->orX(
        Criteria::expr()->lte("birthday", new \DateTime("1976-1-1")),
        Criteria::expr()->eq("name", "Penny")
    ))
    ->orderBy(array('average' => 'ASC'))
;

printPeople($people->matching($criteria), $printPersonWithAverageAndBirthday);
// Alice ->  6.67 -> 11-10-1975
// Penny ->  6.77 -> 18-12-1976
// Bob   ->  9.33 -> 20-01-1972

Y con esto acabamos de ver la clase ArrayCollection y las posibilidades que ofrece, en próximos posts veremos otras clases útiles que hay en Symfony2 o su ecosistema.

 


Viewing all articles
Browse latest Browse all 2

Latest Images

Trending Articles





Latest Images