Skip to content

Commit

Permalink
Miscellaneous changes, in particular for Breadcrumbs (CFM-274)
Browse files Browse the repository at this point in the history
  • Loading branch information
Benn Oshrin committed Jan 3, 2024
1 parent f88d8a6 commit 90ad78b
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 50 deletions.
16 changes: 10 additions & 6 deletions app/src/Controller/AppController.php
Original file line number Diff line number Diff line change
Expand Up @@ -219,20 +219,21 @@ public function getPrimaryLink(bool $lookup=false) {

if($lookup) {
foreach($availablePrimaryLinks as $potentialPrimaryLink) {
// $potentialPrimaryLink will be something like 'attribute_collector_id'
// $potentialPrimaryLinkTable will be something like 'CoreEnroller.AttributeCollectors'
$potentialPrimaryLinkTable = $this->$modelsName->getPrimaryLinkTableName($potentialPrimaryLink);
$potentialPlugin = null;

// Try to find a value

if(strstr($potentialPrimaryLink, '.')) {
if(strstr($potentialPrimaryLinkTable, '.')) {
// For looking up values in records here, we want only the attribute
// itself and not the plugin name (used for hacky notation by
// PrimaryLinkTrait::setPrimaryLink(). Note this is a field and not
// a model, but pluginModel() gets us the bit we need.

// Store the plugin for possible later reference.
$potentialPlugin = StringUtilities::pluginPlugin($potentialPrimaryLink);

// We clobber $potentialPrimaryLink to avoid rewriting a bunch of code,
// but probably we should rewrite it.
$potentialPrimaryLink = StringUtilities::pluginModel($potentialPrimaryLink);
$potentialPlugin = StringUtilities::pluginPlugin($potentialPrimaryLinkTable);
}

if($this->request->is('get')) {
Expand Down Expand Up @@ -321,6 +322,9 @@ public function getPrimaryLink(bool $lookup=false) {
if(!empty($this->cur_pl->value)) {
// We found a populated primary link. Store the attribute and break the loop.
$this->cur_pl->attr = $potentialPrimaryLink;
if($potentialPlugin) {
$this->cur_pl->plugin = $potentialPlugin;
}
$this->set('vv_primary_link', $this->cur_pl->attr);
break;
}
Expand Down
124 changes: 84 additions & 40 deletions app/src/Controller/Component/BreadcrumbComponent.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ class BreadcrumbComponent extends Component
protected $injectParents = [];
// Inject title links (immediately before the title breadcrumb)
protected $injectTitleLinks = [];
// Whether parent links are frozen
protected $parentsFrozen = false;

/**
* Callback run prior to rendering the view.
Expand Down Expand Up @@ -117,7 +119,7 @@ public function beforeRender(EventInterface $event) {

if($action != 'index') {
$target = [
'plugin' => null,
'plugin' => $primaryLink->plugin ?? null,
'controller' => $modelsName,
'action' => 'index'
];
Expand All @@ -126,8 +128,12 @@ public function beforeRender(EventInterface $event) {
$target['?'] = [$primaryLink->attr => $primaryLink->value];
}

$label = (!empty($primaryLink->plugin)
? __d(Inflector::underscore($primaryLink->plugin), 'controller.'.$modelsName, [99])
: __d('controller', $modelsName, [99]));

$parents[] = [
'label' => __d('controller', $modelsName, [99]),
'label' => $label,
'target' => $target
];
}
Expand All @@ -140,65 +146,74 @@ public function beforeRender(EventInterface $event) {
}

/**
* Inject a title link based on the display field of an entity into the breadcrumb set.
* Prevent any additional parent links from being added. Intended primarily for
* Controllers that extend StandardController but do not want the standard behavior.
*
* @since COmanage Registry v5.0.0
* @param Table $table Table for $entity
* @param Entity $entity Entity to generate title link for
* @param string $action Action to link to
* @param string $label If set, use this label instead of the entity's displayField
*/

public function injectTitleLink(
$table,
$entity,
string $action='edit',
?string $label=null
) {
$displayField = $table->getDisplayField();

$this->injectTitleLinks[] = [
'target' => [
'plugin' => null,
'controller' => $table->getTable(),
'action' => $action,
$entity->id
],
'label' => $label ?: $entity->$displayField
];
public function freezeParents() {
$this->parentsFrozen = true;
}

/**
* Inject the primary link into the breadcrumb path.
*
* @since COmanage Registry v5.0.0
* @param object link Primary Link (as returned by getPrimaryLink())
* @param object $link Primary Link (as returned by getPrimaryLink())
* @param bool $index Include link to parent index
* @param string $linkLabel Label to use for Primary Link instead of displayField
*/

public function injectPrimaryLink(object $link) {
public function injectPrimaryLink(object $link, bool $index=true, $linkLabel=null) {
if($this->parentsFrozen) {
return;
}

// eg: "People"
$modelsName = StringUtilities::foreignKeyToClassName($link->attr);
$modelPath = $modelsName;

if(!empty($link->plugin)) {
// eg: "CoreEnroller.AttributeCollectors"
$modelPath = $link->plugin . "." . $modelsName;
}

$contain = [];
$primaryName = null;

$linkTable = TableRegistry::getTableLocator()->get($modelsName);
$linkTable = TableRegistry::getTableLocator()->get($modelPath);
$linkObj = $linkTable->get($link->value, ['contain' => $contain]);
$displayField = $linkTable->getDisplayField();

$this->injectParents[] = [
'target' => [
'plugin' => null,
'controller' => $modelsName,
'action' => 'index',
'?' => [
'co_id' => $link->co_id
]
],
'label' => __d('controller', $modelsName, [99])
];
if($index) {
// We need to determine the primary link of the parent, which might or might
// not be co_id

if(method_exists($linkTable, "findPrimaryLink")) {
// If findPrimaryLink doesn't exist, we're probably working with CosTable

$parentLink = $linkTable->findPrimaryLink($linkObj->id);

$this->injectParents[] = [
'target' => [
'plugin' => $parentLink->plugin ?? null,
'controller' => $modelsName,
'action' => 'index',
'?' => [
$parentLink->attr => $parentLink->value
]
],
'label' => StringUtilities::localizeController(
controllerName: $modelsName,
pluginName: $link->plugin ?? null,
plural: true
)
];
}
}

$label = $linkObj->$displayField;
$label = $linkLabel ?? $linkObj->$displayField;

if($modelsName == 'People' || $modelsName == 'ExternalIdentities') {
// We need the Primary Name (or first name found) to render it
Expand All @@ -218,7 +233,7 @@ public function injectPrimaryLink(object $link) {

$this->injectParents[] = [
'target' => [
'plugin' => null,
'plugin' => $link->plugin ?? null,
'controller' => $modelsName,
'action' => 'edit',
$linkObj->id
Expand All @@ -227,6 +242,35 @@ public function injectPrimaryLink(object $link) {
];
}

/**
* Inject a title link based on the display field of an entity into the breadcrumb set.
*
* @since COmanage Registry v5.0.0
* @param Table $table Table for $entity
* @param Entity $entity Entity to generate title link for
* @param string $action Action to link to
* @param string $label If set, use this label instead of the entity's displayField
*/

public function injectTitleLink(
$table,
$entity,
string $action='edit',
?string $label=null
) {
$displayField = $table->getDisplayField();

$this->injectTitleLinks[] = [
'target' => [
'plugin' => null,
'controller' => $table->getTable(),
'action' => $action,
$entity->id
],
'label' => $label ?: $entity->$displayField
];
}

/**
* Set the set of paths that should be skipped when rendering breadcrumbs.
* Paths are specified as regular expressions, eg: '/^\/cos\/select/'
Expand Down
12 changes: 10 additions & 2 deletions app/src/Controller/StandardController.php
Original file line number Diff line number Diff line change
Expand Up @@ -506,8 +506,12 @@ public function generateRedirect($entity) {
if(!empty($link->attr) && !empty($link->value)) {
$redirect['?'] = [$link->attr => $link->value];
}

if(!empty($this->getPlugin())) {
$redirect['plugin'] = $this->getPlugin();
}
}

return $this->redirect($redirect);
}

Expand Down Expand Up @@ -671,7 +675,7 @@ protected function populateAutoViewVars(object $obj=null) {
case 'array':
// Use the provided array of values. By default, we use the values
// for the keys as well, to generate HTML along the lines of
// <option value="Foo">"Foo"</option>
// <option value="Foo">"Foo"</option>. (See also 'hash'.)
$this->set($vvar, array_combine($avv['array'], $avv['array']));
break;
case 'enum':
Expand All @@ -684,6 +688,10 @@ protected function populateAutoViewVars(object $obj=null) {
}
$this->set($vvar, $class::getLocalizedConsts());
break;
case 'hash':
// Like 'array' but we assume we are passed key/value pairs
$this->set($vvar, $avv['hash']);
break;
// "auxiliary" and "select" do basically the same thing, but the former
// returns the full object and the latter just returns a hash suitable
// for a select. "type" is a shorthand for "select" for type_id.
Expand Down
4 changes: 2 additions & 2 deletions app/src/Lib/Traits/PrimaryLinkTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -180,11 +180,11 @@ public function findFilterPrimaryLink(\Cake\ORM\Query $query, array $options) {
* @since COmanage Registry v5.0.0
* @param int $id Object ID
* @param bool $archived Whether to retrieve archived (deleted) records
* @return Entity Primary Link (as an Entity)
* @return object Primary Link information (as an object)
* @throws \InvalidArgumentException
*/

public function findPrimaryLink(int $id, bool $archived=false) {
public function findPrimaryLink(int $id, bool $archived=false): object {
$obj = $this->get($id, ['archived' => $archived]); //->firstOrFail();

// We might have multiple primary link keys (eg for MVEAs), but only one
Expand Down

0 comments on commit 90ad78b

Please sign in to comment.