Skip site navigation (1)Skip section navigation (2)

FreeBSD Manual Pages

  
 
  

home | help
Oryx::Class(3)	      User Contributed Perl Documentation	Oryx::Class(3)

NAME
       Oryx::Class - abstract base class for Oryx classes

SYNOPSIS
	# define a persistent class
	package	CMS::Page;
	use base qw(Oryx::Class);

	# ... class meta-data here (see	DEFINING CLASS META-DATA below)	...

	1;

	#===========================================================================
	# use a	persistent class
	use CMS::Page;

	$page =	CMS::Page->create({title => 'Life in the Metaverse'});
	$page =	CMS::Page->retrieve($id);

	$page->update;
	$page->delete;

	@pages = CMS::Page->search({author => 'Richard Hun%'}, \@order,	$limit,	$offset);

	#===========================================================================
	# commit your changes
	$page->dbh->commit; # or simply	...
	$page->commit;

	#===========================================================================
	# attribute mutator
	$page->title('The Metamanic Mechanic');
	$tite =	$page->title;

	#===========================================================================
	# reference association	mutator
	$template_obj =	$page->template;
	$page->template( $template_obj );

	#===========================================================================
	# array	association accessor
	$page->paragraphs->[0] = $intro_para;
	$paragraph = $page->paragraphs->[42];

	#===========================================================================
	# array	association operators
	$concl = pop   @{$page->paragraphs};
	$intro = shift @{$page->paragraphs};
	push	@{$page->paragraphs}, $concl;
	unshift	@{$page->paragraphs}, $new_intro;
	splice	@{$page->paragraphs}, 1, 4, ($summary);

	#===========================================================================
	# hash association accessor
	$image_obj = $page->images->{logo};
	$page->images->{mug_shot} = $my_ugly_mug;
	@keys	= keys	 %{$page->images};
	@values	= values %{$page->images};

	#===========================================================================
	# support for Class::Observable
	Page->add_observer(sub {
	    my ($item, $action)	= @_;
	    #...
	});
	$page->add_observer(...); # instance

DESCRIPTION
       Abstract	base class for Oryx persistent classes.

ABSTRACT METHODS
       These methods are overridden by the implementing	Class class, i.e.
       Oryx::DBI::Class	or Oryx::DBM::Class, for example, but the interfaces
       stay the	same, so they are documented here.

       create( \%proto )
	   creates a persistent	object using "\%proto" to set up the initial
	   state.

       retrieve( $oid )
	   retrieves an	object from storage by its object id

       update
	   updates storage to persist and reflect changes in the object

       delete
	   deletes the object from storage

       search( \%param,	[ \@order, $limit, $offset ] )
	   searches for	objects	with fields matching "\%param".	SQL style "%"
	   wildcards are supported. "\@order", $limit and $offset are
	   optional. "\@order" is a list of columns which are used to sort the
	   results, $limit is an integer which is used to limit	the number of
	   results, and	$offset	is used	to exclude the first results up	to
	   that	number.	These last two arguments are useful for	paging through
	   search results.

       commit
	   commits the transaction if your database supports it	and AutoCommit
	   is disabled,	then you must do this.

   Observers
       Oryx::Class objects now unherit from Class::Observable thereby
       implementing a publish/subscribe	system similar to triggers.

       The signals are named according to the 6	interface methods prefixed
       with before_* and after_*, so the following signals are sent:

       before_create
	   Handler is passed a hashref as argument with	fields:	"param", the
	   search parameters, and "query", the SQL::Abstract where clause

       after_create
	   Handler is passed a hashref as argument with	fields:	"param", the
	   search parameters, and "proto", the hashref which will be blessed
	   into	an instance of this class (during 'construct')

       before_retrieve
	   Handler is passed a hashref as argument with	fields:	"id", the id
	   of the object to fetch, and "query",	the SQL::Abstract where	clause

       after_retrieve
	   Handler is passed a hashref as argument with	fields:	"proto", the
	   hashref which will be blessed into an instance of this class
	   (during 'construct')

       before_update
	   Handler is passed a hashref as argument with	fields:	"query", the
	   SQL::Abstract where clause.

       after_update
	   Handler takes no arguments.

       before_delete
	   Handler is passed a hashref as argument with	fields:	"query", the
	   SQL::Abstract where clause.

       after_delete
	   Handler takes no arguments.

       before_search
	   Handler is passed a hashref as argument with	fields:	"query", the
	   SQL::Abstract where clause, "param",	the search parameters, the
	   "order" and "limit" parameters.

       after_search
	   Handler is passed a hashref as argument with	fields:	"query", the
	   SQL::Abstract where clause, "param",	the search parameters, the
	   "order" and "limit" parameters, and "objects", an arrayref of
	   objects returned by the search.

       before_construct
	   Handler is passed a hashref as argument with	fields:	"proto", the
	   hashref which will be blessed into an instance of this class.

       after_construct
	   Handler is passed a hashref as argument with	fields:	"object", the
	   persistent object.

