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

NAME

DBIx::EAV::Entity - Represents an entity record.

SYNOPSIS

DESCRIPTION

This class can be used by itself or as base class for your entity objects.

CUSTOM CLASS

DBIx::EAV lets you define your entities via custom classes, which are subclasses of DBIx::EAV::Entity. Unlike DBIx::Class, the custom classes are not loaded upfront. They are lazy loaded whenever a call to "type" in DBIx::EAV is made. Directly or indirectly (i.e. via other DBIx::EAV methods like "resultset()").

Custom classes are used not only define the entity attributes and relationships, but also to add define you application's business logic, via custom entity methods.

Okay, an example. Lets mimic the namespaces used by DBIx::Class:

    my $eav = DBIx::EAV->connect($dsn, $user, $pass, $attrs, {
        entity_namespaces    => 'MyApp::Schema::Result',
        resultset_namespaces => 'MyApp::Schema::ResultSet',
    });

Now lets create a 'User' entity class.

    package MyApp::Schema::Result::User;
    use Moo;
    BEGIN { extends 'DBIx::EAV::Entity' }

    __PACKAGE__->attribute('first_name');
    __PACKAGE__->attribute('last_name');
    __PACKAGE__->attribute('email');
    __PACKAGE__->attribute('birth_date:datetime');
    __PACKAGE__->attribute('is_verified:boolean:0');

    # can also define relationships
    #__PACKAGE__->has_one( ... );
    #__PACKAGE__->has_many( ... );
    #__PACKAGE__->many_to_many( ... );

    # custom methods
    sub full_name {
        my $self = shift;
        return join ' ', $self->get('first_name'), $self->get('last_name');
    }

    1;

Done. You have just defined the User entity type, and also a custom class for instances of the this type.

    my $user = $eav->resultset('User')->create({
        first_name => 'Carlos',
        last_name  => 'Gratz'
    });

    print $user->full_name; # Carlos Gratz

    # obviously, all other DBIx::EAV::Entity are also available :]

As you could have noted in the first code snippet, its also possible to create custom resultset classes.

    package MyApp::Schema::ResultSet::User;

    use Moo;
    extends 'DBIx::EAV::ResultSet';

    sub verified_only {
        my $self = shift;
        $self->search({ is_verified => 1 });
    }


    1;

Now a call to $eav->resultset('User') returns an instance of MyApp::Schema::ResultSet::User.

    my $users_rs = $eav->resultset('User');

    $users_rs->isa('MyApp::Schema::ResultSet::User'); # 1

    my $verified_user = $users_rs->verified_only
                                  ->find({ email => 'user@example.com'});

CUSTOM CLASS INHERITANCE

DBIx::EAV supports entity type inheritance. When working with custom classes all you need to do is set you custom base class by normal perl means. DBIx::EAV will inspect your class @ISA and get the parent entity name.

    package MyApp::DB::Result::UserSubclass;
    BEGIN { extends 'MyApp::DB::Result::User' }

    # define attributes, relationships and methods for 'UserSubclass'

    1;

For more information on how entity type inheritance works in DBIx::EAV, read DBIx::EAV::Manual::Inheritance.

METHODS

in_storage

Returns true if a database id is present.

    sub in_storage {
        my $self = shift;
        exists $self->raw->{id} && defined $self->raw->{id};
    }

id

Returns the entity database id or undef if entity is not in storage.

    # new_entity() doesn't call save(). $cd1 has no id in this case
    my $cd1 = $eav->resultset('CD')->new_entity({ title => 'CD1' });

    $cd1->id;       # undef
    $cd1->save;
    $cd1->id;       # <database id>
    $cd1->delete;
    $cd1->id;       # undef

get

Arguments: $attr_name | $relationship_name
Return Value: $attr_value | $related_cursor | @related_entities

Returns a attribute value or related entities.

set

Arguments: $name, $value \%values
Arguments: \%values
Return Value: $self

Set a new value for the attribute or relationship $name. Returns $self to allow method chaining. Even though subsequent calls to "get" will return the new value you have just "set", changes are not saved in the database until you call "save". Use "update" if you wan't to set and save in one call.

    $cd->set('title' => 'New title');
    $cd->get('title');  # New title
    $cd->save; # or $cd->discard_changes

    # set multiple values
    $cd->set({
        title => 'New Title',
        year  => 2016
    });

