Skip to content

Cakephp 5 upgrade #327

Open
wants to merge 5 commits into
base: develop
Choose a base branch
from
Open

Conversation

Ioannis
Copy link
Contributor

@Ioannis Ioannis commented Aug 14, 2025

Important changes:

  • ORM: order to orderBy,

example:

- ->order(['EnrollmentFlowSteps.ordr' => 'ASC'])
+ ->orderBy(['EnrollmentFlowSteps.ordr' => 'ASC'])
  • ORM: get() now uses named parameters instead of positional

example:

- $linkObj = $linkTable->get($link->value, ['contain' => $contain]);
+ $linkObj = $linkTable->get($link->value, contain: $contain);
  • Returning values from event listeners / callbacks is deprecated. Use $event->setResult() instead or $event->stopPropogation() to just stop the event propagation.

example:

         if($controller->calculatePermission()) {
           - return true;
           + $event->setResult(true);
            return;
          }
  • pagination results need to be called through items

example:

   - while($rs->valid()) {
   -   $o = $rs->current();
   + while($rs->items()->valid()) {
   +   $o = $rs->items()->current();
  • use the AllowDynamicProperties for the classes that construct dynamic properties

example:

+ [\AllowDynamicProperties]
class CousController extends StandardController {
  • Loading a component is not enough. First we load the component and we return it afterwards

example

    // COmanage specific component that handles authn/z processintg
   - $this->loadComponent('RegistryAuth');
   + $this->RegistryAuth = $this->components()->get('RegistryAuth');

@Ioannis Ioannis force-pushed the cakephp-5-upgrade branch 3 times, most recently from 4511779 to d5209e3 Compare August 18, 2025 08:03
@Ioannis
Copy link
Contributor Author

Ioannis commented Aug 31, 2025

CakePHP 4 → 5 Upgrade Developer Guideline

Scope

  • This document summarizes required source changes and checks to migrate this repository from CakePHP 4.x to 5.x, based on CakePHP official upgrade notes and patterns detected in this codebase.
  • No code changes are applied by this document. Use it as a checklist and reference while performing the upgrade.

References

Repository-specific hotspots (found using IDE scan)

  • ORM order(): multiple usages in app/src and plugins
    • app/src/Lib/Traits/AutoViewVarsTrait.php: lines ~194, ~196
    • app/src/Model/Table/EnrollmentFlowsTable.php: ~204, ~215
    • app/src/Model/Table/NamesTable.php: ~350, ~359
    • app/src/Model/Table/ProvisioningTargetsTable.php: ~156, ~280
    • app/src/Lib/Util/PaginatedSqlIterator.php: ~171
    • app/src/Model/Table/AddressesTable.php: ~184
    • app/src/Model/Table/CousTable.php: ~271
    • app/src/Model/Table/GroupNestingsTable.php: ~180
    • app/src/Model/Table/GroupsTable.php: ~1118
    • app/src/Model/Table/IdentifierAssignmentsTable.php: ~201
    • app/src/Model/Table/PetitionsTable.php: ~769
    • app/src/Model/Table/PipelinesTable.php: ~568
    • app/src/Model/Table/PluginsTable.php: ~215
    • app/src/Model/Table/TrafficDetoursTable.php: ~110
    • Plugins (examples):
    • availableplugins/PipelineToolkit/.../PersonRoleMappersTable.php: ~112
    • plugins/CoreEnroller/.../AttributeCollectorsTable.php: ~445
    • plugins/CoreEnroller/.../EmailVerifiersTable.php: ~192
    • plugins/CoreEnroller/.../AttributeCollectorsCell.php: ~84
  • Pagination: using ResultSet methods directly
    • app/src/Controller/Component/RegistryAuthComponent.php: ~576 has while ($rs->valid())
    • local/logs/debug.log contains deprecation notices advising use of items()
  • get() named parameters vs positional
    • Widespread usage of ->get(…) across controllers/components/tables. Review all entity fetches using Table::get().
  • Dynamic properties
    • Classes extending Cake core types often allow dynamic properties. Add #[\AllowDynamicProperties] (or declare properties) to our classes that set properties dynamically.
  • Event listeners / callbacks
    • Audit any return values in events; use $event->setResult() or $event->stopPropagation().

Checklist and code patterns to change

  1. ORM: order() → orderBy()
  • CakePHP 5 deprecates Query::order() in favor of orderBy(). Replace everywhere in application code (do not change vendor files).
  • Before:
$query = $table->find()->order(['EnrollmentFlowSteps.ordr' => 'ASC']);
  • After:
$query = $table->find()->orderBy(['EnrollmentFlowSteps.ordr' => 'ASC']);
  • Notes:
    • For calls with a second boolean parameter (to overwrite ordering), use:
    • Before: ->order(['name' => 'ASC'], true);
    • After: ->orderBy(['name' => 'ASC'], true);
      • For simple sorting arrays (without explicit ASC/DESC), keep semantics identical:
    • Before: ->order(['Names.family', 'Names.given'])
    • After: ->orderBy(['Names.family', 'Names.given'])
  1. Table::get() named parameters
  • CakePHP 5 changes method signatures to use named parameters for optional args.
  • Before:
$entity = $Table->get($id, ['contain' => $contain, 'fields' => $fields]);
  • After:
$entity = $Table->get($id, contain: $contain, fields: $fields);
  • Common places:
    • Controllers, Components (eg RegistryAuthComponent), and Tables calling other tables via TableLocator.
  • Also review other methods that adopted named parameters, e.g., delete(), save(), findList options, etc., following the migration guide.
  1. Events: returning values from listeners/callbacks is deprecated
  • Do not return values to communicate results. Instead set on the event.
  • Before:
public function beforeSave(EventInterface $event, EntityInterface $entity, ArrayObject $options)
{
  if ($this->needsSkip($entity)) {
    return false; // or return true / return $response
  }
}
  • After:
public function beforeSave(EventInterface $event, EntityInterface $entity, ArrayObject $options)
{
  if ($this->needsSkip($entity)) {
    $event->setResult(false); // or set desired value
    $event->stopPropagation(); // optional: only if you intend to stop other listeners
    return; // explicitly return void
  }
}
  • Controller events similarly should use $event->setResult($value) and return; If the intent is only to halt propagation, call $event->stopPropagation().
  • Then, where you trigger or check event results, use $event->getResult().
  1. Pagination result iteration: use items()
  • In CakePHP 5.1+, calling Cake\ORM\ResultSet methods directly on paginated results is deprecated. Use items().
  • Before:
$rs = $this->paginate($query);
while ($rs->valid()) {
  $o = $rs->current();
  $rs->next();
}
  • After:
$rs = $this->paginate($query);
while ($rs->items()->valid()) {
  $o = $rs->items()->current();
  $rs->items()->next();
}
  • Repository hotspot: RegistryAuthComponent around line ~576.
  1. Dynamic properties: add #[AllowDynamicProperties] or declare properties
  • PHP 8.2 deprecates dynamic properties. Cake 5 runtime warns if you set undeclared properties on app classes.
  • Options per class:
    a) Declare the property explicitly: public ?Type $Foo = null;
    b) Add attribute: #[\AllowDynamicProperties] above the class definition.
  • Before:
class CousController extends StandardController {
    // somewhere: $this->SomeTable = $this->fetchTable('Some');
}
  • After:
#[\AllowDynamicProperties]
class CousController extends StandardController {
    // or declare public properties explicitly
}
  • Where to apply:
    • Controllers, Components, Cells, Helpers, Table classes, Behaviors, and any custom classes where new properties are assigned dynamically (eg via ModelAware/ModelAwareTrait setModelClass, $this->Foo = ...).
  • Tip: Review log notice “Dynamic properties will be removed in PHP 8.2” and code using $this->X = … assignments.
  1. Other frequent Cake 4 → 5 adjustments
  • Query builder method renames/behavior tweaks:
    • group() → groupBy() also exists; check if used in your code and upgrade similarly.
    • Having/order direction expressions still work; but favor Expressions API consistently.
  • Controller::redirect() and Response changes: ensure type checks use Psr\Http\Message\ResponseInterface where appropriate.
  • MiddlewareQueue signatures and callable types may be stricter; update type hints.
  • Command/Shell migrations: Shell is removed/replaced by Command; if custom Shells exist in repo, migrate to Command classes.
  • Http exceptions and status methods often now return new immutable responses; avoid mutating Response in place.

Search-and-Replace plan (do not apply to vendor/):

  1. order( → orderBy(
    • Scope: app/src, app/plugins, app/availableplugins
    • Exclude: app/vendor
    • Manually verify usages with second overwrite parameter.
  2. get( calls with options array → named params
    • Pattern: $Table->get($id, [ ... ])
    • Replace with $Table->get($id, optionName: value, …)
    • Common option names: contain, fields, conditions, lock, forUpdate
  3. Event listeners returning values
    • Replace return true/false/value in event handlers with $event->setResult(value); and return; optionally stopPropagation().
    • Check beforeFilter, beforeRender, beforeRedirect, beforeSave, beforeFind, etc.
  4. Paginator result iteration
    • Replace $rs->valid()/current()/next() with $rs->items()->… or foreach ($rs as $row).
  5. Dynamic properties
    • For classes assigning properties dynamically, add #[\AllowDynamicProperties] or declare properties.

Examples from this repo (before → after)

  • EnrollmentFlowSteps ordering:
->order(['EnrollmentFlowSteps.ordr' => 'ASC'])
→ ->orderBy(['EnrollmentFlowSteps.ordr' => 'ASC'])
  • Petitions/steps chain:
->order(['EnrollmentFlowSteps.ordr'])
→ ->orderBy(['EnrollmentFlowSteps.ordr'])
  • Names natural sort:
->order(['Names.family', 'Names.given', 'Names.middle'])
→ ->orderBy(['Names.family', 'Names.given', 'Names.middle'])
  • Overwriting order:
->order(['name' => 'ASC'], true)
→ ->orderBy(['name' => 'ASC'], true)
  • Table::get with contain:
$linkObj = $linkTable->get($link->value, ['contain' => $contain]);
→ $linkObj = $linkTable->get($link->value, contain: $contain);
  • Pagination iteration:
while($rs->valid()) { $o = $rs->current(); /* … */ }
→ while($rs->items()->valid()) { $o = $rs->items()->current(); /* … */ }
  • Event listener pattern:
if ($controller->calculatePermission()) {
  // return true; (deprecated)
  $event->setResult(true);
  return;
}
  • Dynamic properties:
#[\AllowDynamicProperties]
class CousController extends StandardController { }

@Ioannis Ioannis requested review from benno and arlen August 31, 2025 08:57
@Ioannis
Copy link
Contributor Author

Ioannis commented Sep 1, 2025

Bumped to 5.2.7

Sign in to join this conversation on GitHub.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

1 participant