Beagle

 view release on metacpan or  search on metacpan

lib/Beagle/Handle.pm  view on Meta::CPAN


has 'comments_map' => (
    isa     => 'HashRef',
    is      => 'rw',
    default => sub { {} },
    lazy    => 1,
);

has 'updated' => (
    isa     => 'Str',
    is      => 'rw',
    default => '',
);

sub BUILD {
    my $self = shift;
    my $args = shift;

    if ( $args->{root} || $args->{name} ) {
        my $root = $args->{root} || name_root( $args->{name} );
        $self->backend(
            Beagle::Backend->new(
                root => $root,
                type => $args->{type} || root_type($root),
            )
        );
        $self->name( root_name($root) );
    }

    my $cache       = $self->cache;
    my $need_update = 1;

    if ( enabled_cache() && -e $cache ) {
        require Storable;
        %$self = %{ Storable::retrieve($cache) };
        $self->root( $args->{root} )
          if $args->{root} && ( $self->root || '' ) ne $args->{root};

        if ( $self->updated eq $self->backend->updated ) {
            undef $need_update;
        }
    }

    if ($need_update) {

        $self->map( {} );
        $self->init_info;
        $self->init_entries;

        $self->init_attachments;

        my $updated = $self->backend->updated;
        $self->updated($updated) if $updated;
        $self->update_cache;
        $self->update_relation;
    }

    return $self;
}

sub update_cache {
    my $self = shift;
    return unless enabled_cache();

    unless ( -e $self->cache ) {
        my $parent = parent_dir( $self->cache );
        make_path($parent) or die $! unless -e $parent;
    }

    require Storable;
    Storable::nstore( $self, $self->cache );
}

sub update_relation {
    my $self = shift;
    my $map  = relation();
    for my $key ( keys %$map ) {
        delete $map->{$key}
          if $map->{$key} eq $self->name;
    }
    for my $entry ( @{ $self->comments }, @{ $self->entries } ) {
        $map->{ $entry->id } = $self->name if $entry->can('id');
    }
    set_relation($map);
}

sub init_info {
    my $self    = shift;
    my $backend = $self->backend;
    ( undef, my $string ) = $backend->read( path => 'info' );
    my $info = Beagle::Model::Info->new_from_string(
        $string,
        root => $self->root,
        path => 'info'
    );
    $self->info($info);
    $self->map->{ $info->id } = $info;
}

sub init_entry_type {
    my $self    = shift;
    my $type    = shift;
    my $attr = $type_info->{$type}{plural};
    my $backend = $self->backend;
    {
        my %all = $backend->read( type => $type );
        my @entries;
        for my $id ( keys %all ) {
            my $class = $type_info->{$type}{class};

            my $entry = $class->new_from_string(
                $all{$id}{content},
                id       => $id,
                path     => $all{$id}{path},
                root     => $self->root,
                timezone => $self->info->timezone || 'UTC',
            );
            next if $entry->draft && !$self->drafts;

            $entry->author( current_user() ) unless $entry->author;

            push @entries, $entry;
            $self->map->{ $entry->id } = $entry;
        }

        @entries =
          sort { $b->created <=> $a->created } @entries;
        $self->$attr( \@entries );
    }
}

sub init_attachments {
    my $self            = shift;
    my $backend         = $self->backend;
    my %attachments_map = ();
    my %all             = $backend->read( type => 'attachment' );
    for my $id ( keys %all ) {
        $attachments_map{$id} = {
            map {
                $_ => Beagle::Model::Attachment->new(
                    name      => $_,
                    parent_id => $id,
                    root      => $self->root,
                  )
              } @{ $all{$id} }
        };
    }
    $self->attachments_map( \%attachments_map );
}

sub init_comments {
    my $self = shift;
    $self->init_entry_type('comment');
    my %comments_map;
    for my $comment ( @{ $self->comments } ) {
        $comments_map{ $comment->parent_id }{ $comment->id } = $comment;
    }
    $self->comments_map( \%comments_map );
}

