=pod

=head1 NAME

UR::Object - Abstract class for objects tracked centrally in the application

=head1 SYNOPSIS

  $new_obj = Some::Class->create(...);

  $existing_obj  = Some::Class->get(...);
  @existing_objs = Some::Class->get(...);

  $current_value = $obj->some_property();

  $obj->some_property($new_value);

  @problems = $obj->invalid;

  @changes = $obj->changed;

  @parent_classes = $obj->inheritance;

=head1 DESCRIPTION

UR::Object is the base class which provides several general features
to all UR-based classes.  Most classes tracked through UR's object system
will inherit from UR::Object.

The goal of UR::Objects is that your application doesn't have to do 
data management.  Just ask for what you want, use it, and let it go.  A 
UR::Object works like a common software object, but it has a "context" 
which manages its state, references, relationships, in-memory 
transactions, queries and caching.

UR::Objects support full reflection and meta-programming.

=over 4

=item 1.

All objects have an "id" property which is a scalar value unique
within their class.  The id is intended to be as meaningful as
possible outside of the application, and usually correlates with a
database primary key or has a host/pid for truly application-internal
objects.  Classes with explicitly defined multiple ID properties
will still have an implicit "id" property, and their objects' 
"id" property will contain a composition of the other ID properties'
values.

=item 2.

All UR::Objects are stored in a central hash inside the Context, such
that, once created in one part of the application, the object is
retrievable in other parts of the application.  Objects only leave the
application when explictly removed.  This means it is not necessary
to hold a reference to objects to keep them "alive".

=item 3.

The class provides functionality to get an object by class/id or by
class/key-value-list without knowing if the object(s) specified are
already "in the application", or must be loaded from the outside.

=item 4.

Objects never directly reference other objects with a Perl reference.
References are done by class/id pair, allowing references to objects
which are not currently in the application, and supporting the dynamic
instantiation of objects on an as-needed basis.

=item 5.

The actual loading and saving of objects is handled by data source
classes, supporting varying RDBMS vendors if necessary, handling non-RDBMS
objects transparently as needed.

=item 6.

All objects allow callbacks to be set for changes to their properties,
supporting the model-view-controller design pattern nicely.

=item 7.

A special object for each subclass of UR::Object is available with
meta-data for the class itself.  These class objects are of type
L<UR::Object::Type>, and are also themselves UR::Objects. 

=back

Most other classes in the UR module set derive from UR::Object.

=head1 INHERITANCE

  UR::ModuleBase    Extensions for error, warning, and status messages.
    UR::Object      This class - general OO features

=head1 DERIVED CLASSES

Site-specific classes for logical entity types at the site will
derive from UR::Object indirectly, typically via UR::Entity,
with the intermediate class providing load/save logic and enforcing
database constraints.

=head1 CONSTRUCTORS

=over 4

=item create

  $obj = SomeClass->create(...);

Make a new instance of SomeClass.  This instance will not be visable outside
the application until it is committed to its data source.

=item define

  $obj = SomeClass->define(...);

Creates a new instance of SomeClass within the application.  define()
differs from create() in that define() simply asserts that the specified
object exists in the current Context, not that it is a newly created object.

Objects that exist because of define(), and whose properties have not been
altered since their definition, will not be saved outside the application.

=back

Object instances can also be "constructed" through the Context's object
loader as a side effect of calling C<get> or C<load> on a class whose data
source is external to the program.  The implication here is different than
the above two methods in that the objects existed outside the application
already, but the application is just now aware of them.

=head1 METHODS

The examples below use $obj where an actual object reference is required,
and SomeClass where the class name can be used.

=head2 Finding and destroying things:

=over 4

=item get

  $obj = SomeClass->get($id);

  $obj = SomeClass->get(property1 => value1, ...);

  @obj = SomeClass->get(property1 => value1, ...);

This is the core object retrieval method for all UR::Objects.

It returns one or more objects as decribed by the parameters passed-in.

This method will try SomeClass->is_loaded(@params) as described below, and
failing that will try SomeClass->load(@params), hitting the underlying data
sources only for objects not already active in the application.

If called in scalar context and more than one object matches the given 
parameters, get() will raise an exception through C<die>.

=item delete

  $obj->delete

Takes an object reference an deletes it within the application.  This is not
removed from the outside database until that database is committed.

=back

=head2 Basic identity information:

=over 4

=item class

  $obj->class

Returns the text string name of the class.
Essentially just ref($self) for objects, and $self for classes.

=item id

  $obj->id

A scalar value which uniquely identifies the object within its class.  In many cases,
where there are super-classes beneath UR::Object, the ID identifies the object within the super-class as well.

=back

=head2 Manipulation of object properties:

=over 4

=item (some property name)

  $obj->$property_name($new_value);
  $old_value = $obj->$property_name;