METHODS
       These methods are concrete.

       init
	   Initialises the class data (see Class::Data::Inheritable)

       import
	   Does	the work of constructing the class' meta-instances
	   (Oryx::Attribute, Oryx::Association and Oryx::Parent	instances)
	   from	the $shema class variable or defined in	the DATA section of
	   the module if you have XML::DOM::Lite installed.

       meta
	   Simple accessor to the class	meta data.

       construct( $class, $proto )
	   This	is typically called from within	the "create" and "retrieve"
	   methods of the implementation class (Oryx::DBI::Class or
	   <Oryx::DBM::Class, for example) which then blesses $proto into
	   $class and then allows each class meta-instance to frobnicate it in
	   turn	if they	have any need to, before handing the instance to you.

       addAttribute( $meta )
	   Creates an Attribute	meta-instance and associates it	with the
	   class.

       addAssociation( $meta )
	   Creates an Association meta-instance	and associates it with the
	   class.

       addMethod( $meta	)
	   Does	nothing	at the moment as I cannot decide what such a method
	   would be used for exactly.

       addParent( $super )
	   Creates a Parent meta-instance and associates it with the class.

       id  Returns the object id.

       is_abstract
	   True	if the class does not define any attributes. This is used for
	   creating a special table for	sharing	sequences accross subclasses
	   and for instantiating the correct subclass instance if "retrieve()"
	   is called on	an abstract class.

       table
	   Returns the table name for this class.

       name([ $name ])
	   Get or set the "name" meta-attribute	for the	class.

       members
	   Return a list of all	meta-instances (Attribute, Association,	Method
	   and Parent instances).

       commit
	   calls $self->dbh->commit to commit the trasaction

       schema
	   shortcut for	$self->storage->schema.	Read only.

       remove_from_cache
	   Object method to remove it from the memory cache.

CREATING PERSISTENT CLASSES
       Creating	persistent classes is simple, there is no need to create any
       database	tables by hand as the DB schema	is deployed automatically as
       needed (see "AUTOMATIC TABLE CREATION" below).

       The following three steps illustrate how	this is	done:

       Inherit from Oryx::Class	or subclass thereof (see "INHERITANCE" below):
	    package CMS::Page;
	    use	base qw(Oryx::Class);

       Define meta-data	(see "DEFINING CLASS META-DATA"	below):
	    our	$schema	= {
		attributes => [{
		    name  => 'title',
		    type  => 'String',
		},{
		    name  => 'author',
		    type  => 'String',
		},{
		    name  => 'number',
		    type  => 'Integer',
		}],
		associations =>	[{
		    role  => 'paragraphs',
		    class => 'CMS::Paragraph',
		    type  => 'Array',
		},{
		    role  => 'template',
		    class => 'CMS::Template',
		    type  => 'Reference',
		}],
	    };

	    1;

       Connect to storage (see "CONNECTING TO STORAGE" below):
	   ...far away in another piece	of code...

	    use	CMS::Page;

	    use	Oryx;
	    Oryx->connect(["dbi:Pg:dbname=cms",	$usname, $passwd]);

	    ...

       Now we're ready to start	using persistent CMS::Page objects (and
       friends).

