Resolving disclosures¶
Ask ai_disclosure.resolver rather than reading the field:
use Drupal\ai_disclosure\LabelRequirement;
$resolved = \Drupal::service('ai_disclosure.resolver')->resolve($entity);
if ($resolved !== NULL && $resolved->getLabelRequirement() === LabelRequirement::Required) {
// ...
}
resolve() returns an immutable ResolvedDisclosure, or NULL when the
entity has no effective disclosure. It carries the grade, the review flag,
the editorial responsibility, the description, the EU icon, the IPTC URI,
where the value came from, the scope assessment, and the verdict.
The verdict has three values¶
getLabelRequirement() returns a LabelRequirement: Required,
NotRequired or Undetermined. There is deliberately no boolean
accessor. A bool cannot carry the third value, and every caller that had
not been updated would have read "not assessed" as "not required" - the silent
no this API exists to prevent. Compare against the enum.
getDisclosureModality() returns a DisclosureModality: Standard,
Unobtrusive or Undetermined. It qualifies a Required verdict on the deep
fake branch, where an evidently artistic work limits the manner of the
disclosure without lifting it. DisclosureModality::effective() collapses
Undetermined to Standard, the form that discloses the most.
getScopeAssessment() returns the four answers the verdict was computed on, so
a caller can say which question is still open rather than only that the answer
is undetermined.
Cacheability¶
The object reports its own cacheability, so attaching it to a render array is
enough to have the page follow changes to the grade, the profile and the
field settings - as long as resolve() returned something to attach. A NULL
result carries none, which is wrong when the NULL itself depends on
configuration: a bundle with the field but no default profile set, for
instance, must stop rendering "nothing" once an administrator sets one.
For that case, use resolveWithCacheability() instead. It returns
['resolved' => ?ResolvedDisclosure, 'cacheability' => CacheableMetadata]:
the cacheability is populated even when resolved is NULL, so attach it to
the render array regardless. resolve() itself just discards it and stays
the right call for code that never caches its result.
Resolution itself is memoized: an entity is resolved at most once per
request, keyed on its ID, language and disclosure item value, so rendering
the same field twice - a formatter's view() and viewElements(), for
instance - does not resolve it twice. Call resetMemo() if you change
something the resolver reads outside of the item itself, such as a grade or
a profile, from code the module's own hook_entity_update() does not cover.
Broken references¶
A broken grade or profile reference never throws: resolution falls through to the next step and logs the dangling reference once per request. The compliance report surfaces the same dangling references in its configuration notices.
The same rule in SQL and in JavaScript¶
Two surfaces cannot call resolve(), so the rule is written twice more.
The report cannot resolve every row, so ai_disclosure.query_conditions
restates the resolution precedence as SQL conditions for the module's Views
filters. DisclosureQueryConditionsTest compares the two row by row over a
dataset covering every branch of the precedence.
The editing widget cannot make an AJAX request on every change, so
js/ai-disclosure-widget.js recomputes the status line as the editor works.
ResolvedDisclosure::labelVerdictFor() stays the definition. The other two
follow it, and a change to the rule is a change to all three.