diff --git a/app/availableplugins/ApiConnector/src/Controller/ApiSourceEndpointsController.php b/app/availableplugins/ApiConnector/src/Controller/ApiSourceEndpointsController.php index 33813bc2d..6d4a8fe21 100644 --- a/app/availableplugins/ApiConnector/src/Controller/ApiSourceEndpointsController.php +++ b/app/availableplugins/ApiConnector/src/Controller/ApiSourceEndpointsController.php @@ -53,7 +53,7 @@ public function beforeRender(\Cake\Event\EventInterface $event) { if(!empty($vv_obj->api_source_id)) { $apiSource = $this->ApiSourceEndpoints->ApiSources->get( $vv_obj->api_source_id, - ['contain' => 'ExternalIdentitySources'] + contain: 'ExternalIdentitySources' ); $this->set( diff --git a/app/availableplugins/ApiConnector/src/Model/Table/ApiSourcesTable.php b/app/availableplugins/ApiConnector/src/Model/Table/ApiSourcesTable.php index 99b6a8878..7b59ca2a6 100644 --- a/app/availableplugins/ApiConnector/src/Model/Table/ApiSourcesTable.php +++ b/app/availableplugins/ApiConnector/src/Model/Table/ApiSourcesTable.php @@ -186,11 +186,8 @@ protected function mapApiToRegistry(string $model, array $attributes): array { */ public function remove(int $id, string $sorLabel, string $sorId): bool { - // We call this remove() so as not to interfere with the default table::delete(). - $apiSource = $this->get($id, ['contain' => ['ExternalIdentitySources']]); - // Pull our configuration - $apiSource = $this->get($id, ['contain' => ['ExternalIdentitySources']]); + $apiSource = $this->get($id, contain: ['ExternalIdentitySources']); // Like upsert(), we don't really need $sorLabel, but we check it for // consistency with upsert() (which also doesn't really need it). @@ -413,7 +410,7 @@ public function upsert( $ret = []; // Pull our configuration - $apiSource = $this->get($id, ['contain' => ['ExternalIdentitySources']]); + $apiSource = $this->get($id, contain: ['ExternalIdentitySources']); // Strictly speaking we don't need $sorLabel since we know which configuration // to use from the ApiSource ID, and $sorLabel might not be unique across COs diff --git a/app/availableplugins/SqlConnector/src/Model/Table/SqlProvisionersTable.php b/app/availableplugins/SqlConnector/src/Model/Table/SqlProvisionersTable.php index 04167cddd..bf1f64e33 100644 --- a/app/availableplugins/SqlConnector/src/Model/Table/SqlProvisionersTable.php +++ b/app/availableplugins/SqlConnector/src/Model/Table/SqlProvisionersTable.php @@ -556,7 +556,7 @@ protected function syncEntity( */ public function syncReferenceData(int $id, string $dataSource='targetdb') { - $spcfg = $this->get($id, ['contain' => ['ProvisioningTargets']]); + $spcfg = $this->get($id, contain: ['ProvisioningTargets']); $this->Servers->SqlServers->connect($spcfg->server_id, $dataSource); diff --git a/app/plugins/CoreAssigner/src/Lib/Jobs/SqlAssignerJob.php b/app/plugins/CoreAssigner/src/Lib/Jobs/SqlAssignerJob.php index a1be967e2..85abe18bc 100644 --- a/app/plugins/CoreAssigner/src/Lib/Jobs/SqlAssignerJob.php +++ b/app/plugins/CoreAssigner/src/Lib/Jobs/SqlAssignerJob.php @@ -288,7 +288,7 @@ public function run( $this->ia = $this->IdentifierAssignments->get( $parameters['identifier_assignment_id'], - ['contain' => ['SqlAssigners', 'IdentifierTypes']] + contain: ['SqlAssigners', 'IdentifierTypes'] ); if($this->ia->plugin != 'CoreAssigner.SqlAssigners') { diff --git a/app/plugins/CoreJob/src/Lib/Jobs/SyncJob.php b/app/plugins/CoreJob/src/Lib/Jobs/SyncJob.php index 34e2df7fb..64a5b8179 100644 --- a/app/plugins/CoreJob/src/Lib/Jobs/SyncJob.php +++ b/app/plugins/CoreJob/src/Lib/Jobs/SyncJob.php @@ -284,7 +284,7 @@ protected function getRunContext( $this->runContext->eis = $this->runContext->EISTable->get( $eisId, - ['contain' => $this->runContext->EISTable->getPluginRelations()] + contain: $this->runContext->EISTable->getPluginRelations() ); } diff --git a/app/plugins/CoreServer/src/Model/Table/MatchServersTable.php b/app/plugins/CoreServer/src/Model/Table/MatchServersTable.php index 6815bca8d..6708dc32c 100644 --- a/app/plugins/CoreServer/src/Model/Table/MatchServersTable.php +++ b/app/plugins/CoreServer/src/Model/Table/MatchServersTable.php @@ -59,7 +59,10 @@ public function initialize(array $config): void { $this->setTableType(\App\Lib\Enum\TableTypeEnum::Configuration); // Define associations - $this->belongsTo('Servers'); + // Avoid redefining the association if the parent already set it + if (!$this->hasAssociation('Servers')) { + $this->belongsTo('Servers'); + } $this->hasMany('CoreServer.MatchServerAttributes') ->setDependent(true) ->setCascadeCallbacks(true); diff --git a/app/plugins/CoreServer/src/Model/Table/Oauth2ServersTable.php b/app/plugins/CoreServer/src/Model/Table/Oauth2ServersTable.php index 473a73cb3..07c72bf87 100644 --- a/app/plugins/CoreServer/src/Model/Table/Oauth2ServersTable.php +++ b/app/plugins/CoreServer/src/Model/Table/Oauth2ServersTable.php @@ -54,8 +54,10 @@ public function initialize(array $config): void { $this->setTableType(\App\Lib\Enum\TableTypeEnum::Configuration); // Define associations - // XXX this is defined in HttpServersTable -// $this->belongsTo('Servers'); + // Avoid redefining the association if the parent already set it + if (!$this->hasAssociation('Servers')) { + $this->belongsTo('Servers'); + } $this->setDisplayField('hostname'); diff --git a/app/plugins/CoreServer/src/Model/Table/SqlServersTable.php b/app/plugins/CoreServer/src/Model/Table/SqlServersTable.php index d958d4bfc..a5ad9c46f 100644 --- a/app/plugins/CoreServer/src/Model/Table/SqlServersTable.php +++ b/app/plugins/CoreServer/src/Model/Table/SqlServersTable.php @@ -127,7 +127,7 @@ public function connect(int $serverId, string $name): bool { // which is basically what the SQL Provisioner does. // Pull our configuration via the parent Server object. - $server = $this->Servers->get($serverId, ['contain' => ['SqlServers']]); + $server = $this->Servers->get($serverId, contain: ['SqlServers']); $dbmap = [ RdbmsTypeEnum::MariaDB => 'Mysql', diff --git a/app/plugins/EnvSource/src/Controller/EnvSourceCollectorsController.php b/app/plugins/EnvSource/src/Controller/EnvSourceCollectorsController.php index 1cbae03a8..4df18edaf 100644 --- a/app/plugins/EnvSource/src/Controller/EnvSourceCollectorsController.php +++ b/app/plugins/EnvSource/src/Controller/EnvSourceCollectorsController.php @@ -78,7 +78,7 @@ public function dispatch(string $id) { // Pull our configuration - $envSource = $this->EnvSourceCollectors->get((int)$id, ['contain' => ['ExternalIdentitySources' => 'EnvSources']]); + $envSource = $this->EnvSourceCollectors->get((int)$id, contain: ['ExternalIdentitySources' => 'EnvSources']); try { $vars = $this->EnvSourceCollectors->parse($envSource->external_identity_source->env_source); diff --git a/app/plugins/EnvSource/src/Model/Table/EnvSourceCollectorsTable.php b/app/plugins/EnvSource/src/Model/Table/EnvSourceCollectorsTable.php index c4c23051c..af57c539e 100644 --- a/app/plugins/EnvSource/src/Model/Table/EnvSourceCollectorsTable.php +++ b/app/plugins/EnvSource/src/Model/Table/EnvSourceCollectorsTable.php @@ -232,7 +232,7 @@ public function hydrate(int $id, \App\Model\Entity\Petition $petition) { $eis = $ExtIdentitySources->get( $cfg->external_identity_source_id, - ['contain' => 'EnvSources'] + contain: 'EnvSources' ); $eisrecord = $EnvSources->retrieve($eis, $pei->env_source_identity->source_key); @@ -514,7 +514,7 @@ public function verifiableEmailAddresses( $eis = $this->ExternalIdentitySources->get( $config->external_identity_source_id, - ['contain' => 'Pipelines'] + contain: 'Pipelines' ); $defaultVerified = isset($eis->pipeline->sync_verify_email_addresses) diff --git a/app/src/Command/JobCommand.php b/app/src/Command/JobCommand.php index ee376b192..9a35fc611 100644 --- a/app/src/Command/JobCommand.php +++ b/app/src/Command/JobCommand.php @@ -38,9 +38,12 @@ use Cake\Utility\Security; use App\Lib\Enum\JobStatusEnum; use App\Lib\Events\CoIdEventListener; +use Cake\ORM\Locator\LocatorAwareTrait; class JobCommand extends BaseCommand { + use LocatorAwareTrait; + /** * Register command specific options. * diff --git a/app/src/Command/NotificationCommand.php b/app/src/Command/NotificationCommand.php index 8f749130d..e3ee3ab96 100644 --- a/app/src/Command/NotificationCommand.php +++ b/app/src/Command/NotificationCommand.php @@ -33,9 +33,13 @@ use Cake\Console\BaseCommand; use Cake\Console\ConsoleIo; use Cake\Console\ConsoleOptionParser; +use Cake\ORM\Locator\LocatorAwareTrait; +use Cake\ORM\TableRegistry; class NotificationCommand extends BaseCommand { + use LocatorAwareTrait; + /** * Register command specific options. * @@ -202,6 +206,10 @@ public function execute(Arguments $args, ConsoleIo $io) $io->out("- Recipient Person ID: " . $recipientPersonId); $io->out("- Recipient Group ID: " . $recipientGroupId); + $MessageTemplates = TableRegistry::getTableLocator()->get('MessageTemplates'); + $template = $MessageTemplates->get($args->getOption('messageTemplateId')); + + $notificationIds = $Notifications->register( subjectPersonId: $subjectPersonId, subjectGroupId: $subjectGroupId, @@ -210,7 +218,7 @@ public function execute(Arguments $args, ConsoleIo $io) recipientGroupId: $recipientGroupId, action: $args->getOption('action'), comment: $args->getOption('comment'), - messageTemplateId: (int)$args->getOption('messageTemplateId'), + messageTemplate: $template, source: $args->getOption('source'), mustResolve: $args->getOption('mustResolve') ); diff --git a/app/src/Command/SetupCommand.php b/app/src/Command/SetupCommand.php index 500647a80..ee6b2308d 100644 --- a/app/src/Command/SetupCommand.php +++ b/app/src/Command/SetupCommand.php @@ -36,9 +36,12 @@ use Cake\Utility\Security; use App\Lib\Enum\PermissionEnum; use App\Lib\Enum\SuspendableStatusEnum; +use Cake\ORM\Locator\LocatorAwareTrait; class SetupCommand extends BaseCommand { + use LocatorAwareTrait; + /** * Register command specific options. * diff --git a/app/src/Command/TestCommand.php b/app/src/Command/TestCommand.php index 8661c13ff..748a5cf52 100644 --- a/app/src/Command/TestCommand.php +++ b/app/src/Command/TestCommand.php @@ -35,9 +35,12 @@ use Cake\Console\ConsoleOptionParser; use Cake\Datasource\ConnectionManager; use \App\Lib\Util\DeliveryUtilities; +use Cake\ORM\Locator\LocatorAwareTrait; class TestCommand extends BaseCommand { + use LocatorAwareTrait; + protected $io = null; /** diff --git a/app/src/Command/UpgradeCommand.php b/app/src/Command/UpgradeCommand.php index 1026babc1..5541d713c 100644 --- a/app/src/Command/UpgradeCommand.php +++ b/app/src/Command/UpgradeCommand.php @@ -34,9 +34,12 @@ use Cake\Console\ConsoleIo; use Cake\Console\ConsoleOptionParser; use Cake\Datasource\ConnectionManager; +use Cake\ORM\Locator\LocatorAwareTrait; class UpgradeCommand extends BaseCommand { + use LocatorAwareTrait; + protected $io = null; // A list of known versions, must be semantic versioning compliant. The value diff --git a/app/src/Controller/ApiV2Controller.php b/app/src/Controller/ApiV2Controller.php index b44e1c640..5a19ec129 100644 --- a/app/src/Controller/ApiV2Controller.php +++ b/app/src/Controller/ApiV2Controller.php @@ -44,6 +44,10 @@ class ApiV2Controller extends AppController { use \App\Lib\Traits\LabeledLogTrait; use \App\Lib\Traits\IndexQueryTrait; + protected string $tableName = ''; + + protected \Cake\ORM\Table $table; + /** * Perform Cake Controller initialization. * @@ -82,9 +86,7 @@ public function add() { /** var string $modelsName */ $modelsName = $this->getName(); /** var Cake\ORM\Table $table */ - $table = $this->fetchTable($modelsName); - // $tableName = models - $tableName = $this->tableName; + $table = $this->getCurrentTable(); $json = $this->request->getData(); // Parsed by BodyParserMiddleware @@ -97,13 +99,13 @@ public function add() { foreach($json[$modelsName] as $rec) { try { - $obj = $this->$modelsName->newEntity($rec); + $obj = $table->newEntity($rec); - if($this->$modelsName->saveOrFail($obj)) { + if($table->saveOrFail($obj)) { $results[] = ['id' => $obj->id]; // Trigger provisioning, letting errors bubble up (AR-GMR-5) - if(method_exists($this->$modelsName, "requestProvisioning")) { + if(method_exists($table, "requestProvisioning")) { $this->llog('rule', "AR-GMR-5 Requesting provisioning for $modelsName " . $obj->id); $table->requestProvisioning(id: $obj->id, context: ProvisioningContextEnum::Automatic); } @@ -186,7 +188,7 @@ public function delete($id) { /** var string $modelsName */ $modelsName = $this->getName(); /** var Cake\ORM\Table $table */ - $table = $this->fetchTable($modelsName); + $table = $this->getCurrentTable(); // $tableName = models $tableName = $table->getTable(); @@ -234,10 +236,8 @@ protected function dispatchIndex(string $mode = 'default') { throw new UnauthorizedException(__d('error', 'perm')); } - // $modelsName = Models - $modelsName = $this->getName(); /** var Cake\ORM\Table $table */ - $table = $this->fetchTable($modelsName); + $table = $this->getCurrentTable(); $reqParameters = [...$this->request->getQuery()]; $pickerMode = ($mode === 'picker'); @@ -271,7 +271,7 @@ public function edit($id) { /** var string $modelsName */ $modelsName = $this->getName(); /** var Cake\ORM\Table $table */ - $table = $this->fetchTable($modelsName); + $table = $this->getCurrentTable(); // $tableName = models $tableName = $table->getTable(); @@ -390,10 +390,8 @@ public function index() { */ public function view($id = null) { - /** var string $modelsName */ - $modelsName = $this->getName(); /** var Cake\ORM\Table $table */ - $table = $this->fetchTable($modelsName); + $table = $this->getCurrentTable(); // $tableName = models $tableName = $table->getTable(); diff --git a/app/src/Controller/AppController.php b/app/src/Controller/AppController.php index 919ac0d22..268de4035 100644 --- a/app/src/Controller/AppController.php +++ b/app/src/Controller/AppController.php @@ -48,7 +48,6 @@ * @property \Cake\Controller\Component\FlashComponent $Flash * @property \Cake\Controller\Component\FormProtectionComponent $FormProtection */ -#[\AllowDynamicProperties] class AppController extends Controller { use \App\Lib\Traits\LabeledLogTrait; @@ -221,9 +220,6 @@ public function beforeFilter(\Cake\Event\EventInterface $event) { */ public function beforeRender(\Cake\Event\EventInterface $event) { - /** var string $modelsName */ - $modelsName = $this->getName(); - // Views can also inspect the request object to determine the current // controller and action, but it seems slightly easier to do it once here. $this->set('vv_controller', $this->request->getParam('controller')); @@ -269,6 +265,25 @@ public function getCOID(): ?int { return $cur_co ? $cur_co->id : null; } + /** + * Get the current Table instance for this controller, respecting plugin context. + * + * @since COmanage Registry v5.2.0 + * @return \Cake\ORM\Table + */ + protected function getCurrentTable(): \Cake\ORM\Table + { + /** @var string $modelsName */ + $modelsName = $this->getName(); + + $alias = $this->plugin !== null + ? $this->plugin . '.' . $modelsName + : $modelsName; + + return $this->fetchTable($alias); + } + + /** * @param string $potentialPrimaryLink * @@ -278,14 +293,11 @@ public function getCOID(): ?int { protected function primaryLinkOnGet(string $potentialPrimaryLink): Object|bool { - /** var string $modelsName */ - $modelsName = $this->getName(); - // If this action allows unkeyed, asserted primary link IDs, check the query // string (e.g.: 'add' or 'index' allow matchgrid_id to be passed in) $actionParam = $this->request->getParam('action'); - $allowsUnkeyed = $this->$modelsName->allowUnkeyedPrimaryLink($actionParam); - $allowsLookup = $this->$modelsName->allowLookupPrimaryLink($actionParam); + $allowsUnkeyed = $this->getCurrentTable()->allowUnkeyedPrimaryLink($actionParam); + $allowsLookup = $this->getCurrentTable()->allowLookupPrimaryLink($actionParam); $param = (int)$this->request->getParam('pass.0'); if($allowsUnkeyed) { @@ -299,7 +311,7 @@ protected function primaryLinkOnGet(string $potentialPrimaryLink): Object|bool return false; } - return $this->$modelsName->findPrimaryLink($param); + return $this->getCurrentTable()->findPrimaryLink($param); } /** @@ -345,20 +357,18 @@ protected function primaryLinkOnPost(string $potentialPrimaryLink): Object|bool protected function primaryLinkOnPut(): Object|bool { - /** var string $modelsName */ - $modelsName = $this->getName(); $param = (int)$this->request->getParam('pass.0'); // Put = edit, so we should look up the parent ID via the object itself if ( empty($param) || - !$this->$modelsName->allowLookupPrimaryLink($this->request->getParam('action')) + !$this->getCurrentTable()->allowLookupPrimaryLink($this->request->getParam('action')) ) { return false; } - return $this->$modelsName->findPrimaryLink($param); + return $this->getCurrentTable()->findPrimaryLink($param); } /** @@ -368,11 +378,9 @@ protected function primaryLinkOnPut(): Object|bool */ protected function populatedPrimaryLink(string $potentialPrimaryLink): Object { - /** var string $modelsName */ - $modelsName = $this->getName(); // $potentialPrimaryLink will be something like 'attribute_collector_id' // $potentialPrimaryLinkTable will be something like 'CoreEnroller.AttributeCollectors' - $potentialPrimaryLinkTable = $this->$modelsName->getPrimaryLinkTableName($potentialPrimaryLink); + $potentialPrimaryLinkTable = $this->getCurrentTable()->getPrimaryLinkTableName($potentialPrimaryLink); // For looking up values in records here, we want only the attribute // itself and not the plugin name (used for hacky notation by @@ -406,9 +414,8 @@ protected function populatedPrimaryLink(string $potentialPrimaryLink): Object protected function primaryLinkLookup(): void { - /** var string $modelsName */ - $modelsName = $this->getName(); - $availablePrimaryLinks = $this->$modelsName->getPrimaryLinks(); + $table = $this->getCurrentTable(); + $availablePrimaryLinks = $table->getPrimaryLinks(); // Iterate over all the potential primary links and pick the appropriate one foreach($availablePrimaryLinks as $potentialPrimaryLink) { @@ -429,7 +436,7 @@ protected function primaryLinkLookup(): void // At the end we need to have a Primary Link if(empty($this->cur_pl->value) - && !$this->$modelsName->allowEmptyPrimaryLink($this->request->getParam('action')) + && !$table->allowEmptyPrimaryLink($this->request->getParam('action')) && $this->request->getParam('action') != 'deleted') { throw new \RuntimeException(__d('error', 'primary_link')); } @@ -478,13 +485,10 @@ public function getPrimaryLink(bool $lookup=false): Object return $this->cur_pl; } - /** var string $modelsName */ - $modelsName = $this->getName(); - $this->cur_pl = new \stdClass(); - if(!(method_exists($this->$modelsName, 'getPrimaryLinks') - && $this->$modelsName->getPrimaryLinks()) + if(!(method_exists($this->getCurrentTable(), 'getPrimaryLinks') + && $this->getCurrentTable()->getPrimaryLinks()) ) { return $this->cur_pl; } @@ -504,7 +508,7 @@ public function getPrimaryLink(bool $lookup=false): Object // Look up the link value to find the related entity - $linkTableName = $this->$modelsName->getPrimaryLinkTableName($this->cur_pl->attr); + $linkTableName = $this->getCurrentTable()->getPrimaryLinkTableName($this->cur_pl->attr); $linkTable = $this->getTableLocator()->get($linkTableName); $this->set('vv_primary_link_model', $linkTableName); @@ -540,12 +544,9 @@ public function getPrimaryLink(bool $lookup=false): Object */ protected function getRedirectGoal(string $action): ?string { - /** var string $modelsName */ - $modelsName = $this->getName(); - // PrimaryLinkTrait - if(method_exists($this->$modelsName, "getRedirectGoal")) { - return $this->$modelsName->getRedirectGoal($this->request->getParam('action')); + if(method_exists($this->getCurrentTable(), "getRedirectGoal")) { + return $this->getCurrentTable()->getRedirectGoal($this->request->getParam('action')); } return 'index'; @@ -674,11 +675,10 @@ protected function setCO() { if($this->request->is('restful') && !empty($attrs['params']['model'])) { $modelsName = \Cake\Utility\Inflector::camelize($attrs['params']['model']); - $this->$modelsName = TableRegistry::getTableLocator()->get($modelsName); } - if(!method_exists($this->$modelsName, "requiresCO") - || !$this->$modelsName->requiresCO()) { + if(!method_exists($this->getCurrentTable(), "requiresCO") + || !$this->getCurrentTable()->requiresCO()) { // Nothing to do, CO not required by this model/controller return; } @@ -700,13 +700,13 @@ protected function setCO() { } if(!$coid - && $this->$modelsName->allowUnkeyedCO($this->request->getParam('action')) + && $this->getCurrentTable()->allowUnkeyedCO($this->request->getParam('action')) && !empty($this->request->getQuery('co_id'))) { $coid = $this->request->getQuery('co_id'); } if(!$coid - && !$this->$modelsName->allowEmptyCO() + && !$this->getCurrentTable()->allowEmptyCO() && !$this->request->is('restful')) { // If we get this far without a CO ID, something went wrong. throw new \RuntimeException(__d('error', 'coid')); @@ -728,7 +728,7 @@ protected function setCO() { throw new \InvalidArgumentException(__d('error', 'inactive', [__d('controller', 'Cos', [1]), $coid])); } - if(!empty($modelsName) && !empty($this->$modelsName)) { + if(!empty($modelsName) && !empty($this->getCurrentTable())) { // We store the CO ID in Configuration to facilitate its access from // model contexts such as validation where passing the value via the // Controller is not particularly feasible. Note that for API calls @@ -737,9 +737,9 @@ protected function setCO() { // This only works for the current model, not related models. For // relatedmodels, we use the event listener approach below. - if(method_exists($this->$modelsName, "acceptsCoId") - && $this->$modelsName->acceptsCoId()) { - $this->$modelsName->setCurCoId((int)$coid); + if(method_exists($this->getCurrentTable(), "acceptsCoId") + && $this->getCurrentTable()->acceptsCoId()) { + $this->getCurrentTable()->setCurCoId((int)$coid); } // This doesn't work for the current model since it has already been @@ -753,7 +753,7 @@ protected function setCO() { // a use case to do so, though note it's possible a child associations // wants the CO ID even though the parent doesn't. - foreach($this->$modelsName->associations()->getIterator() as $a) { + foreach($this->getCurrentTable()->associations()->getIterator() as $a) { $aTable = $a->getTarget(); if(method_exists($aTable, "acceptsCoId") @@ -773,9 +773,6 @@ protected function setCO() { */ protected function setTZ() { - /** var string $modelsName */ - $modelsName = $this->getName(); - // See if we've collected it from the browser in a previous page load. Otherwise, // use the system default. If the user set a preferred timezone, we'll catch that below. @@ -802,9 +799,9 @@ protected function setTZ() { $this->set('vv_tz', $tz); - if($this->$modelsName->behaviors()->has('Timezone')) { + if($this->getCurrentTable()->behaviors()->has('Timezone')) { // Tell TimezoneBehavior what the current timezone is - $this->$modelsName->setTimeZone($tz); + $this->getCurrentTable()->setTimeZone($tz); } } } \ No newline at end of file diff --git a/app/src/Controller/AuthenticatorsController.php b/app/src/Controller/AuthenticatorsController.php index c6e7650d2..3175fc4f6 100644 --- a/app/src/Controller/AuthenticatorsController.php +++ b/app/src/Controller/AuthenticatorsController.php @@ -96,7 +96,7 @@ public function manage() { $cfg = $this->Authenticators->get( (int)$this->getRequest()->getQuery('authenticator_id'), - ['contain' => $this->Authenticators->getPluginRelations()] + contain: $this->Authenticators->getPluginRelations() ); // We need to know what type of Authenticator we're managing to construct the redirect. diff --git a/app/src/Controller/Component/BreadcrumbComponent.php b/app/src/Controller/Component/BreadcrumbComponent.php index dd4901e6a..9cbc4d82d 100644 --- a/app/src/Controller/Component/BreadcrumbComponent.php +++ b/app/src/Controller/Component/BreadcrumbComponent.php @@ -112,10 +112,10 @@ public function beforeRender(EventInterface $event) { // Do we have a target model, and if so is it a configuration // model (eg: ApiUsers) or an object model (eg: CoPeople)? - if(\is_object($controller->$modelsName) - && method_exists($controller->$modelsName, "isConfigurationTable") + if(\is_object($controller->fetchTable($modelsName)) + && method_exists($controller->fetchTable($modelsName), "isConfigurationTable") ) { - $controller->set('vv_bc_configuration_link', $controller->$modelsName->isConfigurationTable()); + $controller->set('vv_bc_configuration_link', $controller->fetchTable($modelsName)->isConfigurationTable()); } else { $controller->set('vv_bc_configuration_link', false); } diff --git a/app/src/Controller/ExternalIdentitiesController.php b/app/src/Controller/ExternalIdentitiesController.php index 25adc8c4b..0cb0e1bc5 100644 --- a/app/src/Controller/ExternalIdentitiesController.php +++ b/app/src/Controller/ExternalIdentitiesController.php @@ -135,5 +135,5 @@ public function relink(string $id) { $this->set('vv_title', __d('operation', 'relink.a', [__d('controller', 'ExternalIdentities', [1])])); - $this->set('vv_external_identity', $this->ExternalIdentities->get((int)$id, ['contain' => 'Names'])); + $this->set('vv_external_identity', $this->ExternalIdentities->get((int)$id, contain: 'Names')); }} \ No newline at end of file diff --git a/app/src/Controller/MVEAController.php b/app/src/Controller/MVEAController.php index 0af6cc082..6709e1ae8 100644 --- a/app/src/Controller/MVEAController.php +++ b/app/src/Controller/MVEAController.php @@ -47,6 +47,7 @@ class MVEAController extends StandardController { public function beforeFilter(\Cake\Event\EventInterface $event) { /** var string $modelsName */ $modelsName = $this->getName(); + $table = $this->getCurrentTable(); if(!$this->request->is('restful') && $this->request->getParam('action') != 'deleted') { // Provide additional hints to BreadcrumbsComponent. This needs to be here @@ -62,7 +63,7 @@ public function beforeFilter(\Cake\Event\EventInterface $event) { } else { $parentModel = StringUtilities::foreignKeyToClassName($primaryLink->attr); - $parentPrimaryLink = $this->$modelsName->$parentModel->findPrimaryLink((int)$primaryLink->value); + $parentPrimaryLink = $table->$parentModel->findPrimaryLink((int)$primaryLink->value); $this->Breadcrumb->injectPrimaryLink($parentPrimaryLink); $this->Breadcrumb->injectPrimaryLink($primaryLink); @@ -140,12 +141,13 @@ public function beforeFilter(\Cake\Event\EventInterface $event) { public function beforeRender(\Cake\Event\EventInterface $event) { /** var string $modelsName */ $modelsName = $this->getName(); + $table = $this->getCurrentTable(); // field = model (or model_name) $fieldName = Inflector::underscore(Inflector::singularize($modelsName)); if(!$this->request->is('restful') && $this->request->getParam('action') != 'deleted') { // If there is a default type setting for this model, pass it to the view - if($this->$modelsName->getSchema()->hasColumn('type_id')) { + if($table->getSchema()->hasColumn('type_id')) { $defaultTypeField = "default_" . $fieldName . "_type_id"; $CoSettings = TableRegistry::getTableLocator()->get('CoSettings'); diff --git a/app/src/Controller/MultipleAuthenticatorController.php b/app/src/Controller/MultipleAuthenticatorController.php index 5c9e32933..93570cbb7 100644 --- a/app/src/Controller/MultipleAuthenticatorController.php +++ b/app/src/Controller/MultipleAuthenticatorController.php @@ -52,7 +52,7 @@ public function beforeFilter(\Cake\Event\EventInterface $event) { // $authModelName = eg SshKeyAuthenticators $authModelsName = Inflector::singularize($modelsName) . "Authenticators"; /** var Cake\ORM\Table $table */ - $Table = $this->$modelsName; + $Table = $this->getCurrentTable(); // $authFK = eg ssh_key_authenticator_id $authFK = StringUtilities::classNameToForeignKey($authModelsName); @@ -102,7 +102,7 @@ public function generateRedirect($entity) { // $authModelName = eg SshKeyAuthenticators $authModelsName = Inflector::singularize($modelsName) . "Authenticators"; /** var Cake\ORM\Table $table */ - $Table = $this->$modelsName; + $Table = $this->getCurrentTable(); // $authFK = eg ssh_key_authenticator_id $authFK = StringUtilities::classNameToForeignKey($authModelsName); @@ -135,7 +135,7 @@ public function index() { /** var string $modelsName */ $modelsName = $this->getName(); /** var Cake\ORM\Table $table */ - $table = $this->fetchTable($modelsName); + $table = $this->getCurrentTable(); // $tableName = models $tableName = $table->getTable(); // Construct the Query @@ -185,7 +185,7 @@ public function willHandleAuth(\Cake\Event\EventInterface $event): string { // $authModelName = eg SshKeyAuthenticators $authModelsName = Inflector::singularize($modelsName) . "Authenticators"; /** var Cake\ORM\Table $table */ - $Table = $this->$modelsName; + $Table = $this->getCurrentTable(); // $authFK = eg ssh_key_authenticator_id $authFK = StringUtilities::classNameToForeignKey($authModelsName); diff --git a/app/src/Controller/PetitionsController.php b/app/src/Controller/PetitionsController.php index 5ee3b571f..b6f4a3fb1 100644 --- a/app/src/Controller/PetitionsController.php +++ b/app/src/Controller/PetitionsController.php @@ -209,7 +209,7 @@ public function finalize(string $id) { // We only use the Redirect on Finalize URL (if specified) on success, // since otherwise the Flash error won't render - $petition = $this->Petitions->get((int)$id, ['contain' => ['EnrollmentFlows']]); + $petition = $this->Petitions->get((int)$id, contain: ['EnrollmentFlows']); if(!empty($petition->enrollment_flow->redirect_on_finalize)) { return $this->redirect($petition->enrollment_flow->redirect_on_finalize); @@ -225,7 +225,7 @@ public function finalize(string $id) { // configuration (eg: EnvSource's duplicate redirect URL) since in theory any plugin // can trigger this. - $petition = $this->Petitions->get((int)$id, ['contain' => ['EnrollmentFlows']]); + $petition = $this->Petitions->get((int)$id, contain: ['EnrollmentFlows']); // Redirect to configured URL or default location if(!empty($petition->enrollment_flow->redirect_on_duplicate)) { diff --git a/app/src/Controller/SingleAuthenticatorController.php b/app/src/Controller/SingleAuthenticatorController.php index b2c9dd3f5..d2b1d9748 100644 --- a/app/src/Controller/SingleAuthenticatorController.php +++ b/app/src/Controller/SingleAuthenticatorController.php @@ -47,7 +47,7 @@ public function manage() { // $authModelName = eg PasswordAuthenticators $authModelsName = Inflector::singularize($modelsName) . "Authenticators"; /** var Cake\ORM\Table $table */ - $Table = $this->$modelsName; + $Table = $this->getCurrentTable(); // $authFK = eg password_authenticator_id $authFK = StringUtilities::classNameToForeignKey($authModelsName); @@ -70,7 +70,7 @@ public function manage() { $Authenticators = TableRegistry::getTableLocator()->get('Authenticators'); - $authcfg = $Authenticators->get($cfg->authenticator_id, ['contain' => $authModelsName]); + $authcfg = $Authenticators->get($cfg->authenticator_id, contain: $authModelsName); $status = $Authenticators->AuthenticatorStatuses->getForPerson( $authcfg, diff --git a/app/src/Controller/StandardController.php b/app/src/Controller/StandardController.php index db341aff1..79020e9b2 100644 --- a/app/src/Controller/StandardController.php +++ b/app/src/Controller/StandardController.php @@ -55,7 +55,7 @@ public function add() { /** var string $modelsName */ $modelsName = $this->getName(); /** var Cake\ORM\Table $table */ - $table = $this->fetchTable($modelsName); + $table = $this->getCurrentTable(); // $tableName = models $tableName = $table->getTable(); // Schema @@ -174,7 +174,7 @@ public function beforeRender(\Cake\Event\EventInterface $event) { /** var string $modelsName */ $modelsName = $this->getName(); /** var Cake\ORM\Table $table */ - $table = $this->fetchTable($modelsName); + $table = $this->getCurrentTable(); // Provide some hints to the views if($this->request->getParam('action') != 'deleted') { @@ -239,7 +239,7 @@ public function delete($id) { /** var string $modelsName */ $modelsName = $this->getName(); /** var Cake\ORM\Table $table */ - $table = $this->fetchTable($modelsName); + $table = $this->getCurrentTable(); // Allow a delete via a POST or DELETE $this->request->allowMethod(['post', 'delete']); @@ -376,17 +376,15 @@ public function edit(string $id) { /** var string $modelsName */ $modelsName = $this->getName(); /** var Cake\ORM\Table $table */ - $table = $this->fetchTable($modelsName); - // $tableName = models - $tableName = $table->getTable(); + $table = $this->getCurrentTable(); // We use findById() rather than get() so we can apply subsequent // query modifications via traits $query = $table->findById($id); // QueryModificationTrait - if(method_exists($this->$modelsName, "getEditContains")) { - $query = $query->contain($this->$modelsName->getEditContains()); + if(method_exists($table, "getEditContains")) { + $query = $query->contain($table->getEditContains()); } try { @@ -586,10 +584,8 @@ public function generateRedirect($entity) { */ protected function getFieldTypes() { - /** var string $modelsName */ - $modelsName = $this->getName(); /** var Cake\ORM\Table $table */ - $table = $this->fetchTable($modelsName); + $table = $this->getCurrentTable(); $schema = $table->getSchema(); @@ -609,10 +605,8 @@ protected function getFieldTypes() { */ protected function getRequiredFields() { - /** var string $modelsName */ - $modelsName = $this->getName(); /** var Cake\ORM\Table $table */ - $table = $this->fetchTable($modelsName); + $table = $this->getCurrentTable(); // Build a list of required fields for FieldHelper $reqFields = []; @@ -639,7 +633,7 @@ public function index() { /** var string $modelsName */ $modelsName = $this->getName(); /** var Cake\ORM\Table $table */ - $table = $this->fetchTable($modelsName); + $table = $this->getCurrentTable(); // $tableName = models $tableName = $table->getTable(); // Construct the Query @@ -688,10 +682,8 @@ public function index() { */ protected function populateAutoViewVars(object $obj=null) { - /** var string $modelsName */ - $modelsName = $this->getName(); /** var Cake\ORM\Table $table */ - $table = $this->fetchTable($modelsName); + $table = $this->getCurrentTable(); // AutoViewVarsTrait if(method_exists($table, 'getAutoViewVars') && $table->getAutoViewVars()) { @@ -709,10 +701,8 @@ protected function populateAutoViewVars(object $obj=null) { */ public function provision($id) { - /** var string $modelsName */ - $modelsName = $this->getName(); /** var Cake\ORM\Table $table */ - $table = $this->fetchTable($modelsName); + $table = $this->getCurrentTable(); // $tableName = models $tableName = $table->getTable(); @@ -754,10 +744,8 @@ public function provision($id) { */ public function unfreeze($id) { - /** var string $modelsName */ - $modelsName = $this->getName(); /** var Cake\ORM\Table $table */ - $table = $this->fetchTable($modelsName); + $table = $this->getCurrentTable(); try { // Pull the current record @@ -788,7 +776,7 @@ public function view($id = null) { /** var string $modelsName */ $modelsName = $this->getName(); /** var Cake\ORM\Table $table */ - $table = $this->fetchTable($modelsName); + $table = $this->getCurrentTable(); // $tableName = models $tableName = $table->getTable(); diff --git a/app/src/Controller/StandardEnrollerController.php b/app/src/Controller/StandardEnrollerController.php index 697a6db33..ea70e6982 100644 --- a/app/src/Controller/StandardEnrollerController.php +++ b/app/src/Controller/StandardEnrollerController.php @@ -104,7 +104,8 @@ public function calculatePermission(): bool { return false; } - $stepConfig = $this->$modelsName->get($modelId, ['contain' => ['EnrollmentFlowSteps' => ['EnrollmentFlows']]]); + $stepConfig = $this->getCurrentTable() + ->get($modelId, contain: ['EnrollmentFlowSteps' => ['EnrollmentFlows']]); $this->set('vv_step_config', $stepConfig); $this->set('vv_title', $stepConfig['enrollment_flow_step']['enrollment_flow']['name']); @@ -229,7 +230,7 @@ public function willHandleAuth(\Cake\Event\EventInterface $event): string { return 'notauth'; } - $stepConfig = $this->$modelsName->get($modelId, ['contain' => 'EnrollmentFlowSteps']); + $stepConfig = $this->getCurrentTable()->get($modelId, contain: 'EnrollmentFlowSteps'); // Determine if the requested step is past the current/next step. // We don't allow steps that haven't run yet to be run out of order. diff --git a/app/src/Controller/StandardPluggableController.php b/app/src/Controller/StandardPluggableController.php index 5fdea66e8..86a22454e 100644 --- a/app/src/Controller/StandardPluggableController.php +++ b/app/src/Controller/StandardPluggableController.php @@ -46,10 +46,8 @@ public function configure(string $id) { // (We only need to map into the plugin on actual link click, instead of // potentially many times on an index view for links that may not be used.) - /** var string $modelsName */ - $modelsName = $this->getName(); /** var Cake\ORM\Table $table */ - $table = $this->fetchTable($modelsName); + $table = $this->getCurrentTable(); $parentId = $this->request->getParam('pass')[0]; $parentObj = $table->findById($parentId) diff --git a/app/src/Controller/StandardPluginController.php b/app/src/Controller/StandardPluginController.php index 66f8a1ee2..8f29211f2 100644 --- a/app/src/Controller/StandardPluginController.php +++ b/app/src/Controller/StandardPluginController.php @@ -82,11 +82,6 @@ public function beforeFilter(\Cake\Event\EventInterface $event) { */ public function beforeRender(\Cake\Event\EventInterface $event) { - /** var string $modelsName (ie: from ModelsTable, eg FileProvisionersTable) */ - $modelsName = $this->getName(); - /** var Cake\ORM\Table $table */ - $table = $this->fetchTable($modelsName); - $link = $this->getPrimaryLink(true); if(!empty($link->value) && !empty($link->model_name)) { diff --git a/app/src/Lib/Traits/IndexQueryTrait.php b/app/src/Lib/Traits/IndexQueryTrait.php index 6e6ebb145..13683debd 100644 --- a/app/src/Lib/Traits/IndexQueryTrait.php +++ b/app/src/Lib/Traits/IndexQueryTrait.php @@ -44,16 +44,14 @@ trait IndexQueryTrait { * @since COmanage Registry v5.0.0 */ public function constructGetIndexContains(Query $query): object { - /** var string $modelsName */ - $modelsName = $this->getName(); /** var Cake\ORM\Table $table */ - $table = $this->fetchTable($modelsName); + $table = $this->getCurrentTable(); // Initialize the containClause $containClause = []; // Get whatever the table configuration has if(method_exists($table, 'getIndexContains') - && $table->getIndexContains()) { + && !empty($table->getIndexContains())) { $containClause = $table->getIndexContains(); } @@ -73,10 +71,8 @@ public function constructGetIndexContains(Query $query): object { * @since COmanage Registry v5.0.0 */ public function constructGetPickerContains(Query $query): object { - /** var string $modelsName */ - $modelsName = $this->getName(); /** var Cake\ORM\Table $table */ - $table = $this->fetchTable($modelsName); + $table = $this->getCurrentTable(); // Initialize the containClause $containClause = []; @@ -104,10 +100,8 @@ public function constructGetPickerContains(Query $query): object { */ public function containClauseFromQueryParams(): array { - /** var string $modelsName */ - $modelsName = $this->getName(); /** var Cake\ORM\Table $table */ - $table = $this->fetchTable($modelsName); + $table = $this->getCurrentTable(); // Restfull and ajax do not include the IndexContains by default. $containClause = []; @@ -156,7 +150,7 @@ public function getIndexQuery(bool $pickerMode = false, array $requestParams = [ /** var string $modelsName */ $modelsName = $this->getName(); /** var Cake\ORM\Table $table */ - $table = $this->fetchTable($modelsName); + $table = $this->getCurrentTable(); // PrimaryLinkTrait $link = $this->getPrimaryLink(true); // Initialize the Query Object diff --git a/app/src/Lib/Traits/PluggableModelTrait.php b/app/src/Lib/Traits/PluggableModelTrait.php index ec4cd3234..93620388a 100644 --- a/app/src/Lib/Traits/PluggableModelTrait.php +++ b/app/src/Lib/Traits/PluggableModelTrait.php @@ -197,15 +197,35 @@ protected function setPluginRelations() { continue; } + // Derive association alias from "Plugin.Model" + [$pluginName, $modelAlias] = explode('.', $m->plugin, 2); + + // Skip if alias would clash with this table alias or already exists + if ($modelAlias === $this->getAlias()) { + // Avoid "Association alias 'X' is already set." + $this->llog('debug', "Skipping association for plugin '{$m->plugin}' due to alias clash with table alias '{$this->getAlias()}'"); + continue; + } + + if ($this->associations()->has($modelAlias)) { + // Association already defined elsewhere; don't rebind + $this->llog('debug', "Association '{$modelAlias}' already exists, skipping plugin relation '{$m->plugin}'"); + continue; + } + // In general, a model with a "plugin" field has a 1-1 relation // with the instantiated plugin configuration. eg: One instance // of a Server has exactly one SqlServer associated with it. - $this->hasOne($m->plugin) - ->setDependent(true) - ->setCascadeCallbacks(true); - - // Cache the list of entry points that we found - $this->_pluginModels[] = $m->plugin; + // Bind by alias and explicitly set the className. + $this->hasOne($modelAlias) + ->setClassName($m->plugin) + ->setDependent(true) + ->setCascadeCallbacks(true); + + // Cache the list of entry points that we found (avoid duplicates) + if (!in_array($m->plugin, $this->_pluginModels, true)) { + $this->_pluginModels[] = $m->plugin; + } } // isArtifactTable() might not be the exact right test here... diff --git a/app/src/Lib/Traits/QueryModificationTrait.php b/app/src/Lib/Traits/QueryModificationTrait.php index 6670ef894..b3aa01cb7 100644 --- a/app/src/Lib/Traits/QueryModificationTrait.php +++ b/app/src/Lib/Traits/QueryModificationTrait.php @@ -35,25 +35,25 @@ trait QueryModificationTrait { // Array of associated models to copy during a duplicate - private $duplicateContains = false; + private array $duplicateContains = []; // Array of associated models to pull during an edit - private $editContains = false; + private array $editContains = []; // Containable models for index actions - private $indexContains = null; + private array $indexContains = []; // Filter (where clause) for index actions - private $indexFilter = null; + private array $indexFilter = []; // Array of associated models to save during a patch - private $patchAssociated = []; + private array $patchAssociated = []; // Array of associated models to pull during a view - private $viewContains = false; + private array $viewContains = []; // Array of associated models to pull during a pick action - private $pickerContains = false; + private array $pickerContains = []; /** @@ -88,7 +88,7 @@ public function checkValidity(Query $query): QueryExpression { * @return array Array of associated models */ - public function getDuplicateContains() { + public function getDuplicateContains(): array { return $this->duplicateContains; } @@ -99,7 +99,7 @@ public function getDuplicateContains() { * @return array Array of associated models */ - public function getEditContains() { + public function getEditContains(): array { return $this->editContains; } @@ -110,7 +110,7 @@ public function getEditContains() { * @param boolean $allowEmpty true if the primary link is permitted to be empty */ - public function getIndexContains() { + public function getIndexContains(): array { return $this->indexContains; } @@ -132,7 +132,7 @@ public function getPatchAssociated() { * @return array Array of associated models */ - public function getPickerContains() { + public function getPickerContains(): array { return $this->pickerContains; } @@ -143,7 +143,7 @@ public function getPickerContains() { * @return array Array of associated models */ - public function getViewContains() { + public function getViewContains(): array { return $this->viewContains; } diff --git a/app/src/Lib/Traits/ValidationTrait.php b/app/src/Lib/Traits/ValidationTrait.php index e19508cfc..b6ff096c5 100644 --- a/app/src/Lib/Traits/ValidationTrait.php +++ b/app/src/Lib/Traits/ValidationTrait.php @@ -237,13 +237,14 @@ public function validateIncreaseStep(string $value, int $step, array $context) { /** * Determine if a string submitted from a form is valid input. * - * @since COmanage Registry v5.0.0 - * @param string $value Value to validate - * @param array $context Optional validation context; accepts 'type' of 'html' (may be extended to include 'email', 'url' etc. + * @param string $value Value to validate + * @param array $options + * @param array $context Optional validation context; accepts 'type' of 'html' * @return mixed True if $value validates, or an error string otherwise + *@since COmanage Registry v5.0.0 */ - public function validateInput(string $value, array $context) { + public function validateInput(string $value, array $options = [], array $context = []): bool|string { // By default, we'll accept anything except < and >. Arguably, we should accept // anything at all for input (and filter only on output), but this was agreed to // as an extra "line of defense" against unsanitized HTML output. Where user supplied @@ -252,8 +253,8 @@ public function validateInput(string $value, array $context) { // XXX we previously supported 'flags' and 'invalidchars' as arguments, do we still need to? // CFM-152 review the logic here - if(!empty($context['type'])) { - switch($context['type']) { + if(!empty($options['type'])) { + switch($options['type']) { case 'html': // We are accepting HTML input. We will mostly pass it all through and ensure // properly sanitized output. However, we can do some very rudimentary checking for script tags. @@ -284,7 +285,7 @@ public function validateInput(string $value, array $context) { } // We require at least one non-whitespace character (CO-1551) - $notBlankValidation = $this->validateNotBlank($value, $context); + $notBlankValidation = $this->validateNotBlank($value, $options); if ($notBlankValidation !== true) { return $notBlankValidation; } @@ -296,25 +297,25 @@ public function validateInput(string $value, array $context) { /** * Validate the maximum length of a field. * - * @param string $value Value to validate - * @param array $columnMetadata - * @param array $context Validation context, which must include the schema definition + * @param string $value Value to validate + * @param array $options + * @param array $context Validation context, which must include the schema definition * * @return bool|string True if $value validates, or an error string otherwise * @since COmanage Registry v5.0.0 */ - public function validateMaxLength(string $value, array $columnMetadata, array $context): bool|string { + public function validateMaxLength(string $value, array $options = [], array $context = []): bool|string { // We use our own so we can introspect the field's max length from the // provided table schema object, and use our own error message (without // having to copy it to every table definition). // Text has no limit. - if ($columnMetadata['column']['type'] === 'text') { + if ($options['column']['type'] === 'text') { return true; } - $maxLength = $columnMetadata['column']['length']; + $maxLength = $options['column']['length']; if(!empty($value) && mb_strlen($value) > $maxLength) { return __d('error', 'input.length', [$maxLength]); diff --git a/app/src/Model/Table/AuthenticatorsTable.php b/app/src/Model/Table/AuthenticatorsTable.php index 843ee697e..ed167f2af 100644 --- a/app/src/Model/Table/AuthenticatorsTable.php +++ b/app/src/Model/Table/AuthenticatorsTable.php @@ -179,7 +179,7 @@ public function lock(int $id, int $personId) { */ protected function processLock(int $id, int $personId, string $action) { - $cfg = $this->get($id, ['contain' => $this->getPluginRelations()]); + $cfg = $this->get($id, contain: $this->getPluginRelations()); // Make sure our configuration is active if($cfg->status != SuspendableStatusEnum::Active) { @@ -241,7 +241,7 @@ protected function processLock(int $id, int $personId, string $action) { */ public function reset(int $id, int $personId) { - $cfg = $this->get($id, ['contain' => $this->getPluginRelations()]); + $cfg = $this->get($id, contain: $this->getPluginRelations()); // Make sure our configuration is active if($cfg->status != SuspendableStatusEnum::Active) { diff --git a/app/src/Model/Table/CousTable.php b/app/src/Model/Table/CousTable.php index 4b1f985b4..a69ef3af7 100644 --- a/app/src/Model/Table/CousTable.php +++ b/app/src/Model/Table/CousTable.php @@ -260,7 +260,7 @@ public function potentialParents(int $coId, int $id=null, bool $hierarchy=false) $query = null; if($hierarchy) { - $query = $this->find('treeList', ['spacer' => '-']); + $query = $this->find('treeList', spacer: '-'); } else { $query = $this->find('list'); } diff --git a/app/src/Model/Table/ExternalIdentitiesTable.php b/app/src/Model/Table/ExternalIdentitiesTable.php index c3f91fad0..e91e00926 100644 --- a/app/src/Model/Table/ExternalIdentitiesTable.php +++ b/app/src/Model/Table/ExternalIdentitiesTable.php @@ -269,7 +269,7 @@ public function adopt(int $id): int { ] ]; - $externalIdentity = $this->get($id, ['contain' => $related]); + $externalIdentity = $this->get($id, contain: $related); // For each of the top level related models, walk to the Pipelined record on the Person // and unset the source_ key. @@ -453,7 +453,7 @@ public function beforeDelete(\Cake\Event\Event $event, $entity, \ArrayObject $op $this->Names->delete($n, ['checkRules' => false]); } - return true; + $event->setResult(true); } /** @@ -515,7 +515,7 @@ public function recalculateStatus(int $id): ?string { // Start by pulling the roles for this External Identity, along with the EI record - $externalIdentity = $this->get($id, ['contain' => 'ExternalIdentityRoles']); + $externalIdentity = $this->get($id, contain: 'ExternalIdentityRoles'); if(!empty($externalIdentity->external_identity_roles)) { foreach($externalIdentity->external_identity_roles as $role) { diff --git a/app/src/Model/Table/ExternalIdentityRolesTable.php b/app/src/Model/Table/ExternalIdentityRolesTable.php index 88c012386..541e465c5 100644 --- a/app/src/Model/Table/ExternalIdentityRolesTable.php +++ b/app/src/Model/Table/ExternalIdentityRolesTable.php @@ -238,8 +238,8 @@ public function beforeDelete(\Cake\Event\Event $event, $entity, \ArrayObject $op } $this->recordHistory(entity: $entity, action: ActionEnum::MVEADeleted); - - return true; + + $event->setResult(true); } /** diff --git a/app/src/Model/Table/ExternalIdentitySourcesTable.php b/app/src/Model/Table/ExternalIdentitySourcesTable.php index 1e0937b7f..76a1b0089 100644 --- a/app/src/Model/Table/ExternalIdentitySourcesTable.php +++ b/app/src/Model/Table/ExternalIdentitySourcesTable.php @@ -231,7 +231,7 @@ protected function getEIS(int $id) { // the query simpler we contain all possible relations, which will // usually only be a small number. if(empty($this->eisCache[$id])) { - $this->eisCache[$id] = $this->get($id, ['contain' => $this->getPluginRelations()]); + $this->eisCache[$id] = $this->get($id, contain: $this->getPluginRelations()); } return $this->eisCache[$id]; diff --git a/app/src/Model/Table/GroupMembersTable.php b/app/src/Model/Table/GroupMembersTable.php index 98c0a2a2d..6dbc9a499 100644 --- a/app/src/Model/Table/GroupMembersTable.php +++ b/app/src/Model/Table/GroupMembersTable.php @@ -244,7 +244,7 @@ public function isMember(int $groupId, public function localAfterSave(\Cake\Event\EventInterface $event, \Cake\Datasource\EntityInterface $entity, \ArrayObject $options): bool { // Pull the related entities for HistoryRecord comment creation. - $person = $this->People->get($entity->person_id, ['contain' => ['PrimaryName']]); + $person = $this->People->get($entity->person_id, contain: ['PrimaryName']); $group = $this->Groups->get($entity->group_id); $action = null; @@ -259,8 +259,8 @@ public function localAfterSave(\Cake\Event\EventInterface $event, \Cake\Datasour // We need to allow retrieval of archived records since we might be called // after the GroupNesting was deleted $nesting = $this->GroupNestings->get($entity->group_nesting_id, - ['contain' => ['Groups'], - 'archived' => true]); + contain: ['Groups'], + archived: true); $langKeySuffix = '.nesting'; $commentParams[] = $nesting->group->name; @@ -314,7 +314,7 @@ public function ruleIsGroupMember($entity, $options) { if($this->isMember($entity->group_id, $entity->person_id, true, false)) { // Pull the Person and Group name for the error message. - $person = $this->People->get($entity->person_id, ['contain' => ['PrimaryName']]); + $person = $this->People->get($entity->person_id, contain: ['PrimaryName']); $group = $this->Groups->get($entity->group_id); return __d('error', 'exists.GroupMember', [$person->primary_name->full_name, $group->name]); diff --git a/app/src/Model/Table/GroupsTable.php b/app/src/Model/Table/GroupsTable.php index 42f4c48a1..96fdfa6b5 100644 --- a/app/src/Model/Table/GroupsTable.php +++ b/app/src/Model/Table/GroupsTable.php @@ -329,7 +329,7 @@ public function addDefaults(int $coId, int $couId=null, bool $rename=false): boo 'status' => SuspendableStatusEnum::Active, 'cou_id' => null ]; - }; + } foreach($defaultGroups as $suffix => $attrs) { // Construct the full group name @@ -389,7 +389,7 @@ public function beforeDelete(EventInterface $event, $entity, \ArrayObject $optio // to look at the archived data. } - return true; + $event->setResult(true); } /** @@ -492,7 +492,7 @@ public function createOwnersGroup($group): int { // Update the original Group with a pointer to this one $group->owners_group_id = $ownerGroup->id; - $this->saveOrFail($group); + $this->saveOrFail($group, ['archive' => false]); return $ownerGroup->id; } diff --git a/app/src/Model/Table/IdentifierAssignmentsTable.php b/app/src/Model/Table/IdentifierAssignmentsTable.php index 3bbc58110..29257a1aa 100644 --- a/app/src/Model/Table/IdentifierAssignmentsTable.php +++ b/app/src/Model/Table/IdentifierAssignmentsTable.php @@ -219,7 +219,7 @@ public function assign( // this should be less brittle if we add support for another model // alongside Identifiers and EmailAddresses.) - $entity = $EntityTable->get($entityId, ['contain' => $contains]); + $entity = $EntityTable->get($entityId, contain: $contains); // Check if there is already an identifier of this type diff --git a/app/src/Model/Table/MostlyStaticPagesTable.php b/app/src/Model/Table/MostlyStaticPagesTable.php index bcbd2189d..16617ec9e 100644 --- a/app/src/Model/Table/MostlyStaticPagesTable.php +++ b/app/src/Model/Table/MostlyStaticPagesTable.php @@ -345,7 +345,7 @@ public function validationDefault(Validator $validator): Validator { $validator->notEmptyString('context'); $validator->add('body', [ - 'filter' => ['rule' => ['validateInput',['type' => 'html']], + 'filter' => ['rule' => ['validateInput', ['type' => 'html']], 'provider' => 'table'] ]); $validator->allowEmptyString('body'); diff --git a/app/src/Model/Table/NamesTable.php b/app/src/Model/Table/NamesTable.php index 1d07a8e09..6fa842643 100644 --- a/app/src/Model/Table/NamesTable.php +++ b/app/src/Model/Table/NamesTable.php @@ -242,7 +242,7 @@ public function localAfterSave(\Cake\Event\EventInterface $event, \Cake\Datasour */ public function primaryName(int $id, string $recordType='person', array $options = []) { - $query = empty($options) ? $this->find() : $this->find('all', $options); + $query = empty($options) ? $this->find() : $this->find('all', ...$options); if($recordType == 'person') { // Return the Primary Name diff --git a/app/src/Model/Table/NotificationsTable.php b/app/src/Model/Table/NotificationsTable.php index 177181ae1..26685b220 100644 --- a/app/src/Model/Table/NotificationsTable.php +++ b/app/src/Model/Table/NotificationsTable.php @@ -425,7 +425,7 @@ public function register( if($subjectPersonId) { // Retrieve and attach the Subject Person $messageTemplate->setContextSubjectPerson( - $this->SubjectPeople->get($subjectPersonId, ['contain' => 'PrimaryName']) + $this->SubjectPeople->get($subjectPersonId, contain: 'PrimaryName') ); } diff --git a/app/src/Model/Table/PeopleTable.php b/app/src/Model/Table/PeopleTable.php index 92e8ec0fc..af25f5a44 100644 --- a/app/src/Model/Table/PeopleTable.php +++ b/app/src/Model/Table/PeopleTable.php @@ -358,7 +358,7 @@ public function beforeDelete(\Cake\Event\Event $event, $entity, \ArrayObject $op } } - return true; + $event->setResult(true); } /** @@ -469,10 +469,10 @@ public function localAfterSave(\Cake\Event\EventInterface $event, \Cake\Datasour public function marshalProvisioningData(int $id): array { $ret = []; - $ret['data'] = $this->get($id, [ + $ret['data'] = $this->get($id, // We need archives for handling deleted records - 'archived' => 'true', - 'contain' => [ + archived: 'true', + contain: [ 'PrimaryName' => [ 'Types' ], 'Addresses' => [ 'Types' ], 'AdHocAttributes', @@ -510,7 +510,7 @@ public function marshalProvisioningData(int $id): array { 'TelephoneNumbers' => [ 'Types' ], 'Urls' => [ 'Types' ] ] - ]); + ); // Provisioning Eligibility is // - Deleted if the changelog deleted flag is true OR status is Archived @@ -620,7 +620,7 @@ public function recalculateStatus(int $id): ?string { // Start by pulling the roles for this person, along with the Person record - $person = $this->get($id, ['contain' => 'PersonRoles']); + $person = $this->get($id, contain: 'PersonRoles'); if(!empty($person->person_roles)) { foreach($person->person_roles as $role) { diff --git a/app/src/Model/Table/PetitionsTable.php b/app/src/Model/Table/PetitionsTable.php index 595718082..4ee4ecac6 100644 --- a/app/src/Model/Table/PetitionsTable.php +++ b/app/src/Model/Table/PetitionsTable.php @@ -331,13 +331,13 @@ public function buildRules(RulesChecker $rules): RulesChecker { */ public function derive(int $id) { - $petition = $this->get($id, ['contain' => [ + $petition = $this->get($id, contain: [ 'EnrollmentFlows' => [ 'EnrollmentFlowSteps' => array_merge( $this->EnrollmentFlows->EnrollmentFlowSteps->getPluginRelations(), ['sort' => ['EnrollmentFlowSteps.ordr' => 'ASC']] ) - ]]]); + ]]); if($petition->isComplete()) { throw new \InvalidArgumentException(__d('error', 'Petitions.completed', [$id])); @@ -380,7 +380,7 @@ public function derive(int $id) { */ public function finalize(int $id) { - $petition = $this->get($id, ['contain' => 'EnrollmentFlows']); + $petition = $this->get($id, contain: 'EnrollmentFlows'); if($petition->isComplete()) { throw new \InvalidArgumentException(__d('error', 'Petitions.completed', [$id])); @@ -421,7 +421,7 @@ public function finalize(int $id) { $template->generateMessage(); if(!DeliveryUtilities::sendEmailToAddress( - coId: $coId, + coId: $petition->enrollment_flow->co_id, recipient: $petition->enrollee_email, subject: $template->getMessagePart('subject'), body_text: $template->getMessagePart('body_text'), @@ -528,12 +528,12 @@ public function getEnrolleeName(int $id): ?string { // First see if there is an Enrollee Person associated with the Petition, which would // be the case for (eg) account linking. If so, use their Primary Name. - $petition = $this->get($id, ['contain' => [ + $petition = $this->get($id, contain: [ 'EnrolleePeople' => 'PrimaryName', 'PetitionStepResults' => [ 'EnrollmentFlowSteps' => $this->PetitionStepResults->EnrollmentFlowSteps->getPluginRelations() ] - ]]); + ]); if(!empty($petition->enrollee_person->primary_name)) { return $petition->enrollee_person->primary_name->full_name; @@ -574,13 +574,13 @@ public function hydrate(int $id) { // This is intended to be the first part of finalization, so we set the Petition status // to Finalizing. - $petition = $this->get($id, ['contain' => [ + $petition = $this->get($id, contain: [ 'EnrollmentFlows' => [ 'EnrollmentFlowSteps' => array_merge( $this->EnrollmentFlows->EnrollmentFlowSteps->getPluginRelations(), ['sort' => ['EnrollmentFlowSteps.ordr' => 'ASC']] ) - ]]]); + ]]); if($petition->isComplete()) { throw new \InvalidArgumentException(__d('error', 'Petitions.completed', [$id])); diff --git a/app/src/Model/Table/PipelinesTable.php b/app/src/Model/Table/PipelinesTable.php index 68224a858..f9c2afa54 100644 --- a/app/src/Model/Table/PipelinesTable.php +++ b/app/src/Model/Table/PipelinesTable.php @@ -1248,15 +1248,15 @@ public function relink( $eis = $this->ExternalIdentitySources->get( $eisRecord->external_identity_source_id, - ['contain' => 'Pipelines'] + contain: 'Pipelines' ); $ei = $this->Cos->People->ExternalIdentities->get( $eisRecord->external_identity_id, - ['contain' => [ + contain: [ 'ExternalIdentityRoles' => 'PersonRoles', 'People' - ]] + ] ); // To start the relinking, tell syncPerson to update the source Person with a @@ -1527,7 +1527,7 @@ protected function searchByAttribute( // syncExternalIdentity will pull whatever Person attributes it actually needs. // AR-Pipeline-2 Pipeline Person Matching ignores the existing Person status. - $person = $SearchTable->People->get($personId, ['contain' => ['Names']]); + $person = $SearchTable->People->get($personId, contain: ['Names']); // We can't record history yet since we don't have an External Identity // (we'll do that in execute()), but we can at least log @@ -1647,7 +1647,7 @@ protected function syncExternalIdentity( $externalIdentity = $this->Cos->People->ExternalIdentities->get( $eisRecord->external_identity_id, - ['contain' => [ + contain: [ 'Addresses', 'AdHocAttributes', 'EmailAddresses', @@ -1661,7 +1661,7 @@ protected function syncExternalIdentity( 'Addresses', 'TelephoneNumbers' ] - ]] + ] ); // Map the current backend record... @@ -1941,7 +1941,7 @@ protected function syncPerson( if($externalIdentityId) { $externalIdentity = $this->Cos->People->ExternalIdentities->get( $externalIdentityId, - ['contain' => [ + contain: [ 'Addresses', 'AdHocAttributes', 'EmailAddresses', @@ -1955,7 +1955,7 @@ protected function syncPerson( 'Addresses', 'TelephoneNumbers' ] - ]] + ] ); } else { $externalIdentity = null; diff --git a/app/src/Model/Table/ServersTable.php b/app/src/Model/Table/ServersTable.php index d766ff225..a626f4681 100644 --- a/app/src/Model/Table/ServersTable.php +++ b/app/src/Model/Table/ServersTable.php @@ -72,10 +72,7 @@ public function initialize(array $config): void { $this->hasMany('Pipelines') ->setForeignKey('match_server_id'); -// XXX Note this will bind to (eg) CoreServer but not (eg) SqlProvisioner -// As of Cake 5 this is causing errors with the Servers alias already being set, -// it's not clear that we need this anymore? - // $this->setPluginRelations(); + $this->setPluginRelations(); $this->setDisplayField('description');