diff --git a/app/availableplugins/FileConnector/src/Model/Table/FileSourcesTable.php b/app/availableplugins/FileConnector/src/Model/Table/FileSourcesTable.php index ee57ddd7a..2fb307034 100644 --- a/app/availableplugins/FileConnector/src/Model/Table/FileSourcesTable.php +++ b/app/availableplugins/FileConnector/src/Model/Table/FileSourcesTable.php @@ -166,9 +166,9 @@ public function inventory( } // The first line of a CSV v3 file is our configuration - fgetcsv($handle); + fgetcsv($handle, escape: '\\'); - while(($data = fgetcsv($handle)) !== false) { + while(($data = fgetcsv($handle, escape: '\\')) !== false) { // The source key is always the first field in each line, make sure it is not empty if(!empty($data[0]) && !ctype_space($data[0])) { @@ -306,9 +306,9 @@ protected function processChangeList( } // Ignore the header line - fgetcsv($handle); + fgetcsv($handle, escape: '\\'); - while(($data = fgetcsv($handle)) !== false) { + while(($data = fgetcsv($handle, escape: '\\')) !== false) { // Implode the record back together for string comparison purposes. // This may not be the same as the original line due to quotes, etc. // $data[0] is the SORID @@ -327,9 +327,9 @@ protected function processChangeList( } // Ignore the header line - fgetcsv($handle); + fgetcsv($handle, escape: '\\'); - while(($data = fgetcsv($handle)) !== false) { + while(($data = fgetcsv($handle, escape: '\\')) !== false) { // $data[0] is the SORID if(array_key_exists($data[0], $knownRecords)) { $newData = implode(',', $data); @@ -445,7 +445,7 @@ protected function readFieldConfig( } // The first line is our configuration - $cfg = fgetcsv($handle); + $cfg = fgetcsv($handle, escape: '\\'); fclose($handle); @@ -700,13 +700,13 @@ public function retrieve( // If there is more than one record, we'll return the first one we find. // The first line of a CSV v3 file is our configuration - fgetcsv($handle); + fgetcsv($handle, escape: '\\'); // Set null defaults in case we don't find a matching record $ret['source_record'] = null; $ret['entity_data'] = null; - while(($data = fgetcsv($handle)) !== false) { + while(($data = fgetcsv($handle, escape: '\\')) !== false) { if($data[0] == $source_key) { // This is our record @@ -809,9 +809,9 @@ public function search( } // The first line of a CSV v3 file is our configuration - fgetcsv($handle); + fgetcsv($handle, escape: '\\'); - while(($data = fgetcsv($handle)) !== false) { + while(($data = fgetcsv($handle, escape: '\\')) !== false) { // strtolower, previous behavior was full string only so dupe that $match = collection($data) diff --git a/app/plugins/CoreJob/src/Lib/Jobs/SyncJob.php b/app/plugins/CoreJob/src/Lib/Jobs/SyncJob.php index 64a5b8179..e414348af 100644 --- a/app/plugins/CoreJob/src/Lib/Jobs/SyncJob.php +++ b/app/plugins/CoreJob/src/Lib/Jobs/SyncJob.php @@ -238,13 +238,14 @@ protected function fullSync() { /** * Cache the current run context. - * + * + * @param JobsTable $JobsTable $JobsTable JobsTable + * @param JobHistoryRecordsTable $JobHistoryRecordsTable $JobHistoryRecordsTable JobHistoryRecordsTable + * @param Job $job Current Job + * @param array $parameters Job Parameters (from the command line) + * @param int|null $eisId External Identity Source ID + * @return \StdClass * @since COmanage Registry v5.0.0 - * @param JobsTable $JobsTable JobsTable - * @param JobHistoryRecordsTable $JobHistoryRecordsTable JobHistoryRecordsTable - * @param Job $job Current Job - * @param array $parameters Job Parameters (from the command line) - * @param int $eisId External Identity Source ID */ protected function getRunContext( @@ -252,7 +253,7 @@ protected function getRunContext( \App\Model\Table\JobHistoryRecordsTable $JobHistoryRecordsTable, \App\Model\Entity\Job $job, array $parameters, - int $eisId=null + ?int $eisId = null ): \StdClass { // We use $runContext so we don't have to pass a complicated set of parameters around. @@ -451,7 +452,7 @@ public function run( ); if($this->runContext->eis->status == SyncModeEnum::Disabled) { - throw new \InvalidArgumentException('core_job', 'Sync.error.disabled'); + throw new \InvalidArgumentException(__d('core_job', 'Sync.error.disabled')); } if(!empty($parameters['source_keys'])) { @@ -465,7 +466,7 @@ public function run( if(count($keys) == 1) { $referenceId = $parameters['reference_id']; } else { - throw new \InvalidArgumentException('core_job', 'Sync.error.reference_id'); + throw new \InvalidArgumentException(__d('core_job', 'Sync.error.reference_id')); } } @@ -516,11 +517,11 @@ public function run( * * @since COmanage Registry v5.0.0 * @param string $key Source Key to process - * @param string $referenceId Reference ID to link to record, if known + * @param string|null $referenceId Reference ID to link to record, if known * @return bool True if processing should continue, false otherwise */ - protected function syncRecord(string $key, string $referenceId=null): bool { + protected function syncRecord(string $key, ?string $referenceId=null): bool { // comment and status for HistoryRecords $c = "unknown"; $s = JobStatusEnum::Failed; @@ -577,9 +578,9 @@ protected function syncRecord(string $key, string $referenceId=null): bool { if($this->runContext->JobsTable->isCanceled($this->runContext->job->id)) { // The Job was already marked Canceled, but we can optionally add a History Record $this->runContext->JobHistoryRecordsTable->record( - jobId: $job->id, + jobId: $this->runContext->job->id, recordKey: "", - comment: __d( + comment: __d( 'core_job', 'Sync.finish_summary.count', [$this->runContext->created, $this->runContext->updated, $this->runContext->errors, $this->runContext->count] diff --git a/app/plugins/CoreServer/src/Model/Table/Oauth2ServersTable.php b/app/plugins/CoreServer/src/Model/Table/Oauth2ServersTable.php index f31ce438c..f2beaba94 100644 --- a/app/plugins/CoreServer/src/Model/Table/Oauth2ServersTable.php +++ b/app/plugins/CoreServer/src/Model/Table/Oauth2ServersTable.php @@ -107,18 +107,23 @@ public function exchangeCode(int|string $id, string $code, string $redirectUri, /** * Obtain an OAuth token. * - * @param Integer $id Oauth2Server ID - * @param String $grantType OAuth grant type - * @param String|null $code Access code returned by call to /oauth/authorize, for authorization_code grant - * @param String|null $redirectUri Callback URL used for initial request, for authorization_code grant - * @param Boolean $store If true, store the retrieved tokens in the Oauth2Server configuration + * @param int $id Oauth2Server ID + * @param string $grantType OAuth grant type + * @param string|null $code Access code returned by call to /oauth/authorize, for authorization_code grant + * @param string|null $redirectUri Callback URL used for initial request, for authorization_code grant + * @param bool $store If true, store the retrieved tokens in the Oauth2Server configuration * @return mixed Object of data as returned by server, including access and refresh token * @throws RuntimeException *@since COmanage Registry v5.2.0 */ - public function obtainToken(int $id, string $grantType, string $code=null, string $redirectUri=null, bool $store=true): mixed - { + public function obtainToken( + int $id, + string $grantType, + ?string $code=null, + ?string $redirectUri=null, + bool $store=true) + : mixed { // Pull our configuration $srvr = $this->get($id); diff --git a/app/src/Controller/StandardController.php b/app/src/Controller/StandardController.php index 2658e15c8..190d4f48f 100644 --- a/app/src/Controller/StandardController.php +++ b/app/src/Controller/StandardController.php @@ -721,10 +721,10 @@ public function index() { * Populate any auto view variables, as requested via AutoViewVarsTrait. * * @since COmanage Registry v5.0.0 - * @param object $obj Current object (eg: from edit), if set + * @param object|null $obj Current object (eg: from edit), if set */ - protected function populateAutoViewVars(object $obj=null) { + protected function populateAutoViewVars(?object $obj=null) { /** var Cake\ORM\Table $table */ $table = $this->getCurrentTable(); diff --git a/app/src/Lib/Random/RandomString.php b/app/src/Lib/Random/RandomString.php index ba183990b..c9d88a0e0 100644 --- a/app/src/Lib/Random/RandomString.php +++ b/app/src/Lib/Random/RandomString.php @@ -98,6 +98,10 @@ public static function generateCode(): string { * a token is not expected to be directly visible or handled by a human, but * will (eg) be injected into a URL or a message. * + * @param int $length Length of token + * @param string|null $allowedCharset Allowed characters + * @param string|null $regex Regex to match characters + * * @return string Token * @throws RandomException * @since COmanage Registry v5.0.0 @@ -105,8 +109,8 @@ public static function generateCode(): string { public static function generateToken( int $length = 16, - string $allowedCharset = null, - string $regex = null, // Permitted + ?string $allowedCharset = null, + ?string $regex = null, // Permitted ): string { // Unlike App Keys, tokens don't have restrictions on characters. diff --git a/app/src/Lib/Traits/IndexQueryTrait.php b/app/src/Lib/Traits/IndexQueryTrait.php index fb97219e9..398555f58 100644 --- a/app/src/Lib/Traits/IndexQueryTrait.php +++ b/app/src/Lib/Traits/IndexQueryTrait.php @@ -156,7 +156,7 @@ public function getIndexQuery(bool $pickerMode = false, array $requestParams = [ // Initialize the Query Object $query = $table->find(); // Get a pointer to my expression list - $newexp = $query->newExpr(); + $newexp = $query->expr(); // The searchable attributes can have an AND or an OR conjunction. The first one is used from the filtering block // while the second one from the picker vue module. $newexp = $newexp->setConjunction($pickerMode ? 'OR' : 'AND'); diff --git a/app/src/Lib/Util/DeliveryUtilities.php b/app/src/Lib/Util/DeliveryUtilities.php index 4d63b3a17..5cd761d02 100644 --- a/app/src/Lib/Util/DeliveryUtilities.php +++ b/app/src/Lib/Util/DeliveryUtilities.php @@ -45,15 +45,15 @@ class DeliveryUtilities { * an InvalidArgumentException will be thrown. * * @since COmanage Registry v5.0.0 - * @param int $coId CO ID - * @param string $recipient Recipient email address - * @param string $subject Message subject - * @param string $body_text Message body (plain text) - * @param string $body_html Message body (HTML) - * @param string $cc Addresses to cc - * @param string $bcc Addresses to bcc - * @param string $replyTo Reply-To address to use, instead of the default - * @return bool Returns true if mail was sent + * @param int $coId CO ID + * @param string $recipient Recipient email address + * @param string $subject Message subject + * @param string $body_text Message body (plain text) + * @param string $body_html Message body (HTML) + * @param string|null $cc Addresses to cc + * @param string|null $bcc Addresses to bcc + * @param string|null $replyTo Reply-To address to use, instead of the default + * @return bool Returns true if mail was sent * @throws Cake\Network\Exception\SocketException * @throws InvalidArgumentException */ @@ -64,9 +64,9 @@ public static function sendEmailToAddress( string $subject, string $body_text="", string $body_html="", - string $cc="", - string $bcc="", - string $replyTo="" + ?string $cc="", + ?string $bcc="", + ?string $replyTo="" ) { // We start by trying to pull the CO Outgoing SMTP Server configuration. // If one isn't available, we log a warning, but we don't throw an exception @@ -161,9 +161,9 @@ public static function sendEmailToAddress( * * @since COmanage Registry v5.0.0 * @param MessageTemplate $template Message Template - * @param int $personId Recipient Person ID - * @param string $address Recipient Email Address - * @param int $groupId Recipient Group ID + * @param int|null $personId Recipient Person ID + * @param string|null $address Recipient Email Address + * @param int|null $groupId Recipient Group ID * @return array 'recipient': Recipient email address ("to" only, not "cc" or "bcc") */ @@ -181,9 +181,9 @@ public static function sendEmailFromTemplate( subject: $template->getMessagePart('subject'), body_text: $template->getMessagePart('body_text'), body_html: $template->getMessagePart('body_html'), - cc: $template->cc, - bcc: $template->bcc, - replyTo: $template->reply_to + cc: $template->cc ?? '', + bcc: $template->bcc ?? '', + replyTo: $template->reply_to ?? '' ); } else { self::sendEmailToAddress( @@ -192,9 +192,9 @@ public static function sendEmailFromTemplate( subject: $template->getMessagePart('subject'), body_text: $template->getMessagePart('body_text'), body_html: $template->getMessagePart('body_html'), - cc: $template->cc, - bcc: $template->bcc, - replyTo: $template->reply_to + cc: $template->cc ?? '', + bcc: $template->bcc ?? '', + replyTo: $template->reply_to ?? '' ); return [ @@ -208,14 +208,14 @@ public static function sendEmailFromTemplate( * and other settings. * * @since COmanage Registry v5.0.0 - * @param int $personId Recipient Person ID - * @param string $subject Message subject - * @param string $body_text Message body (plain text) - * @param string $body_html Message body (HTML) - * @param string $cc Addresses to cc - * @param string $bcc Addresses to bcc - * @param string $replyTo Reply-To address to use, instead of the default - * @return array 'recipient': Recipient email address ("to" only, not "cc" or "bcc") + * @param int $personId Recipient Person ID + * @param string $subject Message subject + * @param string $body_text Message body (plain text) + * @param string $body_html Message body (HTML) + * @param string|null $cc Addresses to cc + * @param string|null $bcc Addresses to bcc + * @param string|null $replyTo Reply-To address to use, instead of the default + * @return array 'recipient': Recipient email address ("to" only, not "cc" or "bcc") */ public static function sendEmailToPerson( @@ -223,9 +223,9 @@ public static function sendEmailToPerson( string $subject, string $body_text="", string $body_html="", - string $cc="", - string $bcc="", - string $replyTo="" + ?string $cc="", + ?string $bcc="", + ?string $replyTo="" ): array { // Find a deliverable Email Address for $personId diff --git a/app/src/Model/Table/JobsTable.php b/app/src/Model/Table/JobsTable.php index 150c31e3c..2667789c9 100644 --- a/app/src/Model/Table/JobsTable.php +++ b/app/src/Model/Table/JobsTable.php @@ -200,7 +200,7 @@ public function assign(Job $job) { __d('error', 'Jobs.status.invalid', [ - $jobs->id, + $job->id, __d('enumeration', 'JobStatusEnum.Queued'), __d('enumeration', 'JobStatusEnum.Assigned'), __d('enumeration', 'JobStatusEnum.'.$job->status) @@ -417,7 +417,7 @@ public function finish(Job $job, string $summary="", string $result=JobStatusEnu // The new job will be substantially the same as the last one... $this->register( - coId: job->co_id, + coId: $job->co_id, plugin: $job->plugin, parameters: json_decode($job->parameters, true), registerSummary: $job->register_summary, @@ -471,7 +471,7 @@ public function process(Job $job, string $dbcxn='default') { __d('error', 'Jobs.status.invalid', [ - $jobs->id, + $job->id, __d('enumeration', 'JobStatusEnum.Assigned'), __d('enumeration', 'JobStatusEnum.InProgress'), __d('enumeration', 'JobStatusEnum.'.$job->status) @@ -687,7 +687,7 @@ public function start(Job $job, string $summary="") { __d('error', 'Jobs.status.invalid', [ - $job->id, + $job->id, __d('enumeration', 'JobStatusEnum.Assigned'), __d('enumeration', 'JobStatusEnum.InProgress'), __d('enumeration', 'JobStatusEnum.'.$job->status) diff --git a/app/src/Model/Table/PluginsTable.php b/app/src/Model/Table/PluginsTable.php index 7903fa390..0e3473643 100644 --- a/app/src/Model/Table/PluginsTable.php +++ b/app/src/Model/Table/PluginsTable.php @@ -321,6 +321,12 @@ public function getPluginSchema(\App\Model\Entity\Plugin $plugin): ?object { public function pluginPath(\App\Model\Entity\Plugin $plugin, string $file): string { $fileName = $this->paths[$plugin->location]['path'] . DS . $plugin->plugin . DS . $file; + // "tests/" is optional in deployed environments. Return the computed path + // without treating absence as an error so callers can probe as needed. + if($file === 'tests' || str_starts_with($file, 'tests' . DS)) { + return $fileName; + } + if(is_readable($fileName)) { // This is the plugin we're looking for $this->llog('debug', "Found plugin $plugin->plugin in $plugin->location directory"); diff --git a/app/src/Model/Table/VerificationsTable.php b/app/src/Model/Table/VerificationsTable.php index 49de805a6..89455dfb7 100644 --- a/app/src/Model/Table/VerificationsTable.php +++ b/app/src/Model/Table/VerificationsTable.php @@ -265,7 +265,7 @@ public function requestCodeForPetition( int $codeLength, ?string $codeCharset, ?string $codeRegex, - int $verificationId = null + ?int $verificationId = null ): int { // First generate a new code $code = RandomString::generateToken($codeLength, $codeCharset, $codeRegex); diff --git a/app/src/View/Helper/FieldHelper.php b/app/src/View/Helper/FieldHelper.php index 2d2e58827..5d04bffa8 100644 --- a/app/src/View/Helper/FieldHelper.php +++ b/app/src/View/Helper/FieldHelper.php @@ -297,7 +297,7 @@ public function constructSPAField(string $element, string $vueElementName): stri public function dateField(string $fieldName, string $dateType = DateTypeEnum::Standard, - array $fieldArgs = null): string + ?array $fieldArgs = null): string { // Initialize $dateFormat = $dateType === DateTypeEnum::DateOnly ? 'yyyy-MM-dd' : 'yyyy-MM-dd HH:mm:ss'; @@ -422,13 +422,13 @@ public function dateField(string $fieldName, * @since COmanage Registry v5.0.0 */ public function formField(string $fieldName, - array $fieldOptions = null, - string $fieldLabel = null, + ?array $fieldOptions = null, + ?string $fieldLabel = null, string $fieldPrefix = '', - string $fieldType = null, - array $fieldSelectOptions = null, - string $fieldNameAlias = null, - bool $labelIsTextOnly = null): string + ?string $fieldType = null, + ?array $fieldSelectOptions = null, + ?string $fieldNameAlias = null, + ?bool $labelIsTextOnly = null): string { $fieldArgs = $fieldOptions ?? []; $fieldArgs['label'] = $fieldOptions['label'] ?? false; @@ -766,7 +766,8 @@ public function restructureFieldArguments(array $fieldArgs) { 'id', 'style', 'checked', - 'label' + 'label', + 'name' ]; // Remove the top-level field options that are intended for Cake, and diff --git a/app/src/View/Helper/TabHelper.php b/app/src/View/Helper/TabHelper.php index 05c5058ef..9d538cbf5 100644 --- a/app/src/View/Helper/TabHelper.php +++ b/app/src/View/Helper/TabHelper.php @@ -295,7 +295,7 @@ public function tabBelongsToModelPath(string $tab, string $modelFullName, int &$ * @return int * @since COmanage Registry v5.0.0 */ - public function getCurrentId(string $tabName = null, bool $isNested = false): int + public function getCurrentId(?string $tabName = null, bool $isNested = false): int { $vv_obj = $this->getView()->get('vv_obj'); $vv_primary_link = $this->getView()->get('vv_primary_link');