| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package ExtJS::Generator::DBIC::Model; | 
| 2 |  |  |  |  |  |  | $ExtJS::Generator::DBIC::Model::VERSION = '0.003'; | 
| 3 |  |  |  |  |  |  | #ABSTRACT: ExtJS model producer | 
| 4 |  |  |  |  |  |  |  | 
| 5 |  |  |  |  |  |  |  | 
| 6 | 1 |  |  | 1 |  | 48722 | use Moo; | 
|  | 1 |  |  |  |  | 11290 |  | 
|  | 1 |  |  |  |  | 5 |  | 
| 7 | 1 |  |  | 1 |  | 1769 | use Types::Standard qw( Str HashRef InstanceOf HasMethods CodeRef ); | 
|  | 1 |  |  |  |  | 50143 |  | 
|  | 1 |  |  |  |  | 15 |  | 
| 8 | 1 |  |  | 1 |  | 1369 | use Data::Dump::JavaScript qw( dump_javascript false true ); | 
|  | 1 |  |  |  |  | 8285 |  | 
|  | 1 |  |  |  |  | 64 |  | 
| 9 | 1 |  |  | 1 |  | 418 | use Try::Tiny; | 
|  | 1 |  |  |  |  | 869 |  | 
|  | 1 |  |  |  |  | 44 |  | 
| 10 |  |  |  |  |  |  | #use Text::Xslate; | 
| 11 |  |  |  |  |  |  | #use List::Util qw( none ); | 
| 12 | 1 |  |  | 1 |  | 359 | use Path::Class; | 
|  | 1 |  |  |  |  | 13983 |  | 
|  | 1 |  |  |  |  | 59 |  | 
| 13 | 1 |  |  | 1 |  | 8 | use Fcntl qw( O_CREAT O_WRONLY O_EXCL O_TRUNC ); | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 37 |  | 
| 14 | 1 |  |  | 1 |  | 424 | use Module::Load; | 
|  | 1 |  |  |  |  | 755 |  | 
|  | 1 |  |  |  |  | 6 |  | 
| 15 | 1 |  |  | 1 |  | 444 | use namespace::clean; | 
|  | 1 |  |  |  |  | 7334 |  | 
|  | 1 |  |  |  |  | 10 |  | 
| 16 |  |  |  |  |  |  |  | 
| 17 |  |  |  |  |  |  |  | 
| 18 |  |  |  |  |  |  | has 'schemaname' => ( | 
| 19 |  |  |  |  |  |  | is       => 'ro', | 
| 20 |  |  |  |  |  |  | isa      => Str, | 
| 21 |  |  |  |  |  |  | required => 1, | 
| 22 |  |  |  |  |  |  | ); | 
| 23 |  |  |  |  |  |  |  | 
| 24 |  |  |  |  |  |  |  | 
| 25 |  |  |  |  |  |  | has 'schema' => ( | 
| 26 |  |  |  |  |  |  | is  => 'lazy', | 
| 27 |  |  |  |  |  |  | isa => InstanceOf ['DBIx::Class::Schema'], | 
| 28 |  |  |  |  |  |  | ); | 
| 29 |  |  |  |  |  |  |  | 
| 30 |  |  |  |  |  |  | sub _build_schema { | 
| 31 | 4 |  |  | 4 |  | 39 | my $self = shift; | 
| 32 | 4 |  |  |  |  | 25 | load $self->schemaname; | 
| 33 | 0 |  |  |  |  | 0 | my $schema = $self->schemaname->connect; | 
| 34 | 0 |  |  |  |  | 0 | return $schema; | 
| 35 |  |  |  |  |  |  | } | 
| 36 |  |  |  |  |  |  |  | 
| 37 |  |  |  |  |  |  |  | 
| 38 |  |  |  |  |  |  | has 'appname' => ( | 
| 39 |  |  |  |  |  |  | is       => 'ro', | 
| 40 |  |  |  |  |  |  | isa      => Str, | 
| 41 |  |  |  |  |  |  | required => 1, | 
| 42 |  |  |  |  |  |  | ); | 
| 43 |  |  |  |  |  |  |  | 
| 44 |  |  |  |  |  |  |  | 
| 45 |  |  |  |  |  |  | has 'model_namespace' => ( | 
| 46 |  |  |  |  |  |  | is  => 'lazy', | 
| 47 |  |  |  |  |  |  | isa => Str, | 
| 48 |  |  |  |  |  |  | ); | 
| 49 |  |  |  |  |  |  |  | 
| 50 |  |  |  |  |  |  | sub _build_model_namespace { | 
| 51 | 0 |  |  | 0 |  | 0 | my $self = shift; | 
| 52 |  |  |  |  |  |  |  | 
| 53 | 0 |  |  |  |  | 0 | return $self->appname . '.model'; | 
| 54 |  |  |  |  |  |  | } | 
| 55 |  |  |  |  |  |  |  | 
| 56 |  |  |  |  |  |  |  | 
| 57 |  |  |  |  |  |  | has 'model_baseclass' => ( | 
| 58 |  |  |  |  |  |  | is  => 'lazy', | 
| 59 |  |  |  |  |  |  | isa => Str, | 
| 60 |  |  |  |  |  |  | ); | 
| 61 |  |  |  |  |  |  |  | 
| 62 |  |  |  |  |  |  | sub _build_model_baseclass { | 
| 63 | 0 |  |  | 0 |  | 0 | my $self = shift; | 
| 64 |  |  |  |  |  |  |  | 
| 65 | 0 |  |  |  |  | 0 | return $self->appname . '.data.Model'; | 
| 66 |  |  |  |  |  |  | } | 
| 67 |  |  |  |  |  |  |  | 
| 68 |  |  |  |  |  |  | #sub sort_field_attrs { | 
| 69 |  |  |  |  |  |  | #    my ($attrs, $fixed) = @_; | 
| 70 |  |  |  |  |  |  | #    return [ @$fixed, sort grep { my $attr = $_; none { $_ eq $attr } @$fixed } @$attrs ]; | 
| 71 |  |  |  |  |  |  | #} | 
| 72 |  |  |  |  |  |  |  | 
| 73 |  |  |  |  |  |  | #has '_xslate' => ( | 
| 74 |  |  |  |  |  |  | #    is  => 'lazy', | 
| 75 |  |  |  |  |  |  | #    isa => InstanceOf['Text::Xslate'], | 
| 76 |  |  |  |  |  |  | #); | 
| 77 |  |  |  |  |  |  | # | 
| 78 |  |  |  |  |  |  | #sub _build__xslate { | 
| 79 |  |  |  |  |  |  | #    my $self = shift; | 
| 80 |  |  |  |  |  |  | #    return Text::Xslate->new( | 
| 81 |  |  |  |  |  |  | #        function => { | 
| 82 |  |  |  |  |  |  | #            'array::sort_field_attrs' => \&sort_field_attrs, | 
| 83 |  |  |  |  |  |  | #        }, | 
| 84 |  |  |  |  |  |  | #    ); | 
| 85 |  |  |  |  |  |  | #} | 
| 86 |  |  |  |  |  |  |  | 
| 87 |  |  |  |  |  |  | #has 'model_template' => ( | 
| 88 |  |  |  |  |  |  | #    is  => 'lazy', | 
| 89 |  |  |  |  |  |  | #    isa => Str, | 
| 90 |  |  |  |  |  |  | #); | 
| 91 |  |  |  |  |  |  |  | 
| 92 |  |  |  |  |  |  | #sub _build_model_template { | 
| 93 |  |  |  |  |  |  | #    return q/Ext.define('<: $classname :>', { | 
| 94 |  |  |  |  |  |  | #    : for $attributes.keys().sort_field_attrs(["extend", "requires", "idProperty", "fields"]) -> $attr { | 
| 95 |  |  |  |  |  |  | #    : if is_array_ref($attributes[$attr]) { | 
| 96 |  |  |  |  |  |  | #    <: $attr :>: [ | 
| 97 |  |  |  |  |  |  | #    : for $attributes[$attr].sort() -> $subkey { | 
| 98 |  |  |  |  |  |  | #    : if $attr == 'fields' { | 
| 99 |  |  |  |  |  |  | #        { | 
| 100 |  |  |  |  |  |  | #            : for $subkey.keys().sort_field_attrs(["name", "type"]) -> $field { | 
| 101 |  |  |  |  |  |  | #            <: $field :>: '<: $subkey[$field] :>'<: if ! $~field.is_last { :>,<: } :> | 
| 102 |  |  |  |  |  |  | #            : } | 
| 103 |  |  |  |  |  |  | #        }<: if ! $~subkey.is_last { :>,<: } :> | 
| 104 |  |  |  |  |  |  | #    : } | 
| 105 |  |  |  |  |  |  | #    : else { | 
| 106 |  |  |  |  |  |  | #        '<: $subkey :>'<: if ! $~subkey.is_last { :>,<: } :> | 
| 107 |  |  |  |  |  |  | #    : } | 
| 108 |  |  |  |  |  |  | #    : } | 
| 109 |  |  |  |  |  |  | #    ]<: if ! $~attr.is_last { :>,<: } :> | 
| 110 |  |  |  |  |  |  | #    : } | 
| 111 |  |  |  |  |  |  | #    : else { | 
| 112 |  |  |  |  |  |  | #    <: $attr :>: '<: $attributes[$attr] :>'<: if ! $~attr.is_last { :>,<: } :> | 
| 113 |  |  |  |  |  |  | #    : } | 
| 114 |  |  |  |  |  |  | #    : } | 
| 115 |  |  |  |  |  |  | #}); | 
| 116 |  |  |  |  |  |  | #/; | 
| 117 |  |  |  |  |  |  | #} | 
| 118 |  |  |  |  |  |  |  | 
| 119 |  |  |  |  |  |  |  | 
| 120 |  |  |  |  |  |  | has 'model_args' => ( | 
| 121 |  |  |  |  |  |  | is  => 'ro', | 
| 122 |  |  |  |  |  |  | isa => HashRef, | 
| 123 |  |  |  |  |  |  | ); | 
| 124 |  |  |  |  |  |  |  | 
| 125 |  |  |  |  |  |  | my %translate = ( | 
| 126 |  |  |  |  |  |  |  | 
| 127 |  |  |  |  |  |  | # | 
| 128 |  |  |  |  |  |  | # MySQL types | 
| 129 |  |  |  |  |  |  | # | 
| 130 |  |  |  |  |  |  | bigint     => 'int', | 
| 131 |  |  |  |  |  |  | double     => 'float', | 
| 132 |  |  |  |  |  |  | decimal    => 'float', | 
| 133 |  |  |  |  |  |  | float      => 'float', | 
| 134 |  |  |  |  |  |  | int        => 'int', | 
| 135 |  |  |  |  |  |  | integer    => 'int', | 
| 136 |  |  |  |  |  |  | mediumint  => 'int', | 
| 137 |  |  |  |  |  |  | smallint   => 'int', | 
| 138 |  |  |  |  |  |  | tinyint    => 'int', | 
| 139 |  |  |  |  |  |  | char       => 'string', | 
| 140 |  |  |  |  |  |  | varchar    => 'string', | 
| 141 |  |  |  |  |  |  | tinyblob   => 'auto', | 
| 142 |  |  |  |  |  |  | blob       => 'auto', | 
| 143 |  |  |  |  |  |  | mediumblob => 'auto', | 
| 144 |  |  |  |  |  |  | longblob   => 'auto', | 
| 145 |  |  |  |  |  |  | tinytext   => 'string', | 
| 146 |  |  |  |  |  |  | text       => 'string', | 
| 147 |  |  |  |  |  |  | longtext   => 'string', | 
| 148 |  |  |  |  |  |  | mediumtext => 'string', | 
| 149 |  |  |  |  |  |  | enum       => 'string', | 
| 150 |  |  |  |  |  |  | set        => 'string', | 
| 151 |  |  |  |  |  |  | date       => 'date', | 
| 152 |  |  |  |  |  |  | datetime   => 'date', | 
| 153 |  |  |  |  |  |  | time       => 'date', | 
| 154 |  |  |  |  |  |  | timestamp  => 'date', | 
| 155 |  |  |  |  |  |  | year       => 'date', | 
| 156 |  |  |  |  |  |  |  | 
| 157 |  |  |  |  |  |  | # | 
| 158 |  |  |  |  |  |  | # PostgreSQL types | 
| 159 |  |  |  |  |  |  | # | 
| 160 |  |  |  |  |  |  | numeric             => 'float', | 
| 161 |  |  |  |  |  |  | 'double precision'  => 'float', | 
| 162 |  |  |  |  |  |  | serial              => 'int', | 
| 163 |  |  |  |  |  |  | bigserial           => 'int', | 
| 164 |  |  |  |  |  |  | money               => 'float', | 
| 165 |  |  |  |  |  |  | character           => 'string', | 
| 166 |  |  |  |  |  |  | 'character varying' => 'string', | 
| 167 |  |  |  |  |  |  | bytea               => 'auto', | 
| 168 |  |  |  |  |  |  | interval            => 'float', | 
| 169 |  |  |  |  |  |  | boolean             => 'boolean', | 
| 170 |  |  |  |  |  |  | point               => 'float', | 
| 171 |  |  |  |  |  |  | line                => 'float', | 
| 172 |  |  |  |  |  |  | lseg                => 'float', | 
| 173 |  |  |  |  |  |  | box                 => 'float', | 
| 174 |  |  |  |  |  |  | path                => 'float', | 
| 175 |  |  |  |  |  |  | polygon             => 'float', | 
| 176 |  |  |  |  |  |  | circle              => 'float', | 
| 177 |  |  |  |  |  |  | cidr                => 'string', | 
| 178 |  |  |  |  |  |  | inet                => 'string', | 
| 179 |  |  |  |  |  |  | macaddr             => 'string', | 
| 180 |  |  |  |  |  |  | bit                 => 'int', | 
| 181 |  |  |  |  |  |  | 'bit varying'       => 'int', | 
| 182 |  |  |  |  |  |  |  | 
| 183 |  |  |  |  |  |  | # | 
| 184 |  |  |  |  |  |  | # Oracle types | 
| 185 |  |  |  |  |  |  | # | 
| 186 |  |  |  |  |  |  | number   => 'float', | 
| 187 |  |  |  |  |  |  | varchar2 => 'string', | 
| 188 |  |  |  |  |  |  | long     => 'float', | 
| 189 |  |  |  |  |  |  | ); | 
| 190 |  |  |  |  |  |  |  | 
| 191 |  |  |  |  |  |  | my %extjs_class_for_datatype = ( | 
| 192 |  |  |  |  |  |  | boolean => 'Ext.data.field.Boolean', | 
| 193 |  |  |  |  |  |  | date    => 'Ext.data.field.Date', | 
| 194 |  |  |  |  |  |  | int     => 'Ext.data.field.Integer', | 
| 195 |  |  |  |  |  |  | float   => 'Ext.data.field.Number', | 
| 196 |  |  |  |  |  |  | string  => 'Ext.data.field.String', | 
| 197 |  |  |  |  |  |  | ); | 
| 198 |  |  |  |  |  |  |  | 
| 199 |  |  |  |  |  |  |  | 
| 200 |  |  |  |  |  |  | sub extjs_model_name { | 
| 201 | 0 |  |  | 0 | 1 | 0 | my ( $self, $tablename ) = @_; | 
| 202 | 0 | 0 |  |  |  | 0 | $tablename = $tablename =~ m/^(?:\w+::)* (\w+)$/x ? $1 : $tablename; | 
| 203 | 0 |  |  |  |  | 0 | return $self->model_namespace . '.' . ucfirst($tablename); | 
| 204 |  |  |  |  |  |  | } | 
| 205 |  |  |  |  |  |  |  | 
| 206 |  |  |  |  |  |  |  | 
| 207 |  |  |  |  |  |  | sub extjs_model_alias { | 
| 208 | 0 |  |  | 0 | 1 | 0 | my ( $self, $modelname ) = @_; | 
| 209 | 0 | 0 |  |  |  | 0 | $modelname = $modelname =~ m/^(?:\w+\.)* (\w+\.\w+)$/x ? $1 : $modelname; | 
| 210 | 0 |  |  |  |  | 0 | return lc($modelname); | 
| 211 |  |  |  |  |  |  | } | 
| 212 |  |  |  |  |  |  |  | 
| 213 |  |  |  |  |  |  |  | 
| 214 |  |  |  |  |  |  | sub extjs_model_entityname { | 
| 215 | 0 |  |  | 0 | 1 | 0 | my ( $self, $extjs_model_name ) = @_; | 
| 216 | 0 | 0 |  |  |  | 0 | die 'ExtJS model name is required' | 
| 217 |  |  |  |  |  |  | if not defined $extjs_model_name; | 
| 218 | 0 |  |  |  |  | 0 | my $model_namespace = $self->model_namespace; | 
| 219 | 0 |  |  |  |  | 0 | my ($entityname) = $extjs_model_name =~ /^$model_namespace\.(.+)$/; | 
| 220 | 0 |  |  |  |  | 0 | return $entityname; | 
| 221 |  |  |  |  |  |  | } | 
| 222 |  |  |  |  |  |  |  | 
| 223 |  |  |  |  |  |  |  | 
| 224 |  |  |  |  |  |  | sub extjs_model { | 
| 225 | 2 |  |  | 2 | 1 | 2634 | my ( $self, $rsrcname ) = @_; | 
| 226 | 2 |  |  |  |  | 107 | my $schema = $self->schema; | 
| 227 |  |  |  |  |  |  |  | 
| 228 | 0 |  |  |  |  | 0 | my $rsrc         = $schema->source($rsrcname); | 
| 229 | 0 |  |  |  |  | 0 | my $extjsname    = $self->extjs_model_name($rsrcname); | 
| 230 | 0 |  |  |  |  | 0 | my $columns_info = $rsrc->columns_info; | 
| 231 | 0 |  |  |  |  | 0 | my %field_by_colname; | 
| 232 |  |  |  |  |  |  | my %requires; | 
| 233 |  |  |  |  |  |  | # same order the columns where added to the ResultSource | 
| 234 | 0 |  |  |  |  | 0 | foreach my $colname ( $rsrc->columns ) { | 
| 235 | 0 |  |  |  |  | 0 | my $field_params = { name => $colname }; | 
| 236 | 0 |  |  |  |  | 0 | my $column_info = $columns_info->{$colname}; | 
| 237 |  |  |  |  |  |  |  | 
| 238 |  |  |  |  |  |  | # views might not have column infos | 
| 239 | 0 | 0 |  |  |  | 0 | if ( not %$column_info ) { | 
| 240 | 0 |  |  |  |  | 0 | $field_params->{data_type} = 'auto'; | 
| 241 |  |  |  |  |  |  | } | 
| 242 |  |  |  |  |  |  | else { | 
| 243 | 0 |  |  |  |  | 0 | my $data_type = lc( $column_info->{data_type} ); | 
| 244 | 0 | 0 |  |  |  | 0 | if ( exists $translate{$data_type} ) { | 
| 245 | 0 |  |  |  |  | 0 | my $extjs_data_type = $translate{$data_type}; | 
| 246 |  |  |  |  |  |  |  | 
| 247 |  |  |  |  |  |  | # determine if a numeric column is an int or a really a float | 
| 248 | 0 | 0 |  |  |  | 0 | if ( $extjs_data_type eq 'float' ) { | 
| 249 |  |  |  |  |  |  | $extjs_data_type = 'int' | 
| 250 |  |  |  |  |  |  | if exists $column_info->{size} | 
| 251 | 0 | 0 | 0 |  |  | 0 | && $column_info->{size} !~ /,/; | 
| 252 |  |  |  |  |  |  | } | 
| 253 | 0 |  |  |  |  | 0 | $field_params->{type} = $extjs_data_type; | 
| 254 |  |  |  |  |  |  | # remember all ExtJS data types for requires | 
| 255 | 0 |  |  |  |  | 0 | $requires{$extjs_class_for_datatype{$extjs_data_type}} = 1; | 
| 256 |  |  |  |  |  |  | } | 
| 257 |  |  |  |  |  |  |  | 
| 258 |  |  |  |  |  |  | $field_params->{defaultValue} = $column_info->{default_value} | 
| 259 |  |  |  |  |  |  | if exists $column_info->{default_value} | 
| 260 | 0 | 0 | 0 |  |  | 0 | && defined $column_info->{default_value}; | 
| 261 |  |  |  |  |  |  |  | 
| 262 | 0 | 0 |  |  |  | 0 | if ( exists $column_info->{is_nullable} ) { | 
| 263 | 0 | 0 | 0 |  |  | 0 | if ( $column_info->{is_nullable} && $field_params->{type} ne 'date' ) { | 
| 264 | 0 |  |  |  |  | 0 | $field_params->{allowNull} = true(); | 
| 265 |  |  |  |  |  |  | } | 
| 266 |  |  |  |  |  |  | # only required for foreign key columns -> smaller JS | 
| 267 |  |  |  |  |  |  | #else { | 
| 268 |  |  |  |  |  |  | #    $field_params->{allowBlank} = false(); | 
| 269 |  |  |  |  |  |  | #} | 
| 270 |  |  |  |  |  |  | } | 
| 271 |  |  |  |  |  |  | # is_nullable defaults to false in DBIC, allowNull defaults also | 
| 272 |  |  |  |  |  |  | # to false in ExtJS 6, so we don't need to set it -> smaller JS | 
| 273 |  |  |  |  |  |  | # else { | 
| 274 |  |  |  |  |  |  | #     $field_params->{allowNull} = false(); | 
| 275 |  |  |  |  |  |  | # } | 
| 276 | 0 | 0 | 0 |  |  | 0 | if ( exists $column_info->{is_auto_increment} | 
| 277 |  |  |  |  |  |  | && $column_info->{is_auto_increment} ) { | 
| 278 | 0 |  |  |  |  | 0 | $field_params->{persist} = false(); | 
| 279 |  |  |  |  |  |  | } | 
| 280 |  |  |  |  |  |  |  | 
| 281 |  |  |  |  |  |  | #use Data::Dumper::Concise; | 
| 282 |  |  |  |  |  |  | #warn Dumper($column_info) | 
| 283 |  |  |  |  |  |  | #    if $rsrcname eq 'Customer'; | 
| 284 |  |  |  |  |  |  |  | 
| 285 |  |  |  |  |  |  | # support for DBIx::Class::DynamicDefault | 
| 286 | 0 | 0 | 0 |  |  | 0 | if ( $rsrc->isa('DBIx::Class::DynamicDefault') | 
|  |  |  | 0 |  |  |  |  | 
| 287 |  |  |  |  |  |  | && ( | 
| 288 |  |  |  |  |  |  | (  exists $column_info->{dynamic_default_on_create} | 
| 289 |  |  |  |  |  |  | && $column_info->{dynamic_default_on_create} eq 'get_timestamp' ) | 
| 290 |  |  |  |  |  |  | || ( | 
| 291 |  |  |  |  |  |  | exists $column_info->{dynamic_default_on_update} | 
| 292 |  |  |  |  |  |  | && $column_info->{dynamic_default_on_update} eq 'get_timestamp' | 
| 293 |  |  |  |  |  |  | ) | 
| 294 |  |  |  |  |  |  | ) ) { | 
| 295 | 0 |  |  |  |  | 0 | $field_params->{persist} = false(); | 
| 296 |  |  |  |  |  |  | } | 
| 297 |  |  |  |  |  |  |  | 
| 298 |  |  |  |  |  |  | # support for DBIx::Class::TimeStamp | 
| 299 | 0 | 0 | 0 |  |  | 0 | if ( (  exists $column_info->{set_on_create} | 
|  |  |  | 0 |  |  |  |  | 
|  |  |  | 0 |  |  |  |  | 
| 300 |  |  |  |  |  |  | && $column_info->{set_on_create} ) | 
| 301 |  |  |  |  |  |  | || ( | 
| 302 |  |  |  |  |  |  | exists $column_info->{set_on_update} | 
| 303 |  |  |  |  |  |  | && $column_info->{set_on_update} | 
| 304 |  |  |  |  |  |  | ) ) { | 
| 305 | 0 |  |  |  |  | 0 | $field_params->{persist} = false(); | 
| 306 |  |  |  |  |  |  | } | 
| 307 |  |  |  |  |  |  |  | 
| 308 |  |  |  |  |  |  | # support for DBIx::Class::UserStamp | 
| 309 | 0 | 0 | 0 |  |  | 0 | if ( (  exists $column_info->{store_user_on_create} | 
|  |  |  | 0 |  |  |  |  | 
|  |  |  | 0 |  |  |  |  | 
| 310 |  |  |  |  |  |  | && $column_info->{store_user_on_create} ) | 
| 311 |  |  |  |  |  |  | || ( | 
| 312 |  |  |  |  |  |  | exists $column_info->{store_user_on_update} | 
| 313 |  |  |  |  |  |  | && $column_info->{store_user_on_update} | 
| 314 |  |  |  |  |  |  | ) ) { | 
| 315 | 0 |  |  |  |  | 0 | $field_params->{persist} = false(); | 
| 316 |  |  |  |  |  |  | } | 
| 317 |  |  |  |  |  |  |  | 
| 318 |  |  |  |  |  |  | # support for DBIx::Class::InflateColumn::Boolean | 
| 319 | 0 | 0 | 0 |  |  | 0 | if ( exists $column_info->{is_boolean} | 
| 320 |  |  |  |  |  |  | && $column_info->{is_boolean} ) { | 
| 321 | 0 |  |  |  |  | 0 | $field_params->{type} = 'bool'; | 
| 322 |  |  |  |  |  |  | } | 
| 323 |  |  |  |  |  |  | } | 
| 324 | 0 |  |  |  |  | 0 | $field_by_colname{$colname} = $field_params; | 
| 325 |  |  |  |  |  |  | } | 
| 326 |  |  |  |  |  |  |  | 
| 327 |  |  |  |  |  |  | #my @assocs; | 
| 328 | 0 |  |  |  |  | 0 | foreach my $relname ( sort $rsrc->relationships ) { | 
| 329 | 0 |  |  |  |  | 0 | my $relinfo = $rsrc->relationship_info($relname); | 
| 330 |  |  |  |  |  |  |  | 
| 331 |  |  |  |  |  |  | # FIXME: handle complex relationship conditions, skip for now | 
| 332 | 0 | 0 |  |  |  | 0 | if ( ! (ref $relinfo->{cond} eq 'HASH') ) { | 
| 333 | 0 |  |  |  |  | 0 | warn "$extjsname:\t$relname: complex relationship condition, skipping"; | 
| 334 | 0 |  |  |  |  | 0 | next; | 
| 335 |  |  |  |  |  |  | } | 
| 336 |  |  |  |  |  |  |  | 
| 337 | 0 | 0 |  |  |  | 0 | if ( keys %{ $relinfo->{cond} } > 1 ) { | 
|  | 0 |  |  |  |  | 0 |  | 
| 338 | 0 |  |  |  |  | 0 | warn | 
| 339 |  |  |  |  |  |  | "$extjsname:\t$relname: skipping because multi-cond rels aren't supported by ExtJS\n"; | 
| 340 | 0 |  |  |  |  | 0 | next; | 
| 341 |  |  |  |  |  |  | } | 
| 342 |  |  |  |  |  |  |  | 
| 343 | 0 | 0 |  |  |  | 0 | if ( keys %{ $relinfo->{cond} } > 1 ) { | 
|  | 0 |  |  |  |  | 0 |  | 
| 344 | 0 |  |  |  |  | 0 | warn | 
| 345 |  |  |  |  |  |  | "$extjsname:\t$relname: multiple column relationship not supported by ExtJS\n"; | 
| 346 | 0 |  |  |  |  | 0 | next; | 
| 347 |  |  |  |  |  |  | } | 
| 348 |  |  |  |  |  |  |  | 
| 349 |  |  |  |  |  |  | #use Data::Dumper::Concise; | 
| 350 |  |  |  |  |  |  | #print $rsrcname . Dumper($relinfo) | 
| 351 |  |  |  |  |  |  | #    if $rsrcname eq 'Raduser'; | 
| 352 |  |  |  |  |  |  |  | 
| 353 | 0 |  |  |  |  | 0 | my ($rel_col) = keys %{ $relinfo->{cond} }; | 
|  | 0 |  |  |  |  | 0 |  | 
| 354 | 0 |  |  |  |  | 0 | my $our_col = $relinfo->{cond}->{$rel_col}; | 
| 355 | 0 |  |  |  |  | 0 | $rel_col =~ s/^foreign\.//; | 
| 356 | 0 |  |  |  |  | 0 | $our_col =~ s/^self\.//; | 
| 357 | 0 |  |  |  |  | 0 | my $column_info = $columns_info->{$our_col}; | 
| 358 |  |  |  |  |  |  |  | 
| 359 | 0 |  |  |  |  | 0 | my $remote_rsrc = $schema->source($relinfo->{source}); | 
| 360 | 0 |  |  |  |  | 0 | my $remote_relname; | 
| 361 | 0 |  |  |  |  | 0 | foreach my $relname ( $remote_rsrc->relationships ) { | 
| 362 | 0 |  |  |  |  | 0 | my $remote_relinfo = $remote_rsrc->relationship_info($relname); | 
| 363 |  |  |  |  |  |  |  | 
| 364 |  |  |  |  |  |  | # FIXME: handle complex relationship conditions, skip for now | 
| 365 | 0 | 0 |  |  |  | 0 | if ( ! (ref $remote_relinfo->{cond} eq 'HASH') ) { | 
| 366 | 0 |  |  |  |  | 0 | warn "$extjsname:\t$relname: complex relationship condition, skipping"; | 
| 367 | 0 |  |  |  |  | 0 | next; | 
| 368 |  |  |  |  |  |  | } | 
| 369 | 0 |  |  |  |  | 0 | my ($remote_rel_col) = keys %{ $remote_relinfo->{cond} }; | 
|  | 0 |  |  |  |  | 0 |  | 
| 370 | 0 |  |  |  |  | 0 | my $remote_our_col = $remote_relinfo->{cond}->{$remote_rel_col}; | 
| 371 | 0 |  |  |  |  | 0 | $remote_rel_col =~ s/^foreign\.//; | 
| 372 | 0 |  |  |  |  | 0 | $remote_our_col =~ s/^self\.//; | 
| 373 | 0 | 0 | 0 |  |  | 0 | if ( $remote_relinfo->{source} eq $rsrc->result_class | 
|  |  |  | 0 |  |  |  |  | 
| 374 |  |  |  |  |  |  | && $rel_col eq $remote_our_col | 
| 375 |  |  |  |  |  |  | && $our_col eq $remote_rel_col ) { | 
| 376 | 0 |  |  |  |  | 0 | $remote_relname = $relname; | 
| 377 | 0 |  |  |  |  | 0 | last; | 
| 378 |  |  |  |  |  |  | } | 
| 379 |  |  |  |  |  |  | } | 
| 380 | 0 | 0 |  |  |  | 0 | warn "$extjsname:\t$relname: can't find reverse relationship name\n" | 
| 381 |  |  |  |  |  |  | if not defined $remote_relname; | 
| 382 |  |  |  |  |  |  |  | 
| 383 | 0 |  |  |  |  | 0 | my $attrs = $relinfo->{attrs}; | 
| 384 |  |  |  |  |  |  |  | 
| 385 |  |  |  |  |  |  | #my $extjs_rel = { | 
| 386 |  |  |  |  |  |  | #    name           => $relname, | 
| 387 |  |  |  |  |  |  | #    associationKey => $relname, | 
| 388 |  |  |  |  |  |  | # | 
| 389 |  |  |  |  |  |  | #    # class instead of source? | 
| 390 |  |  |  |  |  |  | #    model      => $self->extjs_model_name( $relinfo->{source} ), | 
| 391 |  |  |  |  |  |  | #    primaryKey => $rel_col, | 
| 392 |  |  |  |  |  |  | #    foreignKey => $our_col, | 
| 393 |  |  |  |  |  |  | #}; | 
| 394 |  |  |  |  |  |  |  | 
| 395 |  |  |  |  |  |  | # belongs_to | 
| 396 |  |  |  |  |  |  | #{ | 
| 397 |  |  |  |  |  |  | #    attrs => { | 
| 398 |  |  |  |  |  |  | #        accessor                  => "filter", | 
| 399 |  |  |  |  |  |  | #        is_depends_on             => 1, | 
| 400 |  |  |  |  |  |  | #        is_foreign_key_constraint => 1, | 
| 401 |  |  |  |  |  |  | #        undef_on_null_fk          => 1 | 
| 402 |  |  |  |  |  |  | #    }, | 
| 403 |  |  |  |  |  |  | #    class => "My::Schema::Result::Another", | 
| 404 |  |  |  |  |  |  | #    cond  => { | 
| 405 |  |  |  |  |  |  | #        "foreign.id" => "self.another_id" | 
| 406 |  |  |  |  |  |  | #    }, | 
| 407 |  |  |  |  |  |  | #    source => "My::Schema::Result::Another" | 
| 408 |  |  |  |  |  |  | #} | 
| 409 |  |  |  |  |  |  |  | 
| 410 |  |  |  |  |  |  | # has_one | 
| 411 |  |  |  |  |  |  | #{ | 
| 412 |  |  |  |  |  |  | #    attrs => { | 
| 413 |  |  |  |  |  |  | #        accessor       => "single", | 
| 414 |  |  |  |  |  |  | #        cascade_delete => 0, | 
| 415 |  |  |  |  |  |  | #        cascade_update => 1, | 
| 416 |  |  |  |  |  |  | #        is_depends_on  => 0, | 
| 417 |  |  |  |  |  |  | #        proxy          => [ "radusername_realm" ] | 
| 418 |  |  |  |  |  |  | #    }, | 
| 419 |  |  |  |  |  |  | #    class => "NAC::Model::DBIC::Table::View_Raduser", | 
| 420 |  |  |  |  |  |  | #    cond  => { | 
| 421 |  |  |  |  |  |  | #        "foreign.id_raduser" => "self.id_raduser" | 
| 422 |  |  |  |  |  |  | #    }, | 
| 423 |  |  |  |  |  |  | #    source => "NAC::Model::DBIC::Table::View_Raduser" | 
| 424 |  |  |  |  |  |  | #} | 
| 425 | 0 | 0 | 0 |  |  | 0 | if ( | 
|  |  |  | 0 |  |  |  |  | 
| 426 |  |  |  |  |  |  | $attrs->{is_foreign_key_constraint} | 
| 427 |  |  |  |  |  |  | && (   $attrs->{accessor} eq 'single' | 
| 428 |  |  |  |  |  |  | || $attrs->{accessor} eq 'filter' ) | 
| 429 |  |  |  |  |  |  | ) { | 
| 430 | 0 | 0 |  |  |  | 0 | if ( exists $field_by_colname{$our_col}->{reference}) { | 
| 431 |  |  |  |  |  |  | warn "$extjsname:\t$relname: relationship for column '$our_col' would overwrite '" | 
| 432 |  |  |  |  |  |  | . $field_by_colname{$our_col}->{reference}->{role} | 
| 433 | 0 |  |  |  |  | 0 | . "', skipping\n"; | 
| 434 | 0 |  |  |  |  | 0 | next; | 
| 435 |  |  |  |  |  |  | } | 
| 436 |  |  |  |  |  |  | # add reference to field definition | 
| 437 |  |  |  |  |  |  | $field_by_colname{$our_col}->{reference} = { | 
| 438 |  |  |  |  |  |  | type => $self->extjs_model_entityname( | 
| 439 | 0 | 0 |  |  |  | 0 | $self->extjs_model_name( $relinfo->{source} ) ), | 
| 440 |  |  |  |  |  |  | role => $relname, | 
| 441 |  |  |  |  |  |  | (defined $remote_relname | 
| 442 |  |  |  |  |  |  | ? (inverse => $remote_relname) | 
| 443 |  |  |  |  |  |  | : () | 
| 444 |  |  |  |  |  |  | ), | 
| 445 |  |  |  |  |  |  | }; | 
| 446 |  |  |  |  |  |  |  | 
| 447 |  |  |  |  |  |  | $field_by_colname{$our_col}->{allowBlank} = false() | 
| 448 |  |  |  |  |  |  | if exists $column_info->{is_nullable} | 
| 449 | 0 | 0 | 0 |  |  | 0 | and !$column_info->{is_nullable}; | 
| 450 |  |  |  |  |  |  |  | 
| 451 |  |  |  |  |  |  | $field_by_colname{$our_col}->{unique} = true() | 
| 452 |  |  |  |  |  |  | if $attrs->{accessor} eq 'single' | 
| 453 | 0 | 0 | 0 |  |  | 0 | && $attrs->{is_depends_on} == 0; | 
| 454 |  |  |  |  |  |  |  | 
| 455 |  |  |  |  |  |  | #$extjs_rel->{type} = 'belongsTo'; | 
| 456 |  |  |  |  |  |  | } | 
| 457 |  |  |  |  |  |  |  | 
| 458 |  |  |  |  |  |  | #{ | 
| 459 |  |  |  |  |  |  | #    attrs => { | 
| 460 |  |  |  |  |  |  | #        accessor       => "multi", | 
| 461 |  |  |  |  |  |  | #        cascade_copy   => 1, | 
| 462 |  |  |  |  |  |  | #        cascade_delete => 1, | 
| 463 |  |  |  |  |  |  | #        is_depends_on  => 0, | 
| 464 |  |  |  |  |  |  | #        join_type      => "LEFT" | 
| 465 |  |  |  |  |  |  | #    }, | 
| 466 |  |  |  |  |  |  | #    class => "My::Schema::Result::Basic", | 
| 467 |  |  |  |  |  |  | #    cond  => { | 
| 468 |  |  |  |  |  |  | #        "foreign.another_id" => "self.id" | 
| 469 |  |  |  |  |  |  | #    }, | 
| 470 |  |  |  |  |  |  | #    source => "My::Schema::Result::Basic" | 
| 471 |  |  |  |  |  |  | #} | 
| 472 |  |  |  |  |  |  | #elsif ( $attrs->{accessor} eq 'multi' ) { | 
| 473 |  |  |  |  |  |  | #    $extjs_rel->{type} = 'hasMany'; | 
| 474 |  |  |  |  |  |  | #} | 
| 475 |  |  |  |  |  |  | #push @assocs, $extjs_rel; | 
| 476 |  |  |  |  |  |  | } | 
| 477 | 0 |  |  |  |  | 0 | my $model = { | 
| 478 |  |  |  |  |  |  |  | 
| 479 |  |  |  |  |  |  | extend => $self->model_baseclass, | 
| 480 |  |  |  |  |  |  | alias => $self->extjs_model_alias($extjsname), | 
| 481 |  |  |  |  |  |  | requires => [ sort keys %requires ], | 
| 482 |  |  |  |  |  |  | }; | 
| 483 | 0 |  |  |  |  | 0 | my @pk = $rsrc->primary_columns; | 
| 484 | 0 | 0 |  |  |  | 0 | if ( @pk == 1 ) { | 
| 485 | 0 |  |  |  |  | 0 | $model->{idProperty} = $pk[0]; | 
| 486 |  |  |  |  |  |  | } | 
| 487 |  |  |  |  |  |  | else { | 
| 488 | 0 |  |  |  |  | 0 | warn | 
| 489 |  |  |  |  |  |  | "$extjsname:\tnot setting idProperty because number of primary key columns isn't one\n"; | 
| 490 |  |  |  |  |  |  | } | 
| 491 | 0 |  |  |  |  | 0 | my @fields; | 
| 492 |  |  |  |  |  |  |  | 
| 493 |  |  |  |  |  |  | # always keep the primary column as the first entry | 
| 494 |  |  |  |  |  |  | push @fields, delete $field_by_colname{ $model->{idProperty} } | 
| 495 | 0 | 0 |  |  |  | 0 | if exists $model->{idProperty}; | 
| 496 | 0 |  |  |  |  | 0 | push @fields, map { $field_by_colname{$_} } sort keys %field_by_colname; | 
|  | 0 |  |  |  |  | 0 |  | 
| 497 | 0 |  |  |  |  | 0 | $model->{fields} = \@fields; | 
| 498 |  |  |  |  |  |  |  | 
| 499 |  |  |  |  |  |  | #$model->{associations} = \@assocs | 
| 500 |  |  |  |  |  |  | #    if @assocs; | 
| 501 |  |  |  |  |  |  |  | 
| 502 |  |  |  |  |  |  | # override any generated config properties | 
| 503 | 0 | 0 |  |  |  | 0 | if ( $self->model_args ) { | 
| 504 | 0 |  |  |  |  | 0 | my %foo = ( %$model, %{ $self->model_args } ); | 
|  | 0 |  |  |  |  | 0 |  | 
| 505 | 0 |  |  |  |  | 0 | $model = \%foo; | 
| 506 |  |  |  |  |  |  | } | 
| 507 |  |  |  |  |  |  |  | 
| 508 | 0 |  |  |  |  | 0 | return [ $extjsname, $model ]; | 
| 509 |  |  |  |  |  |  | } | 
| 510 |  |  |  |  |  |  |  | 
| 511 |  |  |  |  |  |  |  | 
| 512 |  |  |  |  |  |  | sub extjs_models { | 
| 513 | 1 |  |  | 1 | 1 | 17804 | my $self = shift; | 
| 514 |  |  |  |  |  |  |  | 
| 515 | 1 |  |  |  |  | 23 | my $schema = $self->schema; | 
| 516 |  |  |  |  |  |  |  | 
| 517 | 0 |  |  |  |  | 0 | my %output; | 
| 518 | 0 |  |  |  |  | 0 | foreach my $rsrcname ( $schema->sources ) { | 
| 519 | 0 |  |  |  |  | 0 | my $extjs_model = $self->extjs_model($rsrcname); | 
| 520 |  |  |  |  |  |  |  | 
| 521 | 0 |  |  |  |  | 0 | $output{ $extjs_model->[0] } = $extjs_model; | 
| 522 |  |  |  |  |  |  | } | 
| 523 |  |  |  |  |  |  |  | 
| 524 | 0 |  |  |  |  | 0 | return \%output; | 
| 525 |  |  |  |  |  |  | } | 
| 526 |  |  |  |  |  |  |  | 
| 527 |  |  |  |  |  |  |  | 
| 528 |  |  |  |  |  |  | sub extjs_model_to_file { | 
| 529 | 2 |  |  | 2 | 1 | 17454 | my ( $self, $rsrcname, $dirname ) = @_; | 
| 530 |  |  |  |  |  |  |  | 
| 531 | 2 |  |  |  |  | 20 | my $dir = Path::Class::Dir->new($dirname); | 
| 532 | 2 | 100 |  |  |  | 126 | $dir->open | 
| 533 |  |  |  |  |  |  | or die "$!: " . $dirname; | 
| 534 |  |  |  |  |  |  |  | 
| 535 |  |  |  |  |  |  | my ( $extjs_model_name, $extjs_model_code ) = | 
| 536 | 1 |  |  |  |  | 73 | @{ $self->extjs_model($rsrcname) }; | 
|  | 1 |  |  |  |  | 20 |  | 
| 537 |  |  |  |  |  |  |  | 
| 538 | 0 |  |  |  |  | 0 | my @namespaces = split( /\./, $extjs_model_name ); | 
| 539 | 0 | 0 |  |  |  | 0 | die "model class '" | 
| 540 |  |  |  |  |  |  | . $namespaces[0] | 
| 541 |  |  |  |  |  |  | . "' doesn't match appname '" | 
| 542 |  |  |  |  |  |  | . $self->appname . "'" | 
| 543 |  |  |  |  |  |  | if $namespaces[0] ne $self->appname; | 
| 544 |  |  |  |  |  |  |  | 
| 545 | 0 |  |  |  |  | 0 | my $modeldir = $dir->subdir( @namespaces[ 1 .. $#namespaces - 1 ] ); | 
| 546 | 0 |  |  |  |  | 0 | $modeldir->mkpath; | 
| 547 |  |  |  |  |  |  |  | 
| 548 | 0 |  |  |  |  | 0 | my $filename = $namespaces[-1] . '.js'; | 
| 549 | 0 |  |  |  |  | 0 | my $file     = $modeldir->file($filename); | 
| 550 | 0 | 0 |  |  |  | 0 | my $fh       = $file->open( O_CREAT | O_WRONLY | O_EXCL ) | 
| 551 |  |  |  |  |  |  | #my $fh       = $file->open( O_TRUNC | O_WRONLY | O_EXCL ) | 
| 552 |  |  |  |  |  |  | or die "$!: $file"; | 
| 553 |  |  |  |  |  |  |  | 
| 554 |  |  |  |  |  |  | #$extjs_model_code->{classname} = $extjs_model_name; | 
| 555 |  |  |  |  |  |  | #my $template_vars = { | 
| 556 |  |  |  |  |  |  | #    classname => $extjs_model_name, | 
| 557 |  |  |  |  |  |  | #    attributes => $extjs_model_code, | 
| 558 |  |  |  |  |  |  | #}; | 
| 559 | 0 |  |  |  |  | 0 | my $json = | 
| 560 |  |  |  |  |  |  | #$self->_xslate->render_string($self->model_template, $template_vars); | 
| 561 |  |  |  |  |  |  | "Ext.define('$extjs_model_name', " | 
| 562 |  |  |  |  |  |  | . dump_javascript($extjs_model_code) | 
| 563 |  |  |  |  |  |  | . ');'; | 
| 564 |  |  |  |  |  |  | #. $self->_json->encode($extjs_model_code) | 
| 565 |  |  |  |  |  |  |  | 
| 566 | 0 |  |  |  |  | 0 | $fh->write($json . "\n"); | 
| 567 |  |  |  |  |  |  | } | 
| 568 |  |  |  |  |  |  |  | 
| 569 |  |  |  |  |  |  |  | 
| 570 |  |  |  |  |  |  | sub extjs_basemodel_to_file { | 
| 571 | 0 |  |  | 0 | 1 | 0 | my ( $self, $dirname ) = @_; | 
| 572 |  |  |  |  |  |  |  | 
| 573 | 0 |  |  |  |  | 0 | my $dir = Path::Class::Dir->new($dirname); | 
| 574 | 0 | 0 |  |  |  | 0 | $dir->open | 
| 575 |  |  |  |  |  |  | or die "$!: " . $dirname; | 
| 576 |  |  |  |  |  |  |  | 
| 577 | 0 |  |  |  |  | 0 | my @namespaces = split( /\./, $self->model_baseclass ); | 
| 578 | 0 | 0 |  |  |  | 0 | die "model base class '" | 
| 579 |  |  |  |  |  |  | . $namespaces[0] | 
| 580 |  |  |  |  |  |  | . "' doesn't match appname '" | 
| 581 |  |  |  |  |  |  | . $self->appname . "'" | 
| 582 |  |  |  |  |  |  | if $namespaces[0] ne $self->appname; | 
| 583 |  |  |  |  |  |  |  | 
| 584 | 0 |  |  |  |  | 0 | my $basemodeldir = $dir->subdir( @namespaces[ 1 .. $#namespaces - 1 ] ); | 
| 585 | 0 |  |  |  |  | 0 | $basemodeldir->mkpath; | 
| 586 |  |  |  |  |  |  |  | 
| 587 | 0 |  |  |  |  | 0 | my $filename = $namespaces[-1] . '.js'; | 
| 588 | 0 |  |  |  |  | 0 | my $file     = $basemodeldir->file($filename); | 
| 589 | 0 | 0 |  |  |  | 0 | my $fh       = $file->open( O_CREAT | O_WRONLY | O_EXCL ) | 
| 590 |  |  |  |  |  |  | #my $fh       = $file->open( O_TRUNC | O_WRONLY | O_EXCL ) | 
| 591 |  |  |  |  |  |  | or die "$!: $file"; | 
| 592 |  |  |  |  |  |  |  | 
| 593 | 0 |  |  |  |  | 0 | my $extjs_basemodel_code = { | 
| 594 |  |  |  |  |  |  | extend => 'Ext.data.Model', | 
| 595 |  |  |  |  |  |  | schema => { | 
| 596 |  |  |  |  |  |  | namespace => $self->model_namespace, | 
| 597 |  |  |  |  |  |  | }, | 
| 598 |  |  |  |  |  |  | }; | 
| 599 |  |  |  |  |  |  |  | 
| 600 | 0 |  |  |  |  | 0 | my $json = | 
| 601 |  |  |  |  |  |  | "Ext.define('" . $self->model_baseclass . "', " | 
| 602 |  |  |  |  |  |  | . dump_javascript($extjs_basemodel_code) . ');'; | 
| 603 |  |  |  |  |  |  |  | 
| 604 | 0 |  |  |  |  | 0 | $fh->write($json . "\n"); | 
| 605 | 0 | 0 |  |  |  | 0 | $fh->close | 
| 606 |  |  |  |  |  |  | or die "$!: " . $dirname; | 
| 607 |  |  |  |  |  |  | } | 
| 608 |  |  |  |  |  |  |  | 
| 609 |  |  |  |  |  |  |  | 
| 610 |  |  |  |  |  |  | sub extjs_all_to_file { | 
| 611 | 1 |  |  | 1 | 1 | 1239 | my ( $self, $dirname ) = @_; | 
| 612 |  |  |  |  |  |  |  | 
| 613 |  |  |  |  |  |  | # to check if the path exists and not fail for each source | 
| 614 | 1 | 50 |  |  |  | 6 | my $dh = Path::Class::Dir->new($dirname)->open | 
| 615 |  |  |  |  |  |  | or die "$!: $dirname"; | 
| 616 | 1 | 50 |  |  |  | 83 | $dh->close | 
| 617 |  |  |  |  |  |  | or die "$!: $dirname";; | 
| 618 |  |  |  |  |  |  |  | 
| 619 | 1 |  |  |  |  | 34 | my $schema = $self->schema; | 
| 620 |  |  |  |  |  |  |  | 
| 621 |  |  |  |  |  |  | try { | 
| 622 | 0 |  |  | 0 |  |  | $self->extjs_basemodel_to_file($dirname); | 
| 623 |  |  |  |  |  |  | } | 
| 624 |  |  |  | 0 |  |  | catch { | 
| 625 |  |  |  |  |  |  | # ignore fails | 
| 626 | 0 |  |  |  |  |  | }; | 
| 627 |  |  |  |  |  |  |  | 
| 628 | 0 |  |  |  |  |  | $self->extjs_model_to_file( $_, $dirname ) for sort $schema->sources; | 
| 629 |  |  |  |  |  |  | } | 
| 630 |  |  |  |  |  |  |  | 
| 631 |  |  |  |  |  |  |  | 
| 632 |  |  |  |  |  |  | 1; | 
| 633 |  |  |  |  |  |  |  | 
| 634 |  |  |  |  |  |  | __END__ |