Skip to content
Permalink
main
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
3 contributors

Users who have contributed to this file

@arlen @Ioannis @benno
557 lines (497 sloc) 22.2 KB
<?php
/**
* COmanage Standard Index Template
*
* Portions licensed to the University Corporation for Advanced Internet
* Development, Inc. ("UCAID") under one or more contributor license agreements.
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership.
*
* UCAID licenses this file to you under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @link https://www.internet2.edu/comanage COmanage Project
* @package match
* @since COmanage Match v1.0.0
* @license Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
*/
/**
* THIS FILE IS MASTERED IN THE COMMON REPOSITORY.
*/
declare(strict_types = 1);
use \Cake\Utility\Inflector;
use \App\Lib\Enum\StatusEnum;
// $this->name = Models
$modelsName = $this->name;
// $tablefk = model_id
$tableFK = Inflector::singularize($vv_tablename) . "_id";
// Do we have records for this index? This will be set to true during render if we do.
// Otherwise, we'll print out a "no records" message.
$recordsExist = false;
// Our default link actions, in order of preference, unless the column config overrides it
$linkActions = ['edit', 'view'];
// Read the index configuration ($indexColumns) for this model
include(TEMPLATES . $modelsName . "/columns.inc");
// $linkFilter is used for models that belong to a specific parent model (eg: co_id)
$linkFilter = [];
if(!empty($vv_primary_link) && !empty($this->request->getQuery($vv_primary_link))) {
$linkFilter = ['?' => [$vv_primary_link => $this->request->getQuery($vv_primary_link)]];
}
function _column_key($modelsName, $c, $tz=null) {
if(strpos($c, "_id", strlen($c)-3)) {
// Key is of the form field_id, use .ct label instead
$k = Inflector::camelize(Inflector::pluralize(substr($c, 0, strlen($c)-3)));
return __('match.ct.'.$k, [1]);
}
// Look for a model specific key first
$label = __('match.fd.'.$modelsName.'.'.$c);
if($label != 'match.fd.'.$modelsName.'.'.$c) {
return $label;
}
if($tz) {
// If there is a timezone aware label, use that
$label = __('match.fd.'.$c.'.tz', [$tz]);
if($label != 'match.fd.'.$c.'.tz') {
return $label;
}
}
// Otherwise look for the general key
return __('match.fd.'.$c);
}
// $flashArgs pass banner messages to the flash element container
$flashArgs = [];
if(!empty($indexBanners)) {
$flashArgs['vv_index_banners'] = $indexBanners;
}
if(!empty($banners)) {
$flashArgs['vv_banners'] = $banners;
}
?>
<?php if(!empty($subnav)): ?>
<div id="subnavigation">
<div class="supertitle">
<h1>
<?php
if(!empty($vv_primary_link_obj)
&& !empty($vv_primary_link_model)
&& $vv_primary_link_model != 'Matchgrids') {
print $vv_primary_link_obj->name;
}
?>
</h1>
</div>
<?php /* Flash Messages are placed below supertitle when subnavigation exists. */ ?>
<?= $this->element('flash', $flashArgs); ?>
<?= $this->element('subnavigation', $subnav); ?>
</div>
<?php endif; ?>
<div class="pageTitleContainer">
<div class="pageTitle">
<?php if(empty($subnav)): ?>
<h1><?= $vv_title; ?></h1>
<?php else: ?>
<h2><?= $vv_title; ?></h2>
<?php endif; ?>
</div>
<?php if($vv_permissions['add']): ?>
<?php
// topLinks menu dropdown / button listing
$action_args = array();
$action_args['vv_attr_mdl'] = "IndexTopLinks";
// Insert additional actions as per the .inc file
if(!empty($topLinks)) {
if(!isset($entity->status) || $entity->status == StatusEnum::Active) {
$actionOrderDefault = $this->Menu->getMenuOrder('Default');
foreach($topLinks as $a) {
if($vv_permissions[ $a['action'] ]) {
$actionOrder = !empty($a['order']) ? $a['order'] : $actionOrderDefault++;
$actionIcon = !empty($a['icon']) ? $a['icon'] : $this->Menu->getMenuIcon('Default');
$actionClass = !empty($a['class']) ? $a['class'] : '';
$actionUrl = '';
$actionLabel = '';
$actionOnClick = []; // used for confirmation dialog
// Generate the link text and urls:
// If we have a .confirm text, we need to generate a confirm dialog box
$confirmKey = 'match.op.'.$a['action'].'.confirm';
$confirmTxt = __($confirmKey);
if($confirmTxt != $confirmKey) {
// We found the localized string
$actionPostBtnArray = ['action' => $a['action']];
$actionUrl = $this->Url->build(['action' => $a['action']]);
// XXX should be configurable which field we put in, maybe displayField?
$action_args['vv_actions'][] = array(
'order' => $actionOrder,
'icon' => $actionIcon,
'url' => 'javascript:void(0);',
'label' => __('match.op.' . $a['action']),
'class' => !empty($actionClass) ? $actionClass . ' nospin' : 'nospin',
'onclick' => array(
'dg_bd_txt' => __($confirmKey, [$entity->id]), // dialog body text
'dg_post_btn_array' => $actionPostBtnArray, // postButton array for building the postButton
'dg_url' => $actionUrl, // action url for building a unique ID
'dg_conf_btn' => __('match.op.confirm'), // dialog confirm button text
'dg_cancel_btn' => __('match.op.cancel'), // dialog cancel button text
'dg_title' => __('match.op.confirm'), // dialog box title
'dg_bd_txt_repl_str' => '' // dialog body text replacement strings
),
);
} elseif(!empty($a['controller'])) {
// We're linking into a related controller
$queryParams = [ $tableFK => $entity->id ];
if(!empty($a['query']) && is_callable($a['query'])) {
$queryParams = $a['query']($vv_cur_mg->id, $entity);
}
$actionLabel = __('match.ct.' . Inflector::camelize(Inflector::pluralize($a['controller'])), [99]);
$actionUrl = $this->Url->build([
'controller' => $a['controller'],
'action' => $a['action'],
'?' => $queryParams
]);
} else {
$actionLabel = __('match.op.' . $a['action']);
$urlAttrs = ['action' => $a['action']];
$urlAttrs = array_merge_recursive($linkFilter, $urlAttrs);
if(!empty($a['query'])) {
$urlAttrs = array_merge_recursive($urlAttrs,$a['query']);
}
$actionUrl = $this->Url->build($urlAttrs);
}
// If a specific label is sent in the config, use it instead
if(!empty($a['label'])) {
$actionLabel = $a['label'];
}
// Set the action link configuration
$action_args['vv_actions'][] = array(
'order' => $actionOrder,
'icon' => $actionIcon,
'url' => $actionUrl,
'label' => $actionLabel,
'class' => $actionClass,
'onclick' => $actionOnClick
);
}
}
}
}
// Add
$addLink = array_merge($linkFilter, ['action' => 'add']);
// Allow model-specific overrides of the add link. If false,
// the override doesn't want the add link to render.
if(isset($addLinkFilter) && is_callable($addLinkFilter)) {
$addLink = $addLinkFilter($addLink, $this->request);
}
if($addLink) {
$action_args['vv_actions'][] = array(
'order' => $this->Menu->getMenuOrder('Add'),
'icon' => $this->Menu->getMenuIcon('Add'),
'url' => $this->Url->build($addLink),
'label' => __('match.op.add.a', __('match.ct.'.$vv_modelname, [1]))
);
}
// Output the topLinks
if(!empty($action_args['vv_actions'])) {
print '<div id="topLinks" class="field-actions">';
print $this->element('menuAction', $action_args);
print '</div>';
}
?>
<?php endif; ?>
</div>
<?php if(empty($subnav)): ?>
<?php /* Flash Messages are placed below the main title when there's no subnavigation. */ ?>
<?= $this->element('flash', $flashArgs); ?>
<?php endif; ?>
<!-- Search block -->
<?php if(!empty($enableSearch)): ?>
<?= $this->element('search'); ?>
<?php endif; // $enableSearch ?>
<!-- Index table -->
<div class="table-container">
<table id="<?= $vv_tablename . '-table'; ?>">
<tr>
<?php foreach($indexColumns as $col => $cfg): ?>
<th<?= !empty($cfg['cssClass']) ? ' class="' . $cfg['cssClass'] . '"' : ''; ?>><?php
$label = !empty($cfg['label']) ? $cfg['label'] : _column_key($modelsName, $col, $vv_tz);
if(isset($cfg['sortable']) && $cfg['sortable']) {
if(is_string($cfg['sortable'])) {
print $this->Paginator->sort($cfg['sortable'], $label);
} else {
print $this->Paginator->sort($col, $label);
}
} else {
print $label;
}
?></th>
<?php endforeach; ?>
<th class="actions"><?= __('match.fd.action'); ?></th>
</tr>
<?php foreach(${$vv_tablename} as $entity): ?>
<?php
// Normally links just require the entity ID, but sometimes we need to
// explicitly add the linkFilter
$linkArgs = [$entity->id];
if(isset($forcePrimaryLink) && $forcePrimaryLink) {
$linkArgs = array_merge_recursive($linkArgs, $linkFilter);
}
?>
<tr>
<?php foreach($indexColumns as $col => $cfg): ?>
<td<?= !empty($cfg['cssClass']) ? ' class="' . $cfg['cssClass'] . '"' : ''; ?>>
<?php
switch($cfg['type']) {
case 'boolean':
if(!empty($entity->$col) && $entity->$col) {
print __('match.en.'.$cfg['class'].'.1');
} else {
print __('match.en.'.$cfg['class'].'.0');
}
break;
case 'datetime':
// XXX dates can also be rendered as eg $entity->created->format(DATE_RFC850);
print $this->Time->nice($entity->$col, $vv_tz);
break;
case 'enum':
if($entity->$col) {
$badge_color_class = __('match.en.'.$cfg['class'].'.'.$entity->$col . '.badge');
$title = __('match.en.'.$cfg['class'].'.'.$entity->$col);
if(!empty($badge_color_class) && strpos($badge_color_class, '.badge') === false) {
print $this->Badge->badgeIt($title, $this->Badge->getBadgeColor($badge_color_class));
} else {
print $title;
}
}
break;
case 'fk':
// Assuming $col is of the form foo_id, look to see if the corresponding
// AutoViewVar $foos is set, and if so render the lookup value instead
$f = null;
if(preg_match('/^(.*?)_id$/', $col, $f)) {
$avv = Inflector::variable(Inflector::pluralize($f[1]));
if(!empty(${$avv}[$entity->$col])) {
// We found the viewvar (eg: $foos), and it has a corresponding value
// (eg: $foos[3]), so render it
print ${$avv}[$entity->$col]; // XXX filter_var?
} else {
// No match, just render the value
print $entity->$col;
}
} else {
// Just print the value
print $entity->$col;
}
break;
case 'button':
if(!empty($entity->$col)) {
$buttonAttrs = [];
$buttonText = $entity->$col;
if(!empty($cfg['button']['attrs'])) {
$buttonAttrs = $cfg['button']['attrs'];
}
$buttonAttrs['type'] = 'button';
if(!empty($cfg['button']['text']) && $cfg['button']['text'] != 'fieldVal') {
$buttonText = $cfg['button']['text'];
}
if(!empty($cfg['truncate']) && is_int($cfg['truncate'])) {
// We check for $truncate + 1 because there's no point trimming
// the last character if we're just going to replace it with ...
$buttonText = (strlen($buttonText) > $cfg['truncate'] + 1) ? substr($buttonText,0,$cfg['truncate']).'...' : $buttonText;
}
if(!empty($cfg['button']['popover'])) {
if($cfg['button']['popover'] == 'fieldVal') {
$buttonAttrs['data-bs-content'] = $entity->$col;
} else {
$buttonAttrs['data-bs-content'] = $cfg['button']['popover'];
}
$label = !empty($cfg['label']) ? $cfg['label'] : _column_key($modelsName, $col, $vv_tz);
$buttonAttrs['title'] = $label;
$buttonAttrs['data-bs-toggle'] = 'popover';
$buttonAttrs['data-bs-container'] = 'body';
$buttonAttrs['data-bs-placement'] = 'top';
$buttonAttrs['data-bs-animation'] = 'false';
}
print $this->Form->button($buttonText, $buttonAttrs);
}
break;
case 'link':
case 'echo':
default:
// By default our label is the column value, but it might be overridden
$label = $entity->$col;
if(!empty($cfg['model']) && !empty($cfg['field'])) {
$m = $cfg['model'];
$f = $cfg['field'];
if(!empty($entity->$m->$f)) {
$label = $entity->$m->$f;
}
}
$linked = false;
if($cfg['type'] == 'link') {
foreach($linkActions as $a) {
// Does this user have permission for this action?
if($vv_permissions[$a]) {
print $this->Html->link($label, array_merge_recursive(['action' => $a], $linkArgs));
$linked = true;
break 2;
}
}
}
if(!$linked) {
// Just echo the value
print $label;
}
break;
// XXX dates can be rendered as eg $entity->created->format(DATE_RFC850);
}
?>
</td>
<?php endforeach; // $indexColumns ?>
<td class="actions">
<?php
// Action list for command menu dropdown / button listing
$action_args = array();
$action_args['vv_attr_mdl'] = "Index";
$action_args['vv_attr_id'] = $entity->id;
// Edit
if($vv_permissions['edit']) {
$action_args['vv_actions'][] = array(
'order' => $this->Menu->getMenuOrder('Edit'),
'icon' => $this->Menu->getMenuIcon('Edit'),
'url' => $this->Url->build(array_merge_recursive(['action' => 'edit'], $linkArgs)),
'label' => __('match.op.edit')
);
} elseif($vv_permissions['view']) {
$action_args['vv_actions'][] = array(
'order' => $this->Menu->getMenuOrder('View'),
'icon' => $this->Menu->getMenuIcon('View'),
'url' => $this->Url->build(array_merge_recursive(['action' => 'view'], $linkArgs)),
'label' => __('match.op.view')
);
}
// Duplicate
if(isset($vv_permissions['duplicate']) && $vv_permissions['duplicate']) {
$action_args['vv_actions'][] = array(
'order' => $this->Menu->getMenuOrder('Duplicate'),
'icon' => $this->Menu->getMenuIcon('Duplicate'),
'url' => $this->Url->build(array_merge_recursive(['action' => 'duplicate'], $linkArgs)),
'label' => __('match.op.duplicate')
);
}
// Insert additional actions as per the .inc file
if(!empty($indexActions)) {
if(!isset($entity->status) || $entity->status == StatusEnum::Active) {
$actionOrderDefault = $this->Menu->getMenuOrder('Default');
foreach($indexActions as $a) {
if($vv_permissions[ $a['action'] ]) {
$actionOrder = !empty($a['order']) ? $a['order'] : $actionOrderDefault++;
$actionIcon = !empty($a['icon']) ? $a['icon'] : $this->Menu->getMenuIcon('Default');
$actionClass = !empty($a['class']) ? $a['class'] : '';
$actionUrl = '';
$actionLabel = '';
$actionOnClick = []; // used for confirmation dialog
// Generate the link text and urls:
// If we have a .confirm text, we need to generate a confirm dialog box
$confirmKey = 'match.op.'.$a['action'].'.confirm';
$confirmTxt = __($confirmKey);
if($confirmTxt != $confirmKey) {
// We found the localized string
$actionPostBtnArray = array_merge_recursive(['action' => $a['action']], $linkArgs);
$actionUrl = $this->Url->build(array_merge_recursive(['action' => $a['action']], $linkArgs));
// XXX should be configurable which field we put in, maybe displayField?
$action_args['vv_actions'][] = array(
'order' => $actionOrder,
'icon' => $actionIcon,
'url' => 'javascript:void(0);',
'label' => __('match.op.' . $a['action']),
'class' => !empty($actionClass) ? $actionClass . ' nospin' : 'nospin',
'onclick' => array(
'dg_bd_txt' => __($confirmKey, [$entity->id]), // dialog body text
'dg_post_btn_array' => $actionPostBtnArray, // postButton array for building the postButton
'dg_url' => $actionUrl, // action url for building a unique ID
'dg_conf_btn' => __('match.op.confirm'), // dialog confirm button text
'dg_cancel_btn' => __('match.op.cancel'), // dialog cancel button text
'dg_title' => __('match.op.confirm'), // dialog box title
'dg_bd_txt_repl_str' => '' // dialog body text replacement strings
),
);
} elseif(!empty($a['controller'])) {
// We're linking into a related controller
$queryParams = [ $tableFK => $entity->id ];
if(!empty($a['query']) && is_callable($a['query'])) {
$queryParams = $a['query']($vv_cur_mg->id, $entity);
}
$actionLabel = __('match.ct.' . Inflector::camelize(Inflector::pluralize($a['controller'])), [99]);
$actionUrl = $this->Url->build([
'controller' => $a['controller'],
'action' => $a['action'],
'?' => $queryParams
]);
} else {
$actionLabel = __('match.op.' . $a['action']);
$actionUrl = $this->Url->build(
array_merge_recursive(['action' => $a['action']], $linkArgs)
);
}
// If a specific label is sent in the config, use it instead
if(!empty($a['label'])) {
$actionLabel = $a['label'];
}
// Set the action link configuration
$action_args['vv_actions'][] = array(
'order' => $actionOrder,
'icon' => $actionIcon,
'url' => $actionUrl,
'label' => $actionLabel,
'class' => $actionClass,
'onclick' => $actionOnClick
);
}
}
}
}
// Delete
if($vv_permissions['delete']) {
$actionPostBtnArray = array_merge_recursive(['action' => 'delete'], $linkArgs);
$actionUrl = $this->Url->build(array_merge_recursive(['action' => 'delete'], $linkArgs));
$action_args['vv_actions'][] = array(
'order' => $this->Menu->getMenuOrder('Delete'),
'icon' => $this->Menu->getMenuIcon('Delete'),
'url' => 'javascript:void(0);',
'label' => __('match.op.delete'),
'class' => 'deletebutton nospin',
'onclick' => array(
'dg_bd_txt' => __('match.op.delete.confirm', [$entity->id]),
'dg_post_btn_array' => $actionPostBtnArray,
'dg_url' => $actionUrl,
'dg_conf_btn' => __('match.op.remove'),
'dg_cancel_btn' => __('match.op.cancel'),
'dg_title' => __('match.op.remove'),
'dg_bd_txt_repl_str' => ''
),
);
}
if(!empty($action_args['vv_actions'])) {
print '<div class="field-actions">';
print $this->element('menuAction', $action_args);
print '</div>';
}
?>
</td>
</tr>
<?php $recordsExist = true; ?>
<?php endforeach; // $$vv_tablename ?>
<?php if(!$recordsExist): ?>
<tr><td colspan="<?= count($indexColumns); ?>"><?= __('match.in.records.none') ?></td></tr>
<?php endif; ?>
</table>
</div>
<?php
print $this->element("pagination");