| 
119
 | 
     1 use strict;
 | 
| 
 | 
     2 package IMPL::Transform::Json;
 | 
| 
 | 
     3 
 | 
| 
118
 | 
     4 package IMPL::Web::QueryHandler::JsonFormat;
 | 
| 
166
 | 
     5 use parent qw(IMPL::Web::QueryHandler);
 | 
| 
118
 | 
     6 use Error qw(:try);
 | 
| 
 | 
     7 use JSON;
 | 
| 
 | 
     8 
 | 
| 
 | 
     9 sub Process {
 | 
| 
194
 | 
    10     my ($this,$action,$nextHandler) = @_;
 | 
| 
 | 
    11     
 | 
| 
 | 
    12     my $result;
 | 
| 
 | 
    13     
 | 
| 
 | 
    14     try {
 | 
| 
 | 
    15         $result = $nextHandler->();
 | 
| 
 | 
    16         $result = [$result] unless ref $result;
 | 
| 
 | 
    17     } otherwise {
 | 
| 
 | 
    18         my $err = shift;
 | 
| 
 | 
    19         $result = { error => $err };
 | 
| 
 | 
    20     };
 | 
| 
 | 
    21     
 | 
| 
 | 
    22     my $t = new IMPL::Transform::Json($action->context->{json});
 | 
| 
 | 
    23     
 | 
| 
 | 
    24     if ($action->context->{transactionType} and $action->context->{transactionType} eq 'form') {
 | 
| 
 | 
    25         delete @$result{qw(formData formSchema)};
 | 
| 
 | 
    26         my $errors = @$result{formErrors};
 | 
| 
 | 
    27         
 | 
| 
 | 
    28         $result->{formErrors} = [ map $_->Message, @$errors ] if $errors;
 | 
| 
 | 
    29     }
 | 
| 
 | 
    30     
 | 
| 
 | 
    31     $action->response->contentType('text/javascript');
 | 
| 
 | 
    32     
 | 
| 
 | 
    33     my $hout = $action->response->streamBody;
 | 
| 
 | 
    34     print $hout to_json( $t->Transform($result), {pretty => 1} );
 | 
| 
119
 | 
    35 } 
 | 
| 
118
 | 
    36 
 | 
| 
119
 | 
    37 package IMPL::Transform::Json;
 | 
| 
118
 | 
    38 
 | 
| 
166
 | 
    39 use parent qw(IMPL::Transform);
 | 
| 
118
 | 
    40 use IMPL::Class::Property;
 | 
| 
134
 | 
    41 use IMPL::Class::Property::Direct;
 | 
| 
 | 
    42 use Scalar::Util qw(refaddr);
 | 
| 
 | 
    43 
 | 
| 
 | 
    44 BEGIN {
 | 
| 
194
 | 
    45     private _direct property _visited => prop_none;
 | 
| 
134
 | 
    46 }
 | 
| 
 | 
    47 
 | 
| 
119
 | 
    48 my %propListCache;
 | 
| 
118
 | 
    49 
 | 
| 
 | 
    50 our %CTOR = (
 | 
| 
194
 | 
    51     'IMPL::Transform' => sub {
 | 
| 
 | 
    52         my $options = shift;
 | 
| 
 | 
    53         (
 | 
| 
 | 
    54             $options ? %{$options} : ()
 | 
| 
 | 
    55         ),
 | 
| 
 | 
    56         ARRAY => sub {
 | 
| 
 | 
    57             my ($this,$object) = @_;
 | 
| 
 | 
    58             
 | 
| 
 | 
    59             return [
 | 
| 
 | 
    60                 map { $this->Transform($_) } @$object
 | 
| 
 | 
    61             ];    
 | 
| 
 | 
    62         },
 | 
| 
 | 
    63         HASH => sub {
 | 
| 
 | 
    64             my ($this,$object) = @_;
 | 
| 
 | 
    65             
 | 
| 
 | 
    66             return {
 | 
| 
 | 
    67                 map { $_, $this->Transform($object->{$_}) } keys %$object
 | 
| 
 | 
    68             };
 | 
| 
 | 
    69         },
 | 
| 
 | 
    70         'IMPL::Object::List' => sub {
 | 
| 
 | 
    71             my ($this,$object) = @_;
 | 
| 
 | 
    72             
 | 
| 
 | 
    73             return [
 | 
| 
 | 
    74                 map { $this->Transform($_) } @$object
 | 
| 
 | 
    75             ]; 
 | 
| 
 | 
    76         },
 | 
| 
 | 
    77         -plain => sub {
 | 
| 
 | 
    78             $_[1];
 | 
| 
 | 
    79         },
 | 
| 
 | 
    80         -default => sub {
 | 
| 
 | 
    81             my ($this,$object) = @_;
 | 
| 
 | 
    82             
 | 
| 
 | 
    83             return "$object" unless $object->isa('IMPL::Object::Abstract');
 | 
| 
 | 
    84             
 | 
| 
 | 
    85             if ( $object->isa(typeof IMPL::Exception) ) {
 | 
| 
 | 
    86                 return {
 | 
| 
 | 
    87                     type => $object->typeof,
 | 
| 
 | 
    88                     message => $object->Message,
 | 
| 
 | 
    89                     arguments => $this->Transform(scalar $object->Args)
 | 
| 
 | 
    90                 };
 | 
| 
 | 
    91             }
 | 
| 
 | 
    92             
 | 
| 
 | 
    93             my $propList = $propListCache{ref $object};
 | 
| 
 | 
    94             unless ( $propList ) {
 | 
| 
 | 
    95                 my %props = map {
 | 
| 
 | 
    96                     $_->Name, (ref $_->Mutators ? 0 : ($_->Mutators & prop_list))
 | 
| 
 | 
    97                 } $object->get_meta('IMPL::Class::PropertyInfo',sub { $_->Access == IMPL::Class::Member::MOD_PUBLIC and $_->Name !~ /^_/}, 1 );
 | 
| 
 | 
    98                 
 | 
| 
 | 
    99                 $propListCache{ref $object} = $propList = \%props;
 | 
| 
 | 
   100             }
 | 
| 
 | 
   101             
 | 
| 
 | 
   102             return {
 | 
| 
 | 
   103                 map {
 | 
| 
 | 
   104                     $_, $propList->{$_} ? $this->Transform([$object->$_()]) : $this->Transform(scalar $object->$_());
 | 
| 
 | 
   105                 } keys %$propList
 | 
| 
 | 
   106             };
 | 
| 
 | 
   107         }
 | 
| 
 | 
   108     }
 | 
| 
118
 | 
   109 );
 | 
| 
 | 
   110 
 | 
| 
134
 | 
   111 sub Transform {
 | 
| 
194
 | 
   112     my ($this,$object) = @_;
 | 
| 
 | 
   113     
 | 
| 
 | 
   114     # small hack to prevent cycling
 | 
| 
 | 
   115     
 | 
| 
 | 
   116     return $this->SUPER::Transform($object) unless ref $object;
 | 
| 
 | 
   117     
 | 
| 
 | 
   118     if (exists $this->{$_visited}{refaddr $object}) {
 | 
| 
 | 
   119         return $this->{$_visited}{refaddr $object};
 | 
| 
 | 
   120     } else {
 | 
| 
 | 
   121         $this->{$_visited}{refaddr $object} = undef;
 | 
| 
 | 
   122         return $this->{$_visited}{refaddr $object} = $this->SUPER::Transform($object);
 | 
| 
 | 
   123     }
 | 
| 
134
 | 
   124 }
 | 
| 
 | 
   125 
 | 
| 
180
 | 
   126 1;
 |