|
NAMEOryx::Manual::Guts - Oryx internals documentation for developersDESCRIPTIONThis document is intended for hackers to grant an insight into how Oryx's pieces fit together and is intended for anyone wishing to extend Oryx... or for anybody who just wants to know how the sausage is made.NOMENCLATUREOryx implements an object oriented meta-model, that is, information about persistent classes is carried around, usually as instances of meta classes, by the persistent classes themselves, instances of which are your persistent objects.This makes it difficult to describe a meta-model which has components, or meta-components, which themselves are really just ordinary Perl objects. Thus we could end up talking about instances of the Oryx::Value::String class being associated with an instance of the Oryx::Attribute class when mentioning how they relate to our persistant objects - which are themselves Oryx::Class derived instances. All of which can be tricky for the brain (well mine, at any rate) to keep a grip on. So to make this slightly more coherent, we'll stick to the following nomenclature throughout this document:
ABSTRACT METAMODELOryx implements an abstract metamodel which can be specialised to work with any storage backend. At the moment relational databases and a fast, pure Perl file-based database are supported, but the abstraction of the metamodel should allow one to add support for any other storage backend without changing how persistent classes are defined.This abstract metamodel consist of four base meta-types namely: Oryx::Attribute, Oryx::Association, Oryx::Parent and Oryx::Class. Oryx::Class can be regarded as a special case meta-type in that it is the level at which our meta-model joins Perl's own built-in object model. When a persistent class inherits from Oryx::Class, it doesn't have the implementation to be persisted in any given storage back-end, that is, the methods for creating, retrieving, updating, etc. are just stubs and will raise an exception if invoked. During a call to "Oryx->connect(...)", however, Oryx looks at the connection arguments and determines which concrete meta-types will be used thereafter. This is done by simply pushing either Class::DBI::Class or Class::DBM::Class onto @Oryx::Class::ISA, thereby effectively doing dynamic, run-time inheritance. So for example, if we say: use Oryx; use CMS::Page; UNIVERSAL::isa(CMS::Page, 'Oryx::Class') # true UNIVERSAL::isa(CMS::Page, 'Oryx::DBI::Class') # false Oryx->connect('dbi:Pg:dbnam=foo', $user, $pass); UNIVERSAL::isa(CMS::Page, 'Oryx::DBI::Class') # true whereas if we: Oryx->connect('dbm:Deep:datapath=/path/to/data'); UNIVERSAL::isa(CMS::Page, 'Oryx::DBM::Class') # true From this point onwards, the correct concrete meta-types are used and constructed from the class metadata defined in the class' $schema. This happens in the class's "import" hook, but is usually deferred to happen at run-time (instead of compile-time); so in the first case above this would be Oryx::DBI::Association, Oryx::DBI::Attribute and Oryx::DBI::Parent. The actual "connect()" call is then delegated to the appropriate storage class: Oryx::DBI or Oryx::DBM, as the case may be. These storage classes handle low level connection, pinging the DB and caching database handles (indirectly via Ima::DBI) where applicable. Each Oryx::Class derivative (or subclass) has any number of instances of the concrete meta-types associated with it. At the Oryx::Class level, this is done with inheritable class data using Class::Data::Inheritable (of all things!) for creating accessors (or "named closures"), typically by inspecting the $schema class variable, or, in the case of Oryx::Parent meta-instances, by inspecting the class' @ISA array. From our class, we can access the meta-instances as folows: @attribs = values %{CMS::Page->attributes}; # all the attributes $assoc = CMS::Page->associations->{paragraphs}; # single association Oryx::Parent meta-instances are stored in an array ref, so this access looks a little different: @parents = @{CMS::Page->parents}; # all parents Alternatively you can get all the meta-instances as an array using the convenient "members" method: @members = CMS::Page->members; This will then contain a list of all the meta-instances describing our "CMS::Page" class. NOTE: The meta-instances are constructed using "import", so they'll be there after you "use" the class, but not if you just "require" it. meta-types
These all inherit from a common base meta-type: Oryx::MetaClass and they all implement a common interface described therein. COMMON INTERFACEThe overall interface of each Oryx object defines six main methods. At the top level, each of these methods may perform some action as well as delegating additional actions out to each member class (see "meta-types"). Thus, the implementation of each of each of these methods in the Oryx class looks something like:sub create { # take some action to create the record $_->create(...) foreach $class->members; # finish up, store the data, return }
Each delegated class has a chance to modify the object as necessary during each of these calls. CLASSESOryx has a few special unique parts that are used to define the rest. The most visible of these parts are the Oryx and Oryx::Class objects.Each of the following headings describe each group of classes used by Oryx. FRONT-END CLASSESThere are two classes that any Oryx user must be familiar with. The rest of the classes in the system work through the meta-model of Oryx and are not necessarily exposed directly to the user.In order to establish a connection to storage, the user uses methods of the Oryx class. Then, to define a class, the user typically extends Oryx::Class to automatically configure the class from a meta-model representation. The third front-end class is Oryx::Schema, which can be subclassed by the user to change groups of classes in the same storage schema.
META-MODEL IMPLEMENTATION CLASSESThese objects are used under the hood to perform the basic row-level operations for a persistent Oryx class. All Oryx classes ultimately inherit functionality from Oryx::MetaClass. All will inherit functionality from either Oryx::DBM::Class or Oryx::DBI::Class depending on the storage type.
META-MODEL MEMBER CLASSESThe member classes in the meta-model create additional functionality within a database row. These classes are associated with an object as configured by the schema of the class.
STORAGE CLASSESCurrently, Oryx supports to types of backing stores via DBI or DBM::Deep. These classes are responsible for making the connections to those objects when the "connect()" method of Oryx is called. These are also responsible for making the work of deploying objects and schemas happen.
STORAGE UTILITY CLASSESThese are helpers used by Oryx::DBI and Oryx::DBM to do much of the grunt work over the storage connection.
DBI STORAGE META-MODEL IMPLEMENTATION CLASSESThese classes all implement the specifics of the "META-MODEL MEMBER CLASSES". These simply implement the functionality for the Oryx::DBI storage object.
DBM STORAGE META-MODEL IMPLEMENTATION CLASSESThese classes all implement the specifics of the "META-MODEL MEMBER CLASSES". These simply implement the functionality for the Oryx::DBM storage object.
ATTRIBUTE VALUE CLASSESThese are used by Oryx::Attribute and Oryx::Association members to choose how to validate, load, and store information in each for each column. Each of these is a scalar tie object.Each of these defined "TIESCALAR()", "FETCH()", and "STORE()". See perltie for more details.
ACKNOLWEDGEMENTSThis documentation contributed by Andrew Sterling Hanenkamp <hanenkamp@cpan.org>AUTHORCopyright (c) 2005 Richard Hundt <richard NO SPAM AT protea-systems.com>LICENSEOryx may be used under the same terms as Perl itself.
Visit the GSP FreeBSD Man Page Interface. |