CREATING AND USING OBJECTS
       Oryx::Class defines a create method (see	Oryx::Class for	more) which
       takes a hash reference as a constructor for setting up the object's
       initial state:

	    use	CMS::Page;
	    my $page = CMS::Schema::Page->create({
		title  => 'Meta	Model Mania',
		author => 'Sam Vilain',
	    });

       Once an object has been instatiated, attribute mutators can be used to
       get and set attributes on the object (see "ATTRIBUTES" below):

	    $page->number(42);

       Associations are	similar	except that we associate one object with
       another (see "ASSOCIATIONS" below), so we create	an instance of the
       target class:

	    my $paragraph1 = CMS::Paragraph->create({
		content	=> $some_block_of_text,
	    });

       And then, because the association mutator returns a reference to	a tied
       object (an ARRAY	in this	case), we can:

	    $page->paragraphs->[0] = $paragraph1;

       Then update your	object when done:

	    $page->update;

       Or if you no longer need	it:

	    $page->delete;

       Finally,	commit your changes:

	    $page->commit;

DEFINING CLASS META-DATA
       Three ways of defining meta data	for your persistent classes are
       supported as follows:

       Tangram style using a $schema class variable:
	    package CMS::Page;
	    use	base qw(Oryx::Class);

	    our	$schema	= {
		attributes => [{
		    name  => 'title',
		    type  => 'String',
		},{
		    name  => 'author',
		    type  => 'String',
		}],
		associations =>	[{
		    role  => 'paragraphs',
		    class => 'CMS::Paragraph',
		    type  => 'Array',
		},{
		    role  => 'template',
		    class => 'CMS::Template',
		    type  => 'Reference',
		}],
	    };

	    1;

       Class::DBI style	adding members dynamically:
	    package CMS::Paragraph;
	    use	base qw(Oryx::Class);

	    __PACKAGE__->addAttribute({
		name  => 'content',
		type  => 'Text',
	    });

	    __PACKAGE__->addAttribute({
		name  => 'formatted',
		type  => 'Boolean',
	    });

	    __PACKAGE__->addAssociation({
		role  => 'images',
		class => 'CMS::Image',
		type  => 'Hash',
	    });

	    1;

       If you have XML::DOM::Lite, put it in the DATA section:
	    package CMS::Image;
	    use	base qw(Oryx::Class);

	    1;
	    __DATA__
	    <Class>
	      <Attribute name="alt_text" type="String" />
	      <Attribute name="path_to_file" type="String" />
	    </Class>

