Skip to content

v3.2.0

Choose a tag to compare

@github-actions github-actions released this 23 Sep 17:57
· 19 commits to main since this release

What's Changed

Changed

  • Resizer is a service (#150) — registered as drupal_kit.resizer, with the seven \Drupal:: reaches replaced by injected dependencies. Resizer::resizer() stays as a thin static facade, so this is a MINOR and no consumer changes.

    #44 removed the service registration with the reason that "the class has no instance state". That stopped being true when the class grew a format-detection cache: ResizerFocalPointKernelTest::setUp() reset $outputFormat and $formatChecked by reflection, with a comment saying that without it "the getOutputFormat body inside this test class never runs". A test reaching into private static state to keep the next test honest was the evidence, sitting in the repository the whole time. Those nine lines are gone — a kernel test gets a fresh container, so the cache starts clean by construction.

    Measured before touching anything: nothing calls the static entry point. One caller inside the kit (TwigExtension), zero PHP callers across drupal-base, htdvere and proficio — all three reach it through the |resizer Twig filter. So the facade costs one delegation and keeps a promise RELEASING.md makes.

    focal_point.manager is injected with @? and the hash helper now guards on having received the service rather than on moduleExists(). The same correction #137 made in Requirements, for the same reason: one asks whether the container knows the module, the other whether this object holds the thing it is about to call.

    TwigExtension takes the service as a trailing optional constructor argument, which RELEASING.md § Public API surface classifies as MINOR. getResizer() also stops being declared static — it was registered as [$this, 'getResizer'], so PHP was already calling it on an instance and the declaration simply disagreed with the call site.

    Two behaviour changes on the facade, worth stating plainly. It fetches the service before the input guards run, so Resizer::resizer([], []) now needs a container where it used to answer without one. And it needs this module installed: the old body reached only core services, so the class worked in any container where it autoloaded — a kernel test listing just system, file and image, for instance. An uninstalled drupal_kit now raises ServiceNotFoundException. Neither matters in production, where both hold by definition; the second was found by review, not by me.

    The unit tests build the service instead of calling the facade, which is what a unit test should have been doing anyway.

    TwigExtensionTest now asserts delegation. The old case passed an SVG and checked the single-item list came back unchanged, which exercised Resizer's passthrough and said nothing about TwigExtension: a method that ignored its arguments and returned the input would have passed too.

Added

  • DisplayBase::create() and the focal-point hash have tests (#148) — both were gaps the tracker did not record, and both were self-concealing.

    DisplayBase sat at 13% line coverage while __call had fourteen cases. The uncovered half was the constructor and create(), and DisplayBaseKernelTest hid it: it builds its subject with new class(...), listing the same thirteen arguments in the same order create() does, so the test carried its own copy of the ordering it was meant to protect. Reordering create() left it green.

    The ordering matters because $entity_helper is untyped — the type lives only in the docblock. Swapping two typed services is a TypeError; swapping that one is silent, and the class asks the wrong service for the rest of its life. DisplayBase is a base class consumers extend, so the failure would surface in their project, not here. Mutation-checked: current_route_match ↔ language_manager is caught by PHP itself, drupal_kit.entity_helper → drupal_kit.media_array_builder only by the new test.

    ResizerFocalPointKernelTest carried a docblock saying the non-empty-hash branch was "left as a follow-up". It is followed up. The hash is the cache-busting mechanism: Drupal keys a derivative by image style name, so without the suffix an editor who moves the focal point is served the old crop until someone flushes image styles — a silent regression that reads as a caching problem. The tests assert behaviour rather than recomputing md5() against the implementation: no crop means no suffix, two positions give two ids, the same position gives the same id, all read off the generated URL rather than by reflecting into the private helper.

Pull Requests

  • #149 — test: cover DisplayBase::create() and the focal-point hash
  • #152 — refactor(resizer): make Resizer a service, keep the static as a facade

Full Changelog: v3.1.0...v3.2.0