The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Rose::DB::Object::Manager - Fetch multiple Rose::DB::Object-derived objects from the database.

SYNOPSIS

  package Category;

  use Rose::DB::Object;
  our @ISA = qw(Rose::DB::Object);

  __PACKAGE__->meta->table('categories');

  __PACKAGE__->meta->columns
  (
    id          => { type => 'int', primary_key => 1 },
    name        => { type => 'varchar', length => 255 },
    description => { type => 'text' },
  );

  __PACKAGE__->meta->add_unique_key('name');
  __PACKAGE__->meta->initialize;

  ...

  package Product;

  use Rose::DB::Object;
  our @ISA = qw(Rose::DB::Object);

  __PACKAGE__->meta->table('products');

  __PACKAGE__->meta->columns
  (
    id          => { type => 'int', primary_key => 1 },
    name        => { type => 'varchar', length => 255 },
    description => { type => 'text' },
    category_id => { type => 'int' },

    status => 
    {
      type      => 'varchar', 
      check_in  => [ 'active', 'inactive' ],
      default   => 'inactive',
    },

    start_date  => { type => 'datetime' },
    end_date    => { type => 'datetime' },

    date_created     => { type => 'timestamp', default => 'now' },  
    last_modified    => { type => 'timestamp', default => 'now' },
  );

  __PACKAGE__->meta->add_unique_key('name');

  __PACKAGE__->meta->foreign_keys
  (
    category =>
    {
      class       => 'Category',
      key_columns =>
      {
        category_id => 'id',
      }
    },
  );

  __PACKAGE__->meta->initialize;

  ...

  package Product::Manager;

  use Rose::DB::Object::Manager;
  our @ISA = qw(Rose::DB::Object::Manager);

  sub get_products
  {
    my $class = shift;

    Rose::DB::Object::Manager->get_objects(
      object_class => 'Product', @_)
  }

  sub get_products_iterator
  {
    my $class = shift;

    Rose::DB::Object::Manager->get_objects_iterator(
      object_class => 'Product', @_)
  }

  sub get_products_count
  {
    my $class = shift;

    Rose::DB::Object::Manager->get_objects_count(
      object_class => 'Product', @_)
  }

  ...

  #
  # Get a reference to an array of objects
  #

  $products = 
    Product::Manager->get_products
    (
      query =>
      [
        category_id => [ 5, 7, 22 ],
        status      => 'active',
        start_date  => { lt => '15/12/2005 6:30 p.m.' },
        name        => { like => [ '%foo%', '%bar%' ] },
      ],
      sort_by => 'category_id, start_date DESC',
      limit   => 100
    ) 
    or die Product::Manager->error;

  foreach my $product (@$products)
  {
    print $product->id, ' ', $product->name, "\n";
  }

  #
  # Get objects iterator
  #

  $iterator = 
    Product::Manager->get_products_iterator
    (
      query =>
      [
        category_id => [ 5, 7, 22 ],
        status      => 'active',
        start_date  => { lt => '15/12/2005 6:30 p.m.' },
        name        => { like => [ '%foo%', '%bar%' ] },
      ],
      sort_by => 'category_id, start_date DESC',
      limit   => 100
    )
    or die Product::Manager->error;

  while($product = $iterator->next)
  {
    print $product->id, ' ', $product->name, "\n";
  }

  print $iterator->total;

  #
  # Get objects count
  #

  $count =
    Product::Manager->get_products_count
    (
      query =>
      [
        category_id => [ 5, 7, 22 ],
        status      => 'active',
        start_date  => { lt => '15/12/2005 6:30 p.m.' },
        name        => { like => [ '%foo%', '%bar%' ] },
      ],
      limit   => 100
    ); 

   die Product::Manager->error  unless(defined $count);

  print $count; # or Product::Manager->total()

  #
  # Get objects and sub-objects in a single query
  #

  $products = 
    Product::Manager->get_products
    (
      with_objects => [ 'category' ],
      query =>
      [
        category_id => [ 5, 7, 22 ],
        status      => 'active',
        start_date  => { lt => '15/12/2005 6:30 p.m.' },
        name        => { like => [ '%foo%', '%bar%' ] },
      ],
      sort_by => 'category_id, start_date DESC',
      limit   => 100
    )
    or die Product::Manager->error;

  foreach my $product (@$products)
  {
    print $product->name, ': ', $product->category->name, "\n";
  }

DESCRIPTION

Rose::DB::Object::Manager is a base class for classes that select rows from tables fronted by Rose::DB::Object-derived classes. Each row in the table(s) queried is converted into the equivalent Rose::DB::Object-derived object.

Class methods are provided for fetching objects all at once, one at a time through the use of an iterator, or just getting the object count. Subclasses are expected to create syntactically pleasing wrappers for Rose::DB::Object::Manager class methods. A very minimal example is shown in the synopsis above.

CLASS METHODS

error

Returns the text message associated with the last error, or false if there was no error.

get_objects [PARAMS]

Get Rose::DB::Object-derived objects based on PARAMS, where PARAMS are name/value pairs. Returns a reference to a (possibly empty) array in scalar context, a list of objects in list context, or undef if there was an error.

Note that naively calling this method in list context may result in a list containing a single undef element if there was an error. Example:

    # If there is an error, you'll get: @objects = (undef)
    @objects = Rose::DB::Object::Manager->get_objects(...);

If you want to avoid this, feel free to change the behavior your wrapper method, or just call it in scalar context (which is more efficient anyway for long lists of objects).

Valid parameters are:

db DB

A Rose::DB-derived object used to access the database. If omitted, one will be created by calling the init_db() object method of the object_class.

object_args HASHREF

A reference to a hash of name/value pairs to be passed to the constructor of each object_class object fetched, in addition to the values from the database.

object_class CLASS

The class name of the Rose::DB::Object-derived objects to be fetched. This parameter is required; a fatal error will occur if it is omitted.

share_db BOOL

If true, db will be passed to each Rose::DB::Object-derived object when it is constructed. Defaults to true.

with_object OBJECTS

Also fetch sub-objects associated with foreign keys in the primary table, where OBJECTS is a reference to an array of foreign key names, as defined by the Rose::DB::Object::Metadata object for object_class.

Another table will be added to the query for each foreign key listed. The "join" clauses will be added automatically based on the foreign key definitions. Note that (obviously) each foreign key table has to have a Rose::DB::Object-derived class fronting it. See the synopsis for a simple example.

Any valid Rose::DB::Object::QueryBuilder::build_select() parameter

Any parameter that can be passed to the build_select() function of the Rose::DB::Object::QueryBuilder module can also be passed to this method, which will then pass them on to build_select() to create the SQL query string used to fetch the objects.

get_objects_count [PARAMS]

Accepts the same arguments as get_objects(), but just returns the number of rows that would have been fetched, or undef if there was an error.

get_objects_iterator [PARAMS]

Accepts the same arguments as get_objects(), but return a Rose::DB::Objects::Iterator object which can be used to fetch the objects one at a time, or undef if there was an error.

get_objects_sql [PARAMS]

Accepts the same arguments as get_objects(), but return the SQL query string that would have been used to fetch the objects (in scalar context), or the SQL query string and a reference to an array of bind values (in list context).

AUTHOR

John C. Siracusa (siracusa@mindspring.com)

COPYRIGHT

Copyright (c) 2005 by John C. Siracusa. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.