AUTOMATIC TABLE	CREATION
       With Oryx, you never need to write a single line	of SQL although	you
       can if you want to in exactly the same way as you would when using
       Class::DBI (actually it's a ImA::DBI feature). Tables are named
       sensibly	as pluralised versions of the class name with link table names
       equally intuitive.

   Enabling auto_deploy	for all	classes
       To enable automatic table creation, you need to do the following	near
       the top of your application before you use any of your classes:

	use Oryx ( auto_deploy => 1 );

       Because the check to see	if a table exists is made once when the	class
       is first	use'ed,	the performance	penalty	for this is minimal in long
       running process environments such as mod	perl. Otherwise	when running
       in an environment where your code is recompiled each time the program
       is run, or you would like more control, you can leave auto_deploy
       turned off at the top level (which it is	by default) and	simply turn it
       on for each new class that you're adding	to the schema as this method
       is inherited.

ATTRIBUTES
       Attributes are declared as having a name	and a type and as such are
       simply tied Oryx::Value derivatives (see	Oryx::Value for	details) which
       are generally associated	with a field (or column) in the	underlying
       database, and which have	mutators which are automatically created in
       the class for getting and setting these values.

       Certain attributes may also be declared with additional properties as
       relevant, for instance, attributes declared as type => "Float" support
       a precision property which describes the	valid number of	decimal
       places.

   Attribute Value Input Checking
       Input is	checked	when assigning values to attributes and	return values
       are cast	to the correct type using a combination	of regular
       expressions, the	Data::Types module, YAML or Class::Date	where
       relevant. Where additional properties are set such as size or
       precision, these	are checked also and your program will croak if	types
       mismatch	or overflow.

   Supported Attribute Value Types
       Several basic value data	types are supported:

       String
	   Varying character type (VARCHAR for most RDBMS). Input is checked
	   using Data::Types::is_string	and if the attribute is	declared with
	   a size property, the	length is also checked.

       Text
	   Corresponds to a SQL	TEXT type; type	checking is done using
	   Data::Types::is_string, but no length checking is performed.

       Boolean
	   Corresponds to a a SQL TINYINT or INT type and is checked for the
	   values 0 or 1.

       Binary
	   No checking is done here, but a BLOB	or BYTEA or equivalent column
	   type	is created when	the class is deployed.

       Complex
	   This	can be anything	that can be (de)serialized using YAML and is
	   stored internally in	the DB in a column with	a TEXT type.

       DateTime
	   Uses	Class::Date objects. You can pass either a Class::Date
	   instance to the mutator as follows:

	    use	Class::Date qw(date);
	    $page->date_created( date(localtime) );

	   or any value	which is valid input to	the Class::Date::new
	   constructor this includes ARRAY refs	etc. (see Class::Date for
	   details).

	   Attributes declared as DateTime types additionaly support a format
	   property which is used to set Class::Date::DATE_FORMAT for date
	   formatting.

       Float
	   Floating point number checked using Data::Types::is_float. Return
	   value is done with Data::Types::to_float and	precision checks are
	   made	if the attribute is declared with such.

       Integer
	   Corresponds to INT or INTEGER SQL type. Input checks	are performed
	   using Data::Types::is_int.

       Oid This	is also	an integer type, but with the distinction that when a
	   class is deployed to	an RDBMS the column is constrained as a
	   PRIMARY KEY.

ASSOCIATIONS
       Oryx implements the three most common ways in which associations
       between classes can be achieved natively	with Perl. An object can be
       associated with another by simple reference, or we can use either
       ordered (ARRAY),	or keyed (HASH)	associations - so a field in one
       object (usually a blessed HASH reference) can be	an ARRAY reference,
       for example, which could	be filled with references to other objects
       (which themselves are persistent).

       In RDBMS	terms, this sort of to-many ordered relationship requires a
       link table with a column	holding	ordering information, which is exactly
       what happens under the hood, but	Oryx makes it transparent for you
       using Perl's tie	mechanism while	managing the link table	automagically.

       Furthermore one can also	have to-many ordered (Array) or	to-many	keyed
       (Hash) associations which are mixed - in	other words one	class can have
       an ARRAY	(or HASH) reference which can contain instances	of different
       classes (see "ABSTRACT CLASSES" below).

   Reference
       getting :

	my $a_template = $page->template;

       setting :

	$page->template($another_template);

   Array
       getting :

	my $para42 = $page->paragraphs->[42];

       setting :

	$page->paragraph->[0] =	$intro_para;

       as well as all the usual	push, pop, shift, unshift and splice.

   Hash
       getting :

	my $image_obj =	$page->images->{logo};

       setting :

	$page->images->{mug_shot} = $my_ugly_mug;

RETRIEVING AND SEARCHING FOR OBJECTS
       Retrieval is simple, just pass in the id	(primary key) :

	my $page = CMS::Page->retrieve($page_id);

       Searching uses 'LIKE' (assuming an RDBMS	storage) :

	my @pages = CMS::Page->search({	author => '%Hundt%'});

       NOTE : Searches don't search through superclass fields yet...

INHERITANCE
       Inheritance works as you	would expect.

       So if we	have the following :

	package	CMS::Section;
	use base qw(Oryx::Class);

	# ... schema definition	here ...

	1;

	package	CMS::Paragraph;
	use base qw(CMS::Section);

	# ... schema definition	here ...

	1;

       You get exactly what you	would normally get in Perl, that is :

	UNIVERSAL::isa('CMS::Paragraph', 'Oryx::Class')

       holds true and attributes and associations defined in CMS::Section are
       available to CMS::Paragraph instances. So any class which has
       persistant class	as an ancestor,	can be treated and persisted in	the
       same way	as the ancestor. However, it is	important to note that it gets
       its own table in	the database.

       For multiple persistent base classes :

	package	Orange;
	use base qw(Food Fruit);

       As long as Food and Fruit are Oryx::Class derivatives, the Force	That
       Into the	Database Drives	the Object will	make sure the proverbial Right
       Thing is	Done.

       Oryx uses a multiple table inheritance model (as	opposed	to putting all
       the instances for classes in an inheritance chain into the same table),
       each subclass instance has a corresponding superclass instance for each
       superclass (assuming said superclass is a derivative of Oryx::Class),
       so that attributes which	exists in the superclass are stored (as	a row)
       in the superclass' table, and are therefore fully fledged instances of
       the superclass.

       You can access these superclass instances with the PARENT method	as
       follows:

	my $parent_section_instance = $paragraph->PARENT('CMS::Section');

       and then	use this instance normally.

       Updates and deletes cascade up the inheritance chain, as	you'd expect.

ABSTRACT CLASSES
       Abstract	classes	to Oryx	are simply classes which do not	define any
       attributes, but may have	associations. The effect is automatic.

       Abstract	classes	behave slightly	differently to concrete	classes	(which
       define attributes) in that if you retrieve an instance of an abstract
       class (by id or by accessing a member of	an association), you get an
       instance	of the sub class (the one which	created	the row	in the
       abstract	class's	table).

       This is particularly useful where you have an Array or Hash association
       between two classes and need to mix instances of	different types	in
       that association. As long as all	the members of the array (or hash)
       inherit from the	same abstract class, accessing them produces the
       expected	result.

       Consider	the following case :

			   <ABSTRACT>
	+------+  <Array> +----------+
	| Page |----------| Fragment |
	+------+  frags	  +----------+
	|______|	  |__________|
			       /_\
				|
		      +---------+------+
		      |		       |
		+-----------+	   +-------+
		| Paragraph |	   | Image |
		+-----------+	   +-------+
		|___________|	   |_______|

       Here the	Paragraph and Image both inherit from the abstract Fragment
       class. When the frags Array association is accessed it may contain a
       mixture of both Paragraph and Image instances.

       Thus you	can say:

	$my_para = Paragraph->create({ ... });
	$my_page->frags->[42] =	$my_para;

	$my_img	= Image->create({ ... });
	$my_page->frags->[69] =	$my_img;

       pretty neat huh?

OBJECT CACHING
       In the interest of consistency, objects are cached and are unique in
       memory. Therefore, if you retrieve an object more than once, each
       subsequent retrieve until the reference count on	it has dropped to zero
       and has been eaten by the garbage collector, will return	a reference to
       the same	object.

       This has	a performance gain in certain situations too.

AUTHOR
       Richard Hundt <richard NO SPAM AT protea-systems.com>

LICENCE
       This library is free software and may be	used under the same terms as
       Perl itself.

POD ERRORS
       Hey! The	above document had some	coding errors, which are explained
       below:

       Around line 579:
	   You forgot a	'=back'	before '=head1'

perl v5.32.1			  2006-06-18			Oryx::Class(3)

NAME | SYNOPSIS | DESCRIPTION | ABSTRACT METHODS | METHODS | CREATING PERSISTENT CLASSES | CREATING AND USING OBJECTS | DEFINING CLASS META-DATA | AUTOMATIC TABLE CREATION | ATTRIBUTES | ASSOCIATIONS | RETRIEVING AND SEARCHING FOR OBJECTS | INHERITANCE | ABSTRACT CLASSES | OBJECT CACHING | AUTHOR | LICENCE | POD ERRORS

Want to link to this manual page? Use this URL:
<https://www.freebsd.org/cgi/man.cgi?query=Oryx::Class&sektion=3&manpath=FreeBSD+13.0-RELEASE+and+Ports>

home | help