Skip to content

v2.5.0

Choose a tag to compare

@github-actions github-actions released this 17 Apr 06:34
· 34 commits to refs/heads/master since this release
ff64e2d

What's new since v2.4.3

Important

This is the last 2.x release with Drupal 7 support. Only critical bug fixes will be worked on as patches for 2.5, if required.
We are working on 3.x, which will remove Drupal 6/7 support and potentially update some APIs.

Breaking changes

  • Added 'moduleInstall()' and 'moduleUninstall()' to all drivers. @phenaproxima, @AlexSkrypnyk (#315)
    New methods moduleInstall($module_name) and moduleUninstall($module_name) have been added to DriverInterface and CoreInterface. Consumers that implement either interface directly must add both methods to their own classes - the simplest migration is to throw UnsupportedDriverActionException, matching BaseDriver's default. Consumers that extend BaseDriver, DrupalDriver, or DrushDriver need no code changes; the parent classes already provide working implementations.

  • Rewrote 'AddressHandler' with named key support and multi-value handling. @BramDriesen, @daggerhart, @AlexSkrypnyk (#320)
    AddressHandler::expand() now returns one entry per delta for multi-value address fields (previously always a single-item array) and throws \RuntimeException when it receives an unrecognised named key (previously silently discarded). To migrate, audit any test data that passes associative address values and ensure every key is a valid address sub-field (given_name, family_name, organization, address_line1, address_line2, locality, administrative_area, postal_code, country_code), and update assertions that assumed a single delta for a multi-value address field.

Highlights

  • [#281] Fixed 'parseUserId()' to handle Drush 12+ table output format. @AlexSkrypnyk (#324)
    Drush 12+ switched user:information output from "User ID : 123" key-value pairs to a bordered table, which previously caused DrushDriver::parseUserId() to always return null and broke every user-related operation on newer Drush. The method now detects the table format and extracts the UID from the first data row while preserving backward compatibility with older Drush.

  • Added 'moduleInstall()' and 'moduleUninstall()' to all drivers. @phenaproxima, @AlexSkrypnyk (#315)
    Tests can now install and uninstall Drupal modules through the driver without dropping to Drush shell commands or raw PHP. The same API works across DrupalDriver (direct Drupal API), DrushDriver (Drush CLI), and all supported cores (Drupal 6, 7, and 8+).

  • Implemented proper file handling in 'FileHandler'. @azurams, @AlexSkrypnyk (#314)
    The Drupal 8+ FileHandler previously extended EntityReferenceHandler and tried a name-based entity lookup on raw file paths, which never produced a usable file entity. It now reads the file from disk and creates a managed file via the file.repository service, so tests can populate a file field by passing a local path.

  • Rewrote 'AddressHandler' with named key support and multi-value handling. @BramDriesen, @daggerhart, @AlexSkrypnyk (#320)
    Address fields can now be populated using descriptive named keys (given_name, address_line1, country_code, etc.) alongside positional numeric indices, and multi-value address fields correctly produce one delta per value instead of collapsing to a single item. Unknown keys fail loudly with a RuntimeException instead of being silently dropped.

  • Added 'DaterangeHandler' with timezone-aware date formatting. @shrimala, @AlexSkrypnyk (#317)
    The Drupal 8+ daterange field type is now a first-class citizen: the handler reads the site timezone from system.date, converts datetime values to UTC storage, and picks the correct storage format based on the field's datetime_type setting. Supports the relative: prefix, named value/end_value keys, and positional indices.

  • Added 'TimeHandler' for the 'time_field' contrib module. @ericgsmith, @AlexSkrypnyk (#306)
    First-class support for the time_field contrib module. Numeric values are stored as seconds past midnight; string values like "9:30 AM", "14:15:30", or "midnight" are parsed via strtotime() and converted to the storage format automatically.

  • Added 'NameHandler' for the Name module with tests. @sensespidey, @AlexSkrypnyk (#322)
    First-class support for the Name contrib module covering all six name components (title, given, middle, family, generational, credentials). Accepts the "Family, Given" shorthand string, named array keys, and positional indices, with multi-value field support.

All changes

  • Added PHPUnit tests for D8+ field handlers and exceptions. @AlexSkrypnyk (#331)
    Adds targeted PHPUnit coverage for the D8+ field handlers (Address, Daterange, Datetime, Default, EntityReference, File, Image, List*, SupportedImage, TaxonomyTermReference, TextWithSummary) plus BlackboxDriver and UnsupportedDriverActionException. Legacy D6/D7 sources are excluded from coverage measurement, and the CI coverage floor is raised from 10% to 35% to lock in the new D8+ baseline (39% lines).

  • Added PHPUnit code coverage reporting to CI with threshold enforcement. @AlexSkrypnyk (#330)
    Adds pcov-based coverage reporting on the PHP 8.4 / Drupal 11 matrix entry, uploads HTML, Cobertura, and text artifacts, posts a sticky per-PR coverage comment with a collapsible per-class breakdown, and fails the build when line coverage drops below a configurable threshold. Coverage regressions are now visible before merge.

  • Refactored codebase for readability: extracted methods, removed dead code, clarified naming. @AlexSkrypnyk (#329)
    Removes dead loops and unreachable branches across AbstractHandler, EntityReferenceHandler, and Drupal8; extracts long methods in AddressHandler::expand(), DrupalDriver::getDrupalVersion(), and DrushDriver; and reshapes DaterangeHandler to extend DatetimeHandler so date-format logic lives in one place. No behaviour changes.

  • Added project-level rector configuration and applied fixes. @AlexSkrypnyk (#328)
    Replaces the fragile cp+cd workaround that copied palantirnet/drupal-rector's config into the drupal/ directory with a project-level rector.php targeting PHP 7.4. composer lint and composer lint-fix now invoke Rector directly, and the dead-code, code-quality, early-return, and instanceof rule sets have been applied across 18 source and test files.

  • Updated PHPCS configuration and fixed coding standards across the codebase. @AlexSkrypnyk (#327)
    Replaces phpcs-ruleset.xml with phpcs.xml that applies both the Drupal and DrevOps standards via a new drevops/phpcs-standard dev dependency. The DrevOps standard enforces snake_case locals and parameters and dataProvider* naming for test data providers; 358 general plus 311 snake_case fixes were applied, and CI now runs lint and test as separate steps. Strict-type declarations remain deferred to v3.x.

  • Added .gitattributes for lean distribution archives. @AlexSkrypnyk (#326)
    Adds a project .gitattributes with export-ignore rules so composer install and git archive payloads contain only composer.json, LICENSE, README.md, CHANGELOG.md, and src/, dropping CI config, tests, Docker, specs, and docs tooling. Drupal scaffold is told not to overwrite the file.

  • Updated README and CONTRIBUTING to match DrupalExtension structure. @AlexSkrypnyk (#325)
    Modernises the README.md (centred heading, grouped badges, driver comparison table, single composer require install step, cleaner usage example) and expands CONTRIBUTING.md with a "How this project works" section, a field-handler reference table, a test-command table, and a v3.x roadmap pointer. Documentation-only change.

  • [#281] Fixed 'parseUserId()' to handle Drush 12+ table output format. @AlexSkrypnyk (#324)
    Drush 12+ switched user:information output from "User ID : 123" key-value pairs to a bordered table, which previously caused DrushDriver::parseUserId() to always return null and broke every user-related operation on newer Drush. The method now tries the legacy regex first and, on miss, walks the table rows to extract the UID from the first data row, preserving compatibility with older Drush.

  • Resolved project-level Drush binary in DrushDriver. @mxr576, @AlexSkrypnyk (#323)
    When the default drush binary is configured, DrushDriver now tries COMPOSER_BIN_DIR, then vendor/bin/drush relative to the current working directory, before falling back to the global drush. This avoids mismatches between the globally installed Drush and the Drush pinned by a project's composer.json. Resolution is extracted into a protected resolveProjectDrush() method that subclasses can override.

  • Added 'NameHandler' for the Name module with tests. @sensespidey, @AlexSkrypnyk (#322)
    New handler for the Name contrib module covering all six name components (title, given, middle, family, generational, credentials). Accepts the "Family, Given" shorthand string, named array keys, and positional numeric indices, with multi-value field support.

  • Added 'OgStandardReferenceHandler' for Organic Groups. @cheppers, @AlexSkrypnyk (#321)
    New handler for the Organic Groups og_standard_reference field type. The entity-lookup logic is identical to a plain entity reference, so the handler is a thin subclass of EntityReferenceHandler.

  • Rewrote 'AddressHandler' with named key support and multi-value handling. @BramDriesen, @daggerhart, @AlexSkrypnyk (#320)
    Address fields can now be populated using descriptive named keys (given_name, address_line1, country_code, etc.) alongside positional numeric arrays, and multi-value fields correctly produce one entry per delta instead of a single-item array. Hidden-field filtering now works (the previous associative-vs-sequential key bug is fixed), country_code is recognised explicitly, and unknown named keys raise \RuntimeException instead of being silently dropped.

  • [#210] Skipped exception when deleting non-existent role. @bkosborne, @AlexSkrypnyk (#319)
    Drupal8::roleDelete() no longer throws a RuntimeException when the target role does not exist, preventing spurious failures in test teardown when a role was never created in the first place.

  • Cleared EntityAccessControlHandler static cache in 'clearStaticCaches()'. @pfrenssen, @AlexSkrypnyk (#318)
    clearStaticCaches() now calls resetCache() on every entity type's access control handler in addition to the existing drupal_static_reset() and cache-tag resets, so stale access decisions from one test step cannot persist into a later one.

  • Added 'DaterangeHandler' with timezone-aware date formatting. @shrimala, @AlexSkrypnyk (#317)
    New handler for the Drupal 8+ daterange field type, aligned with DatetimeHandler's timezone handling: uses DrupalDateTime, reads the site timezone from system.date, converts datetime values to UTC storage, and picks the correct storage format based on the field's datetime_type setting. Supports the relative: prefix, named value/end_value keys, and positional indices.

  • Added Alex Skrypnyk as maintainer. @AlexSkrypnyk (#316)
    Adds alex@drevops.com as a maintainer in composer.json, reflecting active stewardship of the library.

  • Added 'moduleInstall()' and 'moduleUninstall()' to all drivers. @phenaproxima, @AlexSkrypnyk (#315)
    Introduces moduleInstall($module_name) and moduleUninstall($module_name) on DriverInterface and CoreInterface, wired up across DrupalDriver (delegates to the core), DrushDriver (uses pm-enable / pm-uninstall --yes), and BaseDriver (throws UnsupportedDriverActionException). All three cores - Drupal6, Drupal7, and Drupal8 - implement the methods using their native module APIs.

  • Implemented proper file handling in 'FileHandler'. @azurams, @AlexSkrypnyk (#314)
    FileHandler previously extended EntityReferenceHandler and tried a name-based entity lookup on raw file paths, which was incorrect for real file fields. It now extends AbstractHandler and implements expand() by reading the file from disk and creates a managed file entity via \Drupal::service('file.repository')->writeData(), writing to the public:// stream wrapper with a unique filename.

  • Added URI-only string support to 'LinkHandler'. @zolhorvath, @ohthehugemanatee, @AlexSkrypnyk (#313)
    LinkHandler::expand() now accepts a plain string as a URI-only link value and normalises it to ['uri' => $value] before further processing; null titles are stripped from the returned array. Mixed input (plain strings alongside full arrays) is handled correctly in a single call.

  • [#192] Allowed 'LinkHandler' to accept named field properties. @chrisolof, @AlexSkrypnyk (#311)
    LinkHandler::expand() now accepts named keys title, uri, and options in addition to the existing numeric-index format. Named keys take precedence via null-coalescing, so both input shapes remain supported without regressing existing tests.

  • Skipped processing empty batches in 'processBatch()'. @idimopoulos, @AlexSkrypnyk (#310)
    Drupal8::processBatch() now checks the return value of batch_get() before calling batch_process(), preventing a fatal error when tests trigger processBatch() without any queued batch operations.

  • [#200] Fixed date-only field handling and simplified relative date logic. @ericgsmith, @AlexSkrypnyk (#309)
    DatetimeHandler now inspects the field's datetime_type setting and stores date-only fields using DATE_STORAGE_FORMAT in the site timezone, rather than always applying a UTC-converted datetime format. The relative and explicit branches are unified: the relative: prefix is stripped first, then a single path picks the right storage format by field type, and both cases use DrupalDateTime for proper timezone handling.

  • [#291] Fixed 'EntityReferenceHandler' crash when entity label key is FALSE. @khiminrm, @AlexSkrypnyk (#308)
    Entity types such as commerce_license do not define a label key, which caused EntityReferenceHandler::expand() to build an orConditionGroup with a FALSE field name and crash the entity query. When getKey('label') returns FALSE, the handler now falls back to an ID-only condition.

  • [#293] Added 'SupportedImageHandler' for supported_image module. @chrisolof, @AlexSkrypnyk (#307)
    New handler for the supported_image contrib module's field type that mirrors ImageHandler and adds the module's extra sub-fields: caption_value, caption_format, attribution_value, and attribution_format.

  • Added 'TimeHandler' for the 'time_field' contrib module. @ericgsmith, @AlexSkrypnyk (#306)
    New handler for the time_field contrib module. Numeric values pass through as seconds past midnight; string values like "9:30 AM", "14:15:30", or "midnight" are parsed via strtotime() and converted to seconds past midnight automatically.

  • PostgreSQL crashes when trying to look up an entity reference field t… @svenbergryen (#305)
    Fixes a PostgreSQL-specific crash in EntityReferenceHandler when a non-numeric (string or title) value is used to look up an entity whose ID column is an integer - PostgreSQL rejects the mixed-type OR condition that MySQL silently accepts. The handler now skips the ID-based match for non-numeric inputs and matches by label only.

Full Changelog: v2.4.3...v2.5.0

@AlexSkrypnyk @azurams @bkosborne @BramDriesen @cheppers @chrisolof @daggerhart @ericgsmith @idimopoulos @khiminrm @mxr576 @ohthehugemanatee @pfrenssen @phenaproxima @sensespidey @shrimala @svenbergryen @zolhorvath