There is a method for each property on the object which acts as an accessor.
Identity properties are read-only, while non-identity properties are read-write.
Assigning an invalid value is allowed, but the object will not be savable until corrected.

=item set

  $obj->set(property1 => $value1, property2 => $value2);

This is a special method for bulk access via key-value pair(s).

=back

=head2 Managing the internal set of objects active in the application:

=over

=item load

  SomeClass->load(...)
  $obj->load()

As a class method, this is typically not called directly, but is called
by get() when the specified object(s) are not already in the application.
The parameters are the same as those of get().  load() will attempt to load
the object from it's storage place outside of the application.

As an instance method, load() is used to force a reload of the object's data 
from its external data source.  If the object has one or more changed
properties, and the reloaded data has conflicing changes, load() will raise
an exception.  This also applies to a get() which loads external data.

=item unload

  $obj->unload
  SomeClass->unload()

As an instance method, it removes an object from the application.  This
will fail if the object is changed.  As a class method, it will attempt
to remove all instances of SomeClass (and its subclasses) from the
application.

Objects which have been unloaded are no longer tracked or held by the
application's context and are re-blessed to throw execptions if the
reference is used.

Attempts to get() the same logical object will cause a new object to be
created and made active in the application.

=item is_loaded

  $obj->is_loaded(...)

This is also typically not called directly, but is called by get() to
see if the specified object(s) are already in the application's
central object cache.  It can be called directly when explicitly
testing for an object's presence in the application.

It returns an object or list of objects according to parameters, and
returns true in a boolean context.

=item create_iterator

  $iter = SomeClass->create_iterator(...);

Returns an object of type L<UR::Object::Iterator>.  create_iterator() takes
the same arguments as get(), but instead of returning the matching objects, 
it returns an iterator object with one method, next().  next() will return
one object from the resulting set each time it is called, and undef when
the results have been exhausted.

UR::Object::Iterator instances are normal hashrefs, not UR-based objects,
and obey the same scoping rules as any normal Perl reference. 

=back

=head2 Other methods

=over 4

=item __meta__

  $class_obj = $obj->__meta__();

Returns the class metadata object for the given object's class.  Class objects
are from the class L<UR::Object::Type>, and hold information about the class' 
properties, data source, relationships to other classes, etc.

=item strengthen

  $obj->strengthen();

UR objects are normally tracked by the current Context for the life of the
application, but the programmer can specify a limit to cache size, in 
which case old, unchanged objects are periodically pruned from the cache.
If strengthen() is called on an object, it will effectively be locked in
the cache, and will not be considered for pruning.

See L<UR::Context> for more information about the pruning mechanism.

=item weaken

  $obj->weaken();

weaken() is used to give a hint to the object cache pruner that this instance
is not going to be used in the application in the future, and should be
removed at the earliest chance.

=item changed

  @tags = $obj->changed()

Changes to objects' properties are tracked by the system.  If an object
has been changed since it was defined or loaded from its external data 
source, then changed() will return a list of L<UR::Object::Tag> objects
describing which properties have been changed.

=item invalid

  @tags = $obj->invalid()

Check the validity of an object by applying any constraints layed out in the
class such as making sure any non-optional properties contain values, numeric
properties contain numeric data, and properties with enumerated values only
contain valid values.

invalid() returns a list of L<UR::Object::Tag> objects describing each 
fault the object has.

=back

=head2 Subscriptions

Callbacks can be attached to classes, objects and their properties so an
application can track changes.  

=over 4

=item create_subscription

  $obj->create_subscription(      method   => change_type
                                  callback => $subref );
  SomeClass->create_subscription( id       => $obj_id,
                                  method   => change_type
                                  callback => $subref);
  SomeClass->create_subscription( method   => change_type
                                  callback => $subref );

Registers a callback to be called when a property of an object is changed.

The C<method> param can be any of the class' named parameters, or one of
the special changes such as "load", "create" or "delete".

In the first case, the callback will be fired when the param_name property
of the object is changed.  The second case is essentially identical to the
first, specifying one specific object ID.  In last case, the callback will
be fired if param_name is changed among any of SomeClass's instances.

The callbacks will be called with varying parameters depending on the nature
of the change.  For normal property value changes, the four parameters will
be C<$obj, $property_name, $old_value, $new_value>.  For other change types,
the callback will typically get two parameters, C<$obj, $change_type>.

=item cancel_change_subscription

  $obj->cancel_change_subscription($change_type, $callback);
  SomeClass->cancel_change_subscription($obj_id, $change_type, $callback);

Removes a previously registered subscription to an object or class

=head2 Special change types

=item create

Indicates the object was newly created via create()

=item delete

Indicates the object was removed via delete()

=item load

Indicates the object has been loaded into the application, either via
define() or by loading it from an external data source.

=item unload

Indicates the object is being removed from the application, usually
via unload().  

=head1 SEE ALSO

L<UR>, L<UR::Object::Type>, L<UR::Context>

=cut

