Skip to content

CFM-474_Pipeline_Toolkit_problems #343

Open
wants to merge 14 commits into
base: develop
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class IdentifierMappersTable extends Table {
use \App\Lib\Traits\LabeledLogTrait;
use \App\Lib\Traits\PermissionsTrait;
use \App\Lib\Traits\PrimaryLinkTrait;
use \App\Lib\Traits\QueryModificationTrait;
use \App\Lib\Traits\TableMetaTrait;
use \App\Lib\Traits\ValidationTrait;

Expand Down Expand Up @@ -68,6 +69,19 @@ public function initialize(array $config): void {
$this->setPrimaryLink(['flange_id']);
$this->setRequiresCO(true);

$this->setViewContains([
'Flanges',
]);

$this->setEditContains([
'Flanges',
]);

// Required for deep Breadcrumb calculations
$this->setIndexContains([
'Flanges',
]);

$this->setPermissions([
// Actions that operate over an entity (ie: require an $id)
'entity' => [
Expand Down Expand Up @@ -135,6 +149,17 @@ public function buildRelatedAttributes(
return $retdata;
}

/**
* Table specific logic to generate a display field.
*
* @since COmanage Registry v5.2.0
* @param \PipelineToolkit\Model\Entity\IdentifierMapper $entity Entity to generate display field for
* @return string Display field
*/
public function generateDisplayField(\PipelineToolkit\Model\Entity\IdentifierMapper $entity): string {
return $entity->name ?? $entity->description ?? $entity->flange->description;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IdentifierMappers have neither names nor descriptions, so why are we testing for them?

Also we should fail gracefully (ie: return null) if $entity->flange is not set.

More generally, this seems to be a fairly common pattern, so maybe the parent code in StringUtilities should detect the situation?

Copy link
Contributor Author

@Ioannis Ioannis Oct 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed the first. As for the second, you are correct there is a pattern for the models that have no name or description. In general, we probably want to inherit from their parent. I am not sure how we should generalize this yet. @arlen suggested in the past that each model should have a name or description field to facilitate the title construction, etc. I do not think that the StringUtilities is the appropriate place for this.

}

/**
* Set validation rules.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class LoginIdentifierTypesTable extends Table {
use \App\Lib\Traits\LabeledLogTrait;
use \App\Lib\Traits\PermissionsTrait;
use \App\Lib\Traits\PrimaryLinkTrait;
use \App\Lib\Traits\QueryModificationTrait;
use \App\Lib\Traits\TableMetaTrait;
use \App\Lib\Traits\ValidationTrait;

Expand Down Expand Up @@ -75,6 +76,14 @@ public function initialize(array $config): void {
]
]);

$this->setViewContains([
'IdentifierMappers' => ['Flanges'],
]);

$this->setEditContains([
'IdentifierMappers' => ['Flanges'],
]);

$this->setPermissions([
// Actions that operate over an entity (ie: require an $id)
'entity' => [
Expand Down Expand Up @@ -109,6 +118,17 @@ public function buildRules(RulesChecker $rules): RulesChecker {
return $rules;
}

/**
* Table specific logic to generate a display field.
*
* @since COmanage Registry v5.2.0
* @param \PipelineToolkit\Model\Entity\LoginIdentifierType $entity Entity to generate display field for
* @return string Display field
*/
public function generateDisplayField(\PipelineToolkit\Model\Entity\LoginIdentifierType $entity): string {
return __d('pipeline_toolkit', 'controller.LoginIdentifierTypes', [1]);
}

/**
* Application Rule to determine if a specific Type is already configured.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,8 @@ protected function getChanges(
* @return string Display field
*/
public function generateDisplayField(\SqlConnector\Model\Entity\SqlSource $entity): string {
return __d('sql_connector', 'display.SqlSource', [$entity->external_identity_source->description]);
$value = $entity->name ?? $entity->description ?? $entity->external_identity_source->description;
return __d('sql_connector', 'display.SqlSource', [$value]);
}


Expand Down
3 changes: 2 additions & 1 deletion app/plugins/EnvSource/src/Model/Table/EnvSourcesTable.php
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,8 @@ public function initialize(array $config): void {
* @return string Display field
*/
public function generateDisplayField(\EnvSource\Model\Entity\EnvSource $entity): string {
return __d('env_source', 'display.EnvSource', [$entity->external_identity_source->description]);
$value = $entity->name ?? $entity->description ?? $entity->external_identity_source->description;
return __d('env_source', 'display.EnvSource', [$value]);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ public function initialize(array $config): void {
* @return string Display field
*/
public function generateDisplayField(\SshKeyAuthenticator\Model\Entity\SshKeyAuthenticator $entity): string {
return $entity->authenticator->description;
return $entity->name ?? $entity->description ?? $entity->authenticator->description;
}

/**
Expand Down
3 changes: 3 additions & 0 deletions app/resources/locales/en_US/error.po
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,9 @@ msgstr "Type {0} is in use as a default (via CO Settings)"
msgid "unknown"
msgstr "Unknown value \"{0}\""

msgid "unresolved.association"
msgstr "Unable to resolve association"

msgid "unknown.identifier"
msgstr "Unknown Identifier \"{0}\""

Expand Down
6 changes: 3 additions & 3 deletions app/resources/locales/en_US/information.po
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@ msgid "cos.select"
msgstr "Please select the collaboration (CO) you wish to manage."

msgid "cmp.config.notice"
msgstr "<a href="{0}">Platform-wide configurations</a> are available in the <a href="{1}">COmanage CO</a>."
msgstr "<a href=\"{0}\">Platform-wide configurations</a> are available in the <a href=\"{1}\">COmanage CO</a>."

msgid "cmp.co.notice"
msgstr "This is the COmanage CO, which is used for platform wide <a href="{0}">configurations</a>."
msgstr "This is the COmanage CO, which is used for platform wide <a href=\"{0}\">configurations</a>."

msgid "entity.id"
msgstr "ID: {0}"
Expand Down Expand Up @@ -88,7 +88,7 @@ msgid "ExternalIdentitySourceRecords.metadata"
msgstr "Metadata"

msgid "ExternalIdentitySourceRecords.view"
msgstr "This is the latest record from the source as cached by Registry. <a href="{0}" target="_top">Retrieve the current record directly from the source</a>."
msgstr "This is the latest record from the source as cached by Registry. <a href=\"{0}\" target=\"_top\">Retrieve the current record directly from the source</a>."

msgid "ExternalIdentitySources.search.attrs.none"
msgstr "The External Identity Source cannot be searched."
Expand Down
95 changes: 87 additions & 8 deletions app/src/Controller/AppController.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,12 @@
use App\Lib\Util\StringUtilities;
use Cake\Controller\Controller;
use Cake\Datasource\Exception\RecordNotFoundException;
use Cake\Http\Exception\UnauthorizedException;
use Cake\Event\EventManager;
use Cake\Http\Exception\UnauthorizedException;
use Cake\ORM\TableRegistry;
use Cake\Routing\Router;
use Cake\Utility\Hash;


/**
* @property \App\Controller\Component\RegistryAuthComponent $RegistryAuth
* @property \App\Controller\Component\BreadcrumbComponent $Breadcrumb
Expand Down Expand Up @@ -273,16 +273,95 @@ public function getCOID(): ?int {
*/
public function getCurrentTable(): \Cake\ORM\Table
{
/** @var string $modelsName */
$modelsName = $this->getName();
return $this->fetchTable($this->getQualifiedName());
}

$alias = $this->getPlugin() !== null
? $this->getPlugin() . '.' . $modelsName
: $modelsName;
/**
* Get the fully-qualified controller/model name with plugin prefix when present.
*
* Examples:
* - Core controller "Users" => "Users"
* - Plugin controller "MyPlugin.Users" => "MyPlugin.Users"
*
* @since COmanage Registry v5.2.0
* @return string
*/
public function getQualifiedName(): string
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this belong in AppController? It feels more like it belongs in StringUtilities or something?

Copy link
Contributor Author

@Ioannis Ioannis Oct 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think getQualifiedName belongs in AppController because it returns the fully qualified name of the controller handling the current request. It’s also used by getCurrentTable to resolve the correct table. I understand your point and how it relates to your next comment. To that end, I added the Qualified Name calculation to StringUtilities, but kept this method here to avoid repeatedly accessing the plugin and name values. I find this approach cleaner.

{
$name = $this->getName();
$plugin = $this->getPlugin();

return $plugin !== null && $plugin !== ''
? $plugin . '.' . $name
: $name;
}


/**
* Check if a given route/URL target is valid and can be resolved.
*
* @param array $target Route parameters to validate
* @return bool True if route is valid and can be resolved
* @since COmanage Registry v5.2.0
*/
public function isValidRoute(array $target): bool
Ioannis marked this conversation as resolved.
Show resolved Hide resolved
{
try {
// Normalize plugin nulls and query args
$params = $target;
if (array_key_exists('plugin', $params) && $params['plugin'] === null) {
unset($params['plugin']);
}
if (isset($params['?'])) {
$params['query'] = $params['?'];
unset($params['?']);
}

return $this->fetchTable($alias);
Router::url($params, true); // will throw if unresolvable
return true;
} catch (\Throwable $e) {
return false;
}
}

/**
* Check if target corresponds to an active application route (is routable).
*
* @param array $target e.g. ['plugin'=>'PipelineToolkit','controller'=>'IdentifierMappers','action'=>'index','?'=>['flange_id'=>3]]
* @return bool
* @since COmanage Registry v5.2.0
*/
public function isActiveRoute(array $target): bool
{
try {
// Normalize params for Router::match
$params = $target;

// Query params should not affect route matching
if (isset($params['?'])) {
unset($params['?']);
}
if (isset($params['query'])) {
unset($params['query']);
}

Router::url($target, false);

$params += [
'plugin' => $params['plugin'] ?? null,
'prefix' => $params['prefix'] ?? null,
'controller' => $params['controller'] ?? null,
'action' => $params['action'] ?? null,
'pass' => array_values(array_filter($params, 'is_int', ARRAY_FILTER_USE_KEY)) ?: [],
];

// If a matching route exists, match() returns an array; otherwise it throws
Router::getRouteCollection()->match($params, []);
return true;
} catch (\Throwable $e) {
return false;
}
}

/**
* @param string $potentialPrimaryLink
Expand Down
Loading