1 package DBIx::Class::MethodAttributes;
6 use DBIx::Class::_Util qw( uniq refdesc visit_namespaces );
7 use Scalar::Util qw( weaken refaddr );
11 my ( $attr_cref_registry, $attr_cache_active );
12 sub DBIx::Class::__Attr_iThreads_handler__::CLONE {
14 # This is disgusting, but the best we can do without even more surgery
15 # Note the if() at the end - we do not run this crap if we can help it
16 visit_namespaces( action => sub {
19 # skip dangerous namespaces
20 return 1 if $pkg =~ /^ (?:
21 DB | next | B | .+? ::::ISA (?: ::CACHE ) | Class::C3
27 exists ${"${pkg}::"}{__cag___attr_cache}
29 ref( my $attr_stash = ${"${pkg}::__cag___attr_cache"} ) eq 'HASH'
31 $attr_stash->{ $attr_cref_registry->{$_}{weakref} } = delete $attr_stash->{$_}
32 for keys %$attr_stash;
36 }) if $attr_cache_active;
38 # renumber the cref registry itself
39 %$attr_cref_registry = map {
40 ( defined $_->{weakref} )
42 # because of how __attr_cache works, ugh
43 "$_->{weakref}" => $_,
46 } values %$attr_cref_registry;
49 sub MODIFY_CODE_ATTRIBUTES {
55 $_ =~ /^[a-z]+$/ ? 'builtin'
56 : $_ =~ /^DBIC_/ ? 'dbic'
62 defined $attr_cref_registry->{$_}{weakref} or delete $attr_cref_registry->{$_}
63 for keys %$attr_cref_registry;
65 # The original misc-attr API used stringification instead of refaddr - can't change that now
66 if( $attr_cref_registry->{$code} ) {
67 Carp::confess( sprintf
68 "Coderefs '%s' and '%s' stringify to the same value '%s': nothing will work",
70 refdesc($attr_cref_registry->{$code}{weakref}),
72 ) if refaddr($attr_cref_registry->{$code}{weakref}) != refaddr($code);
75 weaken( $attr_cref_registry->{$code}{weakref} = $code )
79 # increment the pkg gen, this ensures the sanity checkers will re-evaluate
80 # this class when/if the time comes
81 mro::method_changed_in($class) if (
82 ! DBIx::Class::_ENV_::OLD_MRO
84 ( $attrs->{dbic} or $attrs->{misc} )
89 if( $attrs->{misc} ) {
91 # if the user never tickles this - we won't have to do a gross
92 # symtable scan in the ithread handler above, so:
94 # User - please don't tickle this
95 $attr_cache_active = 1;
97 $class->mk_classaccessor('__attr_cache' => {})
98 unless $class->can('__attr_cache');
100 $class->__attr_cache->{$code} = [ sort( uniq(
101 @{ $class->__attr_cache->{$code} || [] },
102 keys %{ $attrs->{misc} },
107 # handle DBIC_* attrs
108 if( $attrs->{dbic} ) {
109 my $slot = $attr_cref_registry->{$code};
111 $slot->{attrs} = [ uniq
112 @{ $slot->{attrs} || [] },
114 $class->VALID_DBIC_CODE_ATTRIBUTE($_)
116 Carp::confess( "DBIC-specific attribute '$_' did not pass validation by $class->VALID_DBIC_CODE_ATTRIBUTE() as described in DBIx::Class::MethodAttributes" )
117 } keys %{$attrs->{dbic}},
122 # FIXME - DBIC essentially gobbles up any attribute it can lay its hands on:
125 # There should be some sort of warning on unrecognized attributes or
126 # somesuch... OTOH people do use things in the wild hence the plan of action
127 # is anything but clear :/
129 # https://metacpan.org/source/ZIGOROU/DBIx-Class-Service-0.02/lib/DBIx/Class/Service.pm#L93-110
130 # https://metacpan.org/source/ZIGOROU/DBIx-Class-Service-0.02/t/lib/DBIC/Test/Service/User.pm#L29
131 # https://metacpan.org/source/ZIGOROU/DBIx-Class-Service-0.02/t/lib/DBIC/Test/Service/User.pm#L36
133 # For the time being reuse the old logic for any attribute we do not have
134 # explicit plans for (i.e. stuff that is neither reserved, nor DBIC-internal)
136 # Pass the "builtin attrs" onwards, as the DBIC internals can't possibly handle them
137 return sort keys %{ $attrs->{builtin} || {} };
140 # Address the above FIXME halfway - if something (e.g. DBIC::Helpers) wants to
141 # add extra attributes - it needs to override this in its base class to allow
142 # for 'return 1' on the newly defined attributes
143 sub VALID_DBIC_CODE_ATTRIBUTE {
144 #my ($class, $attr) = @_;
147 ### !!! IMPORTANT !!!
149 ### *DO NOT* yield to the temptation of using free-form-argument attributes.
150 ### The technique was proven instrumental in Catalyst a decade ago, and
151 ### was more recently revived in Sub::Attributes. Yet, while on the surface
152 ### they seem immensely useful, per-attribute argument lists are in fact an
153 ### architectural dead end.
155 ### In other words: you are *very strongly urged* to ensure the regex below
156 ### does not allow anything beyond qr/^ DBIC_method_is_ [A-Z_a-z0-9]+ $/x
159 $_[1] =~ /^ DBIC_method_is_ (?:
162 (?: bypassable | mandatory ) _resultsource_proxy
164 generated_from_resultsource_metadata
166 (?: inflated_ | filtered_ )? column_ (?: extra_)? accessor
168 single_relationship_accessor
170 (?: multi | filter ) _relationship_ (?: extra_ )? accessor
172 proxy_to_relationship
174 m2m_ (?: extra_)? sugar (?:_with_attrs)?
178 sub FETCH_CODE_ATTRIBUTES {
179 #my ($class,$code) = @_;
182 @{ $_[0]->_attr_cache->{$_[1]} || [] },
183 ( defined( $attr_cref_registry->{$_[1]}{ weakref } )
184 ? @{ $attr_cref_registry->{$_[1]}{attrs} || [] }
193 %{ $self->can('__attr_cache') ? $self->__attr_cache : {} },
194 %{ $self->maybe::next::method || {} },
204 DBIx::Class::MethodAttributes - DBIC-specific handling of CODE attributes
208 my @attrlist = attributes::get( \&My::App::Schema::Result::some_method )
212 This class provides the L<DBIx::Class> inheritance chain with the bits
213 necessary for L<attribute|attributes> support on methods.
215 Historically DBIC has accepted any string as a C<CODE> attribute and made
216 such strings available via the semi-private L</_attr_cache> method. This
217 was used for e.g. the long-deprecated L<DBIx::Class::ResultSetManager>,
218 but also has evidence of use on both C<CPAN> and C<DarkPAN>.
220 Starting mid-2016 DBIC treats any method attribute starting with C<DBIC_>
221 as an I<internal boolean decorator> for various DBIC-related methods.
222 Unlike the general attribute naming policy, strict whitelisting is imposed
223 on attribute names starting with C<DBIC_> as described in
224 L</VALID_DBIC_CODE_ATTRIBUTE> below.
226 =head2 DBIC-specific method attributes
228 The following method attributes are currently recognized under the C<DBIC_*>
231 =head3 DBIC_method_is_indirect_sugar
233 The presence of this attribute indicates a helper "sugar" method. Overriding
234 such methods in your subclasses will be of limited success at best, as DBIC
235 itself and various plugins are much more likely to invoke alternative direct
236 call paths, bypassing your override entirely. Good examples of this are
237 L<DBIx::Class::ResultSet/create> and L<DBIx::Class::Schema/connect>.
240 L<DBIx::Class::Schema::SanityChecker/no_indirect_method_overrides>.
242 =head3 DBIC_method_is_mandatory_resultsource_proxy
244 =head3 DBIC_method_is_bypassable_resultsource_proxy
246 The presence of one of these attributes on a L<proxied ResultSource
247 method|DBIx::Class::Manual::ResultClass/DBIx::Class::ResultSource> indicates
248 how DBIC will behave when someone calls e.g.:
250 $some_result->result_source->add_columns(...)
252 as opposed to the conventional
254 SomeResultClass->add_columns(...)
256 This distinction becomes important when someone declares a sub named after
257 one of the (currently 22) methods proxied from a
258 L<Result|DBIx::Class::Manual::ResultClass> to
259 L<ResultSource|DBIx::Class::ResultSource>. While there are obviously no
260 problems when these methods are called at compile time, there is a lot of
261 ambiguity whether an override of something like
262 L<columns_info|DBIx::Class::ResultSource/columns_info> will be respected by
263 DBIC and various plugins during runtime operations.
265 It must be noted that there is a reason for this weird situation: during the
266 original design of DBIC the "ResultSourceProxy" system was established in
267 order to allow easy transition from Class::DBI. Unfortunately it was not
268 well abstracted away: it is rather difficult to use a custom ResultSource
269 subclass. The expansion of the DBIC project never addressed this properly
270 in the years since. As a result when one wishes to override a part of the
271 ResultSource functionality, the overwhelming practice is to hook a method
272 in a Result class and "hope for the best".
274 The subtle changes of various internal call-chains in C<DBIC v0.0829xx> make
275 this silent uncertainty untenable. As a solution any such override will now
276 issue a descriptive warning that it has been bypassed during a
277 C<< $rsrc->overridden_function >> invocation. A user B<must> determine how
278 each individual override must behave in this situation, and tag it with one
279 of the above two attributes.
281 Naturally any override marked with C<..._bypassable_resultsource_proxy> will
282 behave like it did before: it will be silently ignored. This is the attribute
283 you want to set if your code appears to work fine, and you do not wish to
284 receive the warning anymore (though you are strongly encouraged to understand
287 However overrides marked with C<..._mandatory_resultsource_proxy> will always
288 be reinvoked by DBIC itself, so that any call of the form:
290 $some_result->result_source->columns_info(...)
292 will be transformed into:
294 $some_result->result_source->result_class->columns_info(...)
296 with the rest of the callchain flowing out of that (provided the override did
297 invoke L<next::method|mro/next::method> where appropriate)
299 =head3 DBIC_method_is_generated_from_resultsource_metadata
301 This attribute is applied to all methods dynamically installed after various
302 invocations of L<ResultSource metadata manipulation
303 methods|DBIx::Class::Manual::ResultClass/DBIx::Class::ResultSource>. Notably
304 this includes L<add_columns|DBIx::Class::ResultSource/add_columns>,
305 L<add_relationship|DBIx::Class::ResultSource/add_relationship>,
306 L<the proxied relationship attribute|DBIx::Class::Relationship::Base/proxy>
307 and the various L<relationship
308 helpers|DBIx::Class::Manual::ResultClass/DBIx::Class::Relationship>,
309 B<except> the L<M2M helper|DBIx::Class::Relationship/many_to_many> (given its
310 effects are never reflected as C<ResultSource metadata>).
312 =head3 DBIC_method_is_column_accessor
314 This attribute is applied to all methods dynamically installed as a result of
315 invoking L<add_columns|DBIx::Class::ResultSource/add_columns>.
317 =head3 DBIC_method_is_inflated_column_accessor
319 This attribute is applied to all methods dynamically installed as a result of
320 invoking L<inflate_column|DBIx::Class::InflateColumn/inflate_column>.
322 =head3 DBIC_method_is_filtered_column_accessor
324 This attribute is applied to all methods dynamically installed as a result of
325 invoking L<filter_column|DBIx::Class::FilterColumn/filter_column>.
327 =head3 DBIC_method_is_*column_extra_accessor
329 For historical reasons any L<Class::Accessor::Grouped> accessor is generated
330 twice as C<{name}> and C<_{name}_accessor>. The second method is marked with
331 C<DBIC_method_is_*column_extra_accessor> correspondingly.
333 =head3 DBIC_method_is_single_relationship_accessor
335 This attribute is applied to all methods dynamically installed as a result of
336 invoking L<might_have|DBIx::Class::Relationship/might_have>,
337 L<has_one|DBIx::Class::Relationship/has_one> or
338 L<belongs_to|DBIx::Class::Relationship/belongs_to> (though for C<belongs_to>
339 see L<...filter_rel...|/DBIC_method_is_filter_relationship_accessor> below.
341 =head3 DBIC_method_is_multi_relationship_accessor
343 This attribute is applied to the main method dynamically installed as a result
344 of invoking L<has_many|DBIx::Class::Relationship/has_many>.
346 =head3 DBIC_method_is_multi_relationship_extra_accessor
348 This attribute is applied to the two extra methods dynamically installed as a
349 result of invoking L<has_many|DBIx::Class::Relationship/has_many>:
350 C<$relname_rs> and C<add_to_$relname>.
352 =head3 DBIC_method_is_filter_relationship_accessor
354 This attribute is applied to (legacy) methods dynamically installed as a
355 result of invoking L<belongs_to|DBIx::Class::Relationship/belongs_to> with an
356 already-existing identically named column. The method is internally
357 implemented as an L<inflated_column|/DBIC_method_is_inflated_column_accessor>
358 and is labeled with both atributes at the same time.
360 =head3 DBIC_method_is_filter_relationship_extra_accessor
362 Same as L</DBIC_method_is_*column_extra_accessor>.
364 =head3 DBIC_method_is_proxy_to_relationship
366 This attribute is applied to methods dynamically installed as a result of
367 providing L<the proxied relationship
368 attribute|DBIx::Class::Relationship::Base/proxy>.
370 =head3 DBIC_method_is_m2m_sugar
372 =head3 DBIC_method_is_m2m_sugar_with_attrs
374 One of the above attributes is applied to the main method dynamically
375 installed as a result of invoking
376 L<many_to_many|DBIx::Class::Relationship/many_to_many>. The C<_with_atrs> suffix
377 serves to indicate whether the user supplied any C<\%attrs> to the
378 C<many_to_many> call. There is deliberately no mechanism to retrieve the actual
379 supplied values: if you really need this functionality you would need to rely on
380 L<DBIx::Class::IntrospectableM2M>.
382 =head3 DBIC_method_is_extra_m2m_sugar
384 =head3 DBIC_method_is_extra_m2m_sugar_with_attrs
386 One of the above attributes is applied to the extra B<four> methods dynamically
387 installed as a result of invoking
388 L<many_to_many|DBIx::Class::Relationship/many_to_many>: C<$m2m_rs>, C<add_to_$m2m>,
389 C<remove_from_$m2m> and C<set_$m2m>.
393 =head2 MODIFY_CODE_ATTRIBUTES
395 See L<attributes/MODIFY_type_ATTRIBUTES>.
397 =head2 FETCH_CODE_ATTRIBUTES
399 See L<attributes/FETCH_type_ATTRIBUTES>. Always returns the combination of
400 all attributes: both the free-form strings registered via the
401 L<legacy system|/_attr_cache> and the DBIC-specific ones.
403 =head2 VALID_DBIC_CODE_ATTRIBUTE
407 =item Arguments: $attribute_string
409 =item Return Value: ( true| false )
413 This method is invoked when processing each DBIC-specific attribute (the ones
414 starting with C<DBIC_>). An attribute is considered invalid and an exception
415 is thrown unless this method returns a C<truthy> value.
421 =item Arguments: none
423 =item Return Value: B<purposefully undocumented>
427 The legacy method of retrieving attributes declared on DBIC methods
428 (L</FETCH_CODE_ATTRIBUTES> was not defined until mid-2016). This method
429 B<does not return any DBIC-specific attributes>, and is kept for backwards
432 In order to query the attributes of a particular method use
433 L<attributes::get()|attributes/get> as shown in the L</SYNOPSIS>.
435 =head1 FURTHER QUESTIONS?
437 Check the list of L<additional DBIC resources|DBIx::Class/GETTING HELP/SUPPORT>.
439 =head1 COPYRIGHT AND LICENSE
441 This module is free software L<copyright|DBIx::Class/COPYRIGHT AND LICENSE>
442 by the L<DBIx::Class (DBIC) authors|DBIx::Class/AUTHORS>. You can
443 redistribute it and/or modify it under the same terms as the
444 L<DBIx::Class library|DBIx::Class/COPYRIGHT AND LICENSE>.