view lib/IMPL/Config/Container.pm @ 420:df591e3afd10 ref20150831

sync
author cin
date Sat, 25 Feb 2017 22:35:26 +0300
parents bbc4739c4d48
children 7798345304bc
line wrap: on
line source

package IMPL::Config::Container;
use strict;

use Scalar::Util qw(blessed);
use IMPL::Exception();
use IMPL::lang qw(:base);
use IMPL::declare {
    require => {
        Descriptor        => 'IMPL::Config::Descriptor',
        ActivationContext => 'IMPL::Config::ActivationContext',
        Hierarchy         => 'IMPL::Config::Hierarchy',
        Bag               => 'IMPL::Config::Bag',
        Loader            => 'IMPL::Code::Loader'
    },
    base => [
        'IMPL::Object'             => undef,
        'IMPL::Object::Disposable' => undef
    ],
    props => [
        roles     => 'r',
        services  => 'r',
        instances => 'r',
        parent    => 'r',
        root      => 'r',
        loader    => 'r'
    ]
};

my $nextRoleId = 1;

sub CTOR {
    my ( $this, $parent, %opts ) = @_;

    $this->instances( {} );

    $this->loader( $opts{loader} || Loader->safe );

    if ($parent) {
        $this->roles( Hierarchy->new( $parent->roles ) );
        $this->services( Bag->new( $parent->services ) );
        $this->parent($parent);
        $this->root( $parent->root );
    }
    else {
        $this->roles( Hierarchy->new() );
        $this->services( Bag->new() );
        $this->root($this);
    }
}

sub Dispose {
    my ($this) = @_;

    my $d;
    foreach my $v ( values %{ $this->instances } ) {
        if ( $d = blessed($v) && $v->can('Dispose') ) {
            &$d($v);
        }
    }
}

sub Require {
    my ( $this, $class ) = @_;

    return $this->loader->Require($class);
}

sub Register {
    my ( $this, $role, $service ) = @_;

    die IMPL::InvalidArgumentException->new('service')
      unless is( $service, Descriptor );
    $this->services->Register( $this->GetLinearRoleHash($role), $service );
}

sub GetLinearRoleHash {
    my ( $this, $role ) = @_;

    die IMPL::InvalidArgumentException->new(
        role => 'The argument is required' )
      unless $role;

    if ( isarray($role) ) {
        my $tempRole = "unnamed-" . $nextRoleId++;
        $this->roles->AddRole( $tempRole, $role );
        $role = $tempRole;
    }

    $this->roles->GetLinearRoleHash($role);
}

sub Resolve {
    my ( $this, $role, %opts ) = @_;

    my $descriptor = $this->services->Resolve($role);

    return $descriptor->Activate( ActivationContext->new($this) )
      if $descriptor;

    return $opts{default} if exists $opts{default};
}

sub ResolveAll {
    my ( $this, $role, %opts ) = @_;

    my $all = $this->services->ResolveAll($role);

    my $context;

    my @result;

    foreach my $service (@$all) {
        $context = ActivationContext->new($this)
          unless $context || $opts{shared};

        push @result, $service->Activate($context);
    }

    return \@result;
}

1;

__END__

=pod

=head1 NAME

C<IMPL::Config::Container> - dependency injection container

=head1 SYNOPSIS

=head2 METHODS

=head3 Resolve($role)

=head3 ResolveAll($role, shared => $useSharedContext)

=head3 Register($role, $service)

=cut