sub total_size {
    my $self = shift;
    require Devel::Size;
    return Devel::Size::total_size($self);
}

sub list {
    my $self = shift;

    my %ret;

    return map { $_ => $self->$_ } qw/info total_size sites
      map attachments_map comments_map updated
      entry_types
      /, map { $type_info->{$_}{plural} } keys %$type_info;
}

sub update_info {
    my $self = shift;
    my $info = shift;
    my %args = @_;
    my $message = 'update info';
    $message .= "\n\n" . $args{message} if defined $args{message};
    $message .= "\n\n" . $info->commit_message if $info->commit_message;
    return unless $self->backend->update( $info, @_, message => $message );
    $self->info($info);
    return 1;
}

sub update {
    my $self    = shift;
    my $updated = $self->backend->updated;
    my $map     = $self->map;

    if ( $self->updated != $updated ) {
        $self->map( {} );
        $self->init_info;
        $self->init_entries;

        $self->init_attachments;
        $self->updated($updated);

        $self->update_cache;
        $self->update_relation;
    }
}

sub create_entry {
    my $self   = shift;
    my $entry  = shift;
    my $type   = $entry->type;
    my $method = "create_$type";
    if ( $self->can($method) && $method ne 'create_entry' ) {
        return $self->$method( $entry, @_ );
    }
    else {
        my %args = @_;
        my $message =
            'create '
          . $entry->type . ' '
          . $entry->id . ': '
          . $entry->summary(20);
        $message .= "\n\n" . $args{message} if defined $args{message};
        $message .= "\n\n" . $entry->commit_message if $entry->commit_message;

        return unless $self->backend->create( $entry, @_, message => $message );
        $self->map->{ $entry->id } = $entry;
        if ( $type eq 'comment' ) {
            $self->comments( [ $entry, @{ $self->comments } ] );
            $self->comments_map->{ $entry->parent_id }{ $entry->id } = $entry;
        }
        else {
            my $attr = PL($type);
            $self->$attr( [ $entry, @{ $self->$attr || [] } ] );
        }
    }
    return 1;
}

sub update_entry {
    my $self   = shift;
    my $entry  = shift;
    my $type   = $entry->type;
    my $method = "update_$type";
    if ( $self->can($method) ) {
        return $self->$method( $entry, @_ );
    }
    else {
        my %args = @_;
        my $message =
            'update '
          . $entry->type . ' '
          . $entry->id . ': '
          . $entry->summary(20);
        $message .= "\n\n" . $args{message} if defined $args{message};
        $message .= "\n\n" . $entry->commit_message if $entry->commit_message;

        return unless $self->backend->update( $entry, @_, message => $message );
        if ( $type eq 'comment' ) {
            $self->comments(
                [
                    map { $_->id eq $entry->id ? $entry : $_ }
                      @{ $self->comments }
                ]
            );
            $self->comments_map->{ $entry->parent_id }{ $entry->id } = $entry;
        }
        else {
            my $attr = PL($type);
            $self->$attr(
                [
                    map { $_->id eq $entry->id ? $entry : $_ } @{ $self->$attr || [] }
                ]
            );
        }
    }
    return 1;
}

sub delete_entry {
    my $self   = shift;
    my $entry  = shift;
    my $type   = $entry->type;
    my $method = "delete_$type";
    if ( $self->can($method) ) {
        return $self->$method( $entry, @_ );
    }
    else {
        my %args = @_;
        my $message =
            'delete '
          . $entry->type . ' '
          . $entry->id . ': '
          . $entry->summary(20);
        $message .= "\n\n" . $args{message} if defined $args{message};
        $message .= "\n\n" . $entry->commit_message if $entry->commit_message;
        return unless $self->backend->delete( $entry, @_, message => $message );
        delete $self->map->{ $entry->id };
        if ( my $att = $self->attachments_map->{ $entry->id } ) {
            $self->delete_attachment($_)



( run in 0.690 second using v1.01-cache-2.11-cpan-f56aa216473 )