v2.5.0
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 methodsmoduleInstall($module_name)andmoduleUninstall($module_name)have been added toDriverInterfaceandCoreInterface. Consumers that implement either interface directly must add both methods to their own classes - the simplest migration is to throwUnsupportedDriverActionException, matchingBaseDriver's default. Consumers that extendBaseDriver,DrupalDriver, orDrushDriverneed 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\RuntimeExceptionwhen 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+ switcheduser:informationoutput from"User ID : 123"key-value pairs to a bordered table, which previously causedDrushDriver::parseUserId()to always returnnulland 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 acrossDrupalDriver(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+FileHandlerpreviously extendedEntityReferenceHandlerand 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 thefile.repositoryservice, so tests can populate afilefield 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 aRuntimeExceptioninstead of being silently dropped. -
Added 'DaterangeHandler' with timezone-aware date formatting. @shrimala, @AlexSkrypnyk (#317)
The Drupal 8+daterangefield type is now a first-class citizen: the handler reads the site timezone fromsystem.date, converts datetime values to UTC storage, and picks the correct storage format based on the field'sdatetime_typesetting. Supports therelative:prefix, namedvalue/end_valuekeys, and positional indices. -
Added 'TimeHandler' for the 'time_field' contrib module. @ericgsmith, @AlexSkrypnyk (#306)
First-class support for thetime_fieldcontrib module. Numeric values are stored as seconds past midnight; string values like"9:30 AM","14:15:30", or"midnight"are parsed viastrtotime()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) plusBlackboxDriverandUnsupportedDriverActionException. 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 acrossAbstractHandler,EntityReferenceHandler, andDrupal8; extracts long methods inAddressHandler::expand(),DrupalDriver::getDrupalVersion(), andDrushDriver; and reshapesDaterangeHandlerto extendDatetimeHandlerso date-format logic lives in one place. No behaviour changes. -
Added project-level rector configuration and applied fixes. @AlexSkrypnyk (#328)
Replaces the fragilecp+cdworkaround that copiedpalantirnet/drupal-rector's config into thedrupal/directory with a project-levelrector.phptargeting PHP 7.4.composer lintandcomposer lint-fixnow invoke Rector directly, and the dead-code, code-quality, early-return, andinstanceofrule sets have been applied across 18 source and test files. -
Updated PHPCS configuration and fixed coding standards across the codebase. @AlexSkrypnyk (#327)
Replacesphpcs-ruleset.xmlwithphpcs.xmlthat applies both theDrupalandDrevOpsstandards via a newdrevops/phpcs-standarddev dependency. The DrevOps standard enforces snake_case locals and parameters anddataProvider*naming for test data providers; 358 general plus 311 snake_case fixes were applied, and CI now runslintandtestas separate steps. Strict-type declarations remain deferred to v3.x. -
Added .gitattributes for lean distribution archives. @AlexSkrypnyk (#326)
Adds a project.gitattributeswithexport-ignorerules socomposer installandgit archivepayloads contain onlycomposer.json,LICENSE,README.md,CHANGELOG.md, andsrc/, 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 theREADME.md(centred heading, grouped badges, driver comparison table, singlecomposer requireinstall step, cleaner usage example) and expandsCONTRIBUTING.mdwith 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+ switcheduser:informationoutput from"User ID : 123"key-value pairs to a bordered table, which previously causedDrushDriver::parseUserId()to always returnnulland 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 defaultdrushbinary is configured,DrushDrivernow triesCOMPOSER_BIN_DIR, thenvendor/bin/drushrelative to the current working directory, before falling back to the globaldrush. This avoids mismatches between the globally installed Drush and the Drush pinned by a project'scomposer.json. Resolution is extracted into a protectedresolveProjectDrush()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 Groupsog_standard_referencefield type. The entity-lookup logic is identical to a plain entity reference, so the handler is a thin subclass ofEntityReferenceHandler. -
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_codeis recognised explicitly, and unknown named keys raise\RuntimeExceptioninstead of being silently dropped. -
[#210] Skipped exception when deleting non-existent role. @bkosborne, @AlexSkrypnyk (#319)
Drupal8::roleDelete()no longer throws aRuntimeExceptionwhen 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 callsresetCache()on every entity type's access control handler in addition to the existingdrupal_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+daterangefield type, aligned withDatetimeHandler's timezone handling: usesDrupalDateTime, reads the site timezone fromsystem.date, converts datetime values to UTC storage, and picks the correct storage format based on the field'sdatetime_typesetting. Supports therelative:prefix, namedvalue/end_valuekeys, and positional indices. -
Added Alex Skrypnyk as maintainer. @AlexSkrypnyk (#316)
Addsalex@drevops.comas a maintainer incomposer.json, reflecting active stewardship of the library. -
Added 'moduleInstall()' and 'moduleUninstall()' to all drivers. @phenaproxima, @AlexSkrypnyk (#315)
IntroducesmoduleInstall($module_name)andmoduleUninstall($module_name)onDriverInterfaceandCoreInterface, wired up acrossDrupalDriver(delegates to the core),DrushDriver(usespm-enable/pm-uninstall --yes), andBaseDriver(throwsUnsupportedDriverActionException). All three cores -Drupal6,Drupal7, andDrupal8- implement the methods using their native module APIs. -
Implemented proper file handling in 'FileHandler'. @azurams, @AlexSkrypnyk (#314)
FileHandlerpreviously extendedEntityReferenceHandlerand tried a name-based entity lookup on raw file paths, which was incorrect for real file fields. It now extendsAbstractHandlerand implementsexpand()by reading the file from disk and creates a managed file entity via\Drupal::service('file.repository')->writeData(), writing to thepublic://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;nulltitles 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 keystitle,uri, andoptionsin 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 ofbatch_get()before callingbatch_process(), preventing a fatal error when tests triggerprocessBatch()without any queued batch operations. -
[#200] Fixed date-only field handling and simplified relative date logic. @ericgsmith, @AlexSkrypnyk (#309)
DatetimeHandlernow inspects the field'sdatetime_typesetting and stores date-only fields usingDATE_STORAGE_FORMATin the site timezone, rather than always applying a UTC-converted datetime format. The relative and explicit branches are unified: therelative:prefix is stripped first, then a single path picks the right storage format by field type, and both cases useDrupalDateTimefor proper timezone handling. -
[#291] Fixed 'EntityReferenceHandler' crash when entity label key is FALSE. @khiminrm, @AlexSkrypnyk (#308)
Entity types such ascommerce_licensedo not define a label key, which causedEntityReferenceHandler::expand()to build anorConditionGroupwith aFALSEfield name and crash the entity query. WhengetKey('label')returnsFALSE, the handler now falls back to an ID-only condition. -
[#293] Added 'SupportedImageHandler' for supported_image module. @chrisolof, @AlexSkrypnyk (#307)
New handler for thesupported_imagecontrib module's field type that mirrorsImageHandlerand adds the module's extra sub-fields:caption_value,caption_format,attribution_value, andattribution_format. -
Added 'TimeHandler' for the 'time_field' contrib module. @ericgsmith, @AlexSkrypnyk (#306)
New handler for thetime_fieldcontrib module. Numeric values pass through as seconds past midnight; string values like"9:30 AM","14:15:30", or"midnight"are parsed viastrtotime()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 inEntityReferenceHandlerwhen a non-numeric (string or title) value is used to look up an entity whose ID column is an integer - PostgreSQL rejects the mixed-typeORcondition 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