view lib/IMPL/Web/DOM/FileNode.pm @ 409:f7eeafbd33da ref20150831

sync
author cin
date Sun, 13 Sep 2015 19:30:49 +0300
parents c6e90e02dd17
children
line wrap: on
line source

package IMPL::Web::DOM::FileNode;
use parent qw(IMPL::DOM::Node);

__PACKAGE__->PassThroughArgs;

use IMPL::Class::Property;
use File::Temp qw(tempfile);

BEGIN {
    public property parameterName => {
        get => sub {
            my ($this) = @_;
            $this->_parameterName() or
            $this->_parameterName(
                join '/', ( map {
                    (defined $_->nodeProperty('instanceId')) ?
                        $_->nodeName . '['.$_->nodeProperty('instanceId').']':
                        $_->nodeName
                } $this->_selectParents, $this )
            );
        }
    };
    private property _parameterName => prop_all;
    public property fileName => {
        get => sub {
            my ($this) = @_;
            return $this->document->query->param($this->parameterName);
        }
    };
    public property fileHandle => {
        get => sub {
            my ($this) = @_;
            return $this->document->query->upload($this->parameterName);
        }
    };
}

sub invokeTempFile {
    my ($this,$sub,$target) = @_;
    
    die new IMPL::InvalidArgumentException("A reference to a function should be specified") unless $sub && ref $sub eq 'CODE';
    
    $target ||= $this;
    
    my $query = $this->document->nodeProperty('query') or die new IMPL::InvalidOperationException("Failed to get a CGI query from the document");
    my $hFile = $query->upload($this->parameterName) or die new IMPL::IOException("Failed to open the uploaded file",$query->cgi_error,$this->parameterName,$this->nodeProperty('instanceId'));
            
    my ($hTemp,$tempFileName) = tempfile();
    binmode($hTemp);
    
    print $hTemp $_ while <$hFile>;
    
    $hTemp->flush();
    seek $hTemp, 0,0;
    {
        local $_ = $tempFileName;
        $sub->($this,$tempFileName,$hTemp);
    }
}

sub _selectParents {
    my ($node) = @_;
    
    my @result;
    
    unshift @result, $node while $node = $node->parentNode;
    
    return @result;
}

1;

__END__

=pod

=head1 NAME

C<IMPL::Web::DOM::FileNode> - узел, использующийся для представления параметра запроса в котором передан файл.

=head1 SINOPSYS

=begin code xml

<!-- input.schema.xml -->
<schema>
    <SimpleType type="file" nativeType="IMPL::Web::DOM::FileNode"/>
    <ComplexNode name="user">
        <Node type="file" name="avatar"/>
    </ComplexNode>
</schema>

=end code xml

=begin code

# handle.pl
use IMPL::DOM::Transform::PostToDOM ();
use IMPL::DOM::Schema;
use CGI;
use File::Copy qw(copy);

my $t = new IMPL::DOM::Transform::PostToDOM(
    undef,
    IMPL::DOM::Schema->LoadSchema('input.schema.xml'),
    'user'    
);

my $doc = $t->Transform(CGI->new());

if ($t->Errors->Count) {
    # handle errors    
}

$doc->selectSingleNode('avatar')->invokeTempFile(
    sub {
        my($node,$fname,$fhandle) = @_;
        
        # do smth with file
        copy($_,'avatar.jpg');
        
        # same thing
        # copy($fname,'avatar.jpg');
    }
);

=end code

=head1 DESCRIPTION

Данный класс используется для представлении параметров C<CGI> запросов при преобзаовании
запроса в ДОМ документ преобразованием C<IMPL::DOM::Transform::PostToDOM>.

Узлы данного типа расширяют стандатрный C<IMPL::DOM::Node> несколькими свойствами и
методами для доступа к файлу, переданному в виде параметра запроса.

=head1 MEMBERS

=head2 PROPERTIES

=over

=item C<[get] parameterName>

Имя параметра C<CGI> запроса соответствующего данному узлу.

=item C<[get] fileName>

Имя файла из параметра запроса

=item C<[get] fileHandle>

Указатель на файл из параметра запроса

=back

=head2 METHODS

=over

=item C<invokeTempFile($callback,$target)>

Сохраняет файл, переданный в запросе во временный, вызывает C<$callback> для обработки временного файла.

=over

=item C<$callback>

Ссылка на функцию которая будет вызвана для обработки временного файла. C<callback($target,$fname,$fhandle)>

=over

=item C<$fname>

Имя временного файла

=item C<$fhandle>

Указатель на временный файл

=back
    
Также пременная C<$_> содержит имя временного файла.

=item C<$target>

Значение этого параметра будет передано первым параметром функции C<$callback>.

=back

=back

=cut