When setting the value for a relationship, this method replaces the existing set of related entities by the new one (relationship bindings are deleted, not the related entities themselves). Valid values for relationships are existing entities or hashref suitable for inserting the related entity, or a arrayref of those (for *_many relationships). Passing an entity instance which is not of the correct type for the relationship or not "in_storage" is a fatal error.

    # set (and replace) the cd tracks
    $cd->set('tracks', [
        { title => 'Track1', duration => ... },
        { title => 'Track2', duration => ... },
        { title => 'Track3', duration => ... },
    ]);

    # set its tags
    my @tags = $eav->resultset('Tag')->find( name => [qw/ Foo Bar Baz /]);
    $cd->set('tags', \@tags);

You can obviously set attribute and relationships at the same time:

    $cd->set({
        title  => 'New Title',
        year   => 2016,
        tracks => \@tracks
    });

Se also "add_related" if you want to add (instead of replace) related entities.

save

Arguments: none
Return Value: $self

Save all changes to the database.

    # modify
    $entity->set( ... );

    $entity->save;

First thing save does is insert the entity (in the entities table) if its not already "in_storage". Then it saves the non-static attributes: attributes values (in the values tables) are inserted, updated or deleted, whether the value is new (undef -> value), existing (value -> value), or undef (value -> undef).

Then relationship bindings are inserted/deleted according with each relationship type and rules. Related entities in the form of hashref is inserted before the bindings takes place.

Last but not least, modifications to static attributes are saved on the entities table.

update

Arguments: $name, $value \%values
Arguments: \%values
Return Value: $self

A shortcut for set() and save().

    # set and save in one call
    $cd->update({
        title => 'New CD Title',
        year  => 2016
    });

load_attributes

Arguments: @attr_names?

Fetches the attributes values from database "value tables" and stores in entity's "raw" data structure. If this method is called without arguments all attributes will be loaded.

NOTE: In the current version of DBIx::EAV this method is called internally by "next" in DBIx::EAV::Cursor, which makes all attributes to be loaded everytime. Its planned for a future version to make the attributes get lazy-loaded, which will make this method relevant.

Arguments: $rel_name, $related_data

Available only for has_many and many_to_many relationships, this method binds entities via the $rel_name relationship. $related_data must be a entity instance (of the proper type for the relationship) or a hashref of data to be inserted (again, suitable for the related type), or a arrayref of those. Passing Entity objects which are not "in_storage" results in a fatal error.

    # add tracks to a cd
    $cd->add_related('tracks', [
        { title => 'Track1', duration => ... },
        { title => 'Track2', duration => ... },
        { title => 'Track3', duration => ... },
    ]);

    # also accepts existing entities
    my @tracks = $eav->resultset('Track')->populate( ... );
    $cd->add_related('tracks', \@tracks);
Arguments: $rel_name, $related_entities

Unbinds $related_entities from the relationship $rel_name. Note that it doesn't delete the related entities.

    my @tags = $eav->resultset('Tag')->find( name => [qw/ Foo Bar Baz /]);
    $article->remove_related('tags', \@tags);

discard_changes

Reverts all modified attributes to the its original value. Note that the internal memory of modified attributes is reset after a call to "save".

delete

Arguments: none
Return Value: $result

Throws an exception if the object is not in the database according to "in_storage".

The object is still perfectly usable, but "in_storage" will now return 0 and the object will be reinserted (same attrs, new id) if you call "save".

If you delete an object in a class with a has_many or has_one relationship, an attempt is made to delete all the related objects as well. To turn this behaviour off, pass cascade_delete => 0 in the $attr hashref of the relationship, see "Relationships" in DBIx::EAV.

Since a entity is represented by data not only in the entities table, but also in value tables and relationship links table, those related rows must be deleted before the main row.

First a DELETE is executed for the relationship links table where this entity is the right-side entity, unbinding from "parent" relationships. Then a DELETE query is executed for each value table, unless this entity has no attributes of that data type.

Those extra DELETE operations are unneccessary if you are using database-level ON DELETE CASCADE. See "DATABASE-LEVEL CASCADE DELETE" in DBIx::EAV.

See also "delete" in DBIx::EAV::ResulutSet.

LICENSE

Copyright (C) Carlos Fernando Avila Gratz.

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

AUTHOR

Carlos Fernando Avila Gratz <cafe@kreato.com.br>