DBIx-EAV

 view release on metacpan or  search on metacpan

lib/DBIx/EAV/Entity.pm  view on Meta::CPAN

    }
}

sub add_related {
    my ($self, $relname, $data) = @_;
    my $rel = $self->type->relationship($relname);
    die "Can't call add_related() for relationship '$rel->{name}'"
        if $rel->{is_has_one} || ($rel->{is_has_many} && $rel->{is_right_entity});

    $self->_save_related($relname, $data, { keep_current_links => 1 });
}


sub remove_related {
    my ($self, $relname, $data) = @_;
    my $rel = $self->type->relationship($relname);

    die "Can't call add_related() for relationship '$rel->{name}'"
        if $rel->{is_has_one} || ($rel->{is_has_many} && $rel->{is_right_entity});

    my $relationships_table = $self->eav->table('entity_relationships');
    my ($our_side, $their_side) = $rel->{is_right_entity} ? qw/ right left / : qw/ left right /;
    my $related_type = $self->eav->type_by_id($rel->{"${their_side}_entity_type_id"});

    $data = [$data] unless ref $data eq 'ARRAY';

    foreach my $entity (@$data) {

        die "remove_related() error: give me an instance of '".$related_type->name."' or an arrayref of it."
            unless blessed $entity && $entity->isa('DBIx::EAV::Entity') && $entity->is_type($related_type->name);

        $relationships_table->delete({
            relationship_id          => $rel->{id},
            $our_side  ."_entity_id" => $self->id,
            $their_side."_entity_id" => $entity->id
        });
    }
}


sub discard_changes {
    my $self = shift;

    while (my ($k, $v) = each %{$self->_modified}) {
        $self->raw->{$k} = $v;
        delete $self->raw->{$k};
    }

    $self;
}


sub delete {
    my $self = shift;
    die "Can't delete coz I'm not in storage!"
        unless $self->in_storage;

    my $eav  = $self->eav;
    my $type = $self->type;

    # cascade delete child entities
    foreach my $rel ($type->relationships) {

        next if $rel->{is_right_entity}
                || $rel->{is_many_to_many}
                || (exists $rel->{cascade_delete} && $rel->{cascade_delete} == 0);

        my $rs = $self->_get_related($rel->{name});
        while (my $related_entity = $rs->next) {
            $related_entity->delete;
        }
    }

    unless ($eav->schema->database_cascade_delete) {

        # delete relationship links
        $eav->table('entity_relationships')->delete([
            { left_entity_id  => $self->id },
            { right_entity_id => $self->id }
        ]);

        # delete attributes
        my %data_types = map { $_->{data_type} => 1 }
        $type->attributes( no_static => 1 );

        foreach my $data_type (keys %data_types) {
            $eav->table('value_'.$data_type)->delete({ entity_id => $self->id });
        }
    }

    # delete entity
    my $entities_table = $self->eav->table('entities');
    my $rv = $entities_table->delete({ id => $self->id });
    delete $self->raw->{id}; # not in_storage
    $rv;
}


##               ##
## Class Methods ##
##               ##

sub is_custom_class {
    my $class = shift;
    croak "is_custom_class() is a Class method." if ref $class;
    $class ne __PACKAGE__;
}

sub type_definition {
    my $class = shift;

    croak "type_definition() is a Class method." if ref $class;
    croak "type_definition() must be called on DBIx::EAV::Entity subclasses."
        unless $class->is_custom_class;

    no strict 'refs';
    unless (defined *{"${class}::__TYPE_DEFINITION__"}) {

        my %definition;
        # detect parent entity
        my $parent_class = ${"${class}::ISA"}[0];
        ($definition{extends}) = $parent_class =~ /::(\w+)$/
            if $parent_class ne __PACKAGE__;

        *{"${class}::__TYPE_DEFINITION__"} = \%definition;
    }


    \%{"${class}::__TYPE_DEFINITION__"};
}

# install class methods for type definition
foreach my $stuff (qw/ attribute has_many has_one many_to_many /) {
    no strict 'refs';

lib/DBIx/EAV/Entity.pm  view on Meta::CPAN


=back

Available only for has_many and many_to_many relationships, this method binds
entities via the C<$rel_name> relationship. C<$related_data> must be a
L<entity|DBIx::EAV::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 L<Entity|DBIx::EAV::Entity> objects which are not
L</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);


=head2 remove_related

=over 4

=item Arguments: L<$rel_name|DBIx::EAV::EntityType/relationship>, L<$related_entities|DBIx::EAV::Entity>

=back

Unbinds C<$related_entities> from the relationship C<$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);

=head2 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 L</save>.

=head2 delete

=over

=item Arguments: none

=item Return Value: L<$result|DBIx::Class::Manual::ResultClass>

=back

Throws an exception if the object is not in the database according to
L</in_storage>.

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

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

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 C<DELETE> is executed for the relationship links table where this entity
is the right-side entity, unbinding from "parent" relationships. Then a
C<DELETE> query is executed for each value table, unless this entity has no
attributes of that data type.

Those extra C<DELETE> operations are unneccessary if you are using database-level
C<ON DELETE CASCADE>. See L<DBIx::EAV/DATABASE-LEVEL CASCADE DELETE>.

See also L<DBIx::EAV::ResulutSet/delete>.

=head1 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.

=head1 AUTHOR

Carlos Fernando Avila Gratz E<lt>cafe@kreato.com.brE<gt>

=cut



( run in 0.501 second using v1.01-cache-2.11-cpan-5a3173703d6 )