<?php
// {{{ Header
/*
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
| SIERRA : PHP Application Framework http://code.google.com/p/sierra-php |
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
| Copyright 2005 Jason Read |
| |
| Licensed 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. |
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
*/
// }}}
// {{{ Imports
require_once('SRA_LookupProcessor.php');
require_once('SRA_ListLookupProcessorAction.php');
require_once('SRA_ListLookupProcessorData.php');
require_once('SRA_QueryBuilder.php');
// }}}
// {{{ Constants
/**
* the default form name
* @type string
*/
define('SRA_LIST_LOOKUP_PROCESSOR_DEFAULT_FORM_NAME', 'LLP');
/**
* identifies a GET form
* @type string
*/
define('SRA_LIST_LOOKUP_PROCESSOR_FORM_GET', 'get');
/**
* identifies a POST form
* @type string
*/
define('SRA_LIST_LOOKUP_PROCESSOR_FORM_POST', 'post');
/**
* the default form type
* @type string
*/
define('SRA_LIST_LOOKUP_PROCESSOR_DEFAULT_FORM_TYPE', SRA_LIST_LOOKUP_PROCESSOR_FORM_POST);
/**
* the default limit if none is specified
* @type int
*/
define('SRA_LIST_LOOKUP_PROCESSOR_DEFAULT_LIMIT', 10);
/**
* the default offset if none is specified
* @type int
*/
define('SRA_LIST_LOOKUP_PROCESSOR_DEFAULT_OFFSET', 0);
/**
* the default page field name if none is specified
* @type int
*/
define('SRA_LIST_LOOKUP_PROCESSOR_DEFAULT_PAGE', 'pg');
/**
* the default sort method if none is specified
* @type string
*/
define('SRA_LIST_LOOKUP_PROCESSOR_DEFAULT_SORT', 'asc');
/**
* the default name of the template variable to store the LLP results to
* @type string
*/
define('SRA_LIST_LOOKUP_PROCESSOR_DEFAULT_TPL_VAR', 'LLP_DATA');
/**
* identifies dynamic attribute parameters
* @type string
*/
define('SRA_LIST_LOOKUP_PROCESSOR_DYN_STR', 'dyn');
/**
* primary key value identifying that a new entity should be rendered
* @type string
*/
define('SRA_LIST_LOOKUP_PROCESSOR_NEW_PK', 'new');
/**
* regular expression used to parse field names for dyn attributes
* @type string
*/
define('SRA_LIST_LOOKUP_PROCESSOR_DYN_REGEX', '/^(.*)\${attr(|.*)?}(.*)/i');
/**
* form prefix used to identify a dynamic ascending sorting constraint. this
* value will be followed by the attribute name in a multi-sort environment
* @type string
*/
define('SRA_LIST_LOOKUP_PROCESSOR_DYNAMIC_ASC_SORT_CONSTRAINT_PREFIX', 'llp_dynamic_sort_asc');
/**
* form prefix used to identify a dynamic descending sorting constraint. this
* value will be followed by the attribute name in a multi-sort environment
* @type string
*/
define('SRA_LIST_LOOKUP_PROCESSOR_DYNAMIC_DESC_SORT_CONSTRAINT_PREFIX', 'llp_dynamic_sort_desc');
/**
* form prefix used to identify the sort order field. this value will be followed
* by the attribute name
* @type string
*/
define('SRA_LIST_LOOKUP_PROCESSOR_DYNAMIC_SORT_ORDER_FIELD_PREFIX', 'llp_dynamic_sort_order');
/**
* prefix of the form field that identifies the name of the field containing the primary keys of the
* selected entities for a global action
* @type string
*/
define('SRA_LIST_LOOKUP_PROCESSOR_GLOBAL_ACTION_SELECT_FIELD_NAME_PREFIX', 'llp_global_action_select_');
/**
* name of the select all form field checkbox
* @type string
*/
define('SRA_LIST_LOOKUP_PROCESSOR_GLOBAL_ACTION_SELECT_ALL_FIELD_NAME', 'llp_global_action_select_all');
/**
* name of the hidden field to identify the pk id of the entity selected for an action
* @type string
*/
define('SRA_LIST_LOOKUP_PROCESSOR_SELECT_FIELD_NAME', 'llp_select_action_id');
/**
* name of the hidden field to identify the action that was invoked
* @type string
*/
define('SRA_LIST_LOOKUP_PROCESSOR_SELECT_ACTION_FIELD_NAME', 'llp_select_action');
/**
* name of the hidden field to identify the action invoked was global
* @type string
*/
define('SRA_LIST_LOOKUP_PROCESSOR_SELECT_ACTION_GLOBAL_FIELD_NAME', 'llp_select_action_global');
/**
* field name prefix identifying entity fields that should be updated
* @type string
*/
define('SRA_LIST_LOOKUP_PROCESSOR_UPDATE_FIELD_PREFIX', 'llp_u');
/**
* field name prefix identifying fields that should be removed from the $form when submitted
* @type string
*/
define('SRA_LIST_LOOKUP_PROCESSOR_IGNORE_PREFIX', 'tmp_');
// }}}
// {{{ SRA_ListLookupProcessor
/**
* A powerful lookup processor that can be utilized to display lists of entities
* in any format including the ability to segment the view into multiple pages.
* The following lookup "params" are applicable to this SRA_LookupProcessor (see
* constants section for default values for these params if applicable):
*
* ------ PARAMS ------
* Name Type Value Description
* {csv attrs} llp-constraint-{mask} {value*} used to define attribute value constraints. the {mask} is a bit mask
* defining 1 or more of the SRA_QUERY_BUILDER_CONSTRAINT_TYPE_* bits
* that should apply to the constraint. to determine a bit value for
* multiple constraint types, simply | (bitwise or) the constraints
* which will result in the sum of the constraints. This constraint
* is for DEFAULT values, which can be overriden by the dynamic
* constraints (llp-dconstraint-{mask}). Review the SRA_QueryBuilderConstraint
* API documentation for more details on the different types of
* constraints
* limit llp-constraint {value} default limit (max # of results)
* offset llp-constraint {value} default offset
* {csv attrs*} llp-fconstraint-{mask} {value} FIXED constraints. cannot be overriden by the default or dynamic.
* should be used to enforce data security in order to avoid allowing
* invalid access to view and/or manipulate entities. for example,
* adding a user contraint as described below: ${user}
* limit llp-fconstraint {value} fixed limit (max # of results) - overrides both default and dynamic limits
* {csv attrs|dynn}llp-dconstraint-{mask} {field name*} DYNAMIC constraints. these will override identical DEFAULT constraints
* limit llp-dconstraint {field name} name of the form field specifying the limit
* (max # of results) - overrides default limit
* page llp-dconstraint {field name} name of the form field specifying the current page # - used
* to determine offset
* name llp-form {form name} the name that should be assigned to the form enclosing the result data
* type llp-form (get|post) form type for dynamic variables and actions. default is get
* actionOrder llp-form-action {csv actions} defines the order of the actions (select + any {actions}s defined) as
* they should be rendered if "renderActions" is invoked. this should
* be a comma separated value like "view1,view2,delete,select". if not
* specified, the order will be the order in which the views are defined,
* followed by the global action selector if applicable
* globalActionOrder llp-form-action {csv actions} if the order to display the global actions should be different (or
* include only a subset of the possible actions), that order/subset
* may be defined using this parameter
* globalActions llp-form-action (1|0) whether or global actions should be available to users. global actions
* are rendered using a checkbox next to each set of action links that the
* user may select in order to invoke an action for more than one selected
* entity
* {action} llp-form-action {field name} unique identifier for an action that can be invoked from the list
* view. actions can include such activities as deleting/updating/viewing
* of entities. what occurs when this action is invoked is determined by
* the {action}Type value which is a bitmask containing any of the
* SRA_LIST_LOOKUP_PROCESSOR_ACTION_TYPE_* constant values defined in
* SRA_ListLookupProcessorAction.php
* {action}Type llp-form-action {type bitmask} one or more of the SRA_LIST_LOOKUP_PROCESSOR_ACTION_TYPE_* constant values
* represented as a bitmask identifying what should happen when this action
* is invoked
* {action}Apost llp-form-action {html} html code to render after the close </a> tag
* {action}Apre llp-form-action {html} html code to render before the <a... /> tag
* {action}Class llp-form-action {html class} the html class to use in the <a.../ > tag generated for the view link
* {action}Link llp-form-action {resource} the resource to use as the text for the view link
* {action}Btn llp-form-action (1|0) whether or not to render the action link as a button. the default behavior
* is to render it as a link
* {action}Img llp-form-action {img src} the img src to use for the action link (only 1, {action}Img or
* {action}Link should be specified)
* {action}ImgClass llp-form-action {html class} css class to assign to the {action}Img
* {action}Alt llp-form-action {resource} the resource to use action the alt/title attribute for {action}Img
* {action}GlobalAlt llp-form-action {resource} {action}Alt for global links: optional - {action}Alt will be used if not specified
* {action}MsgCmpl llp-form-action {resource} the resource to display when an action has been invoked successfully. if the {action} includes a view, this message will only be displayed once the ACTION has been processed successfully. for example, an insert completed, an update performed
* {action}MsgCnfm llp-form-action {resource} the resource to display when the action is initiated (clicked) - single quotes, if used, must be prefixed by backslash
* {action}GlobalMsgCmpl llp-form-action {resource} {action}MsgCmpl for global links: optional - {action}MsgCmpl will be used if not specified
* {action}GlobalMsgCnfm llp-form-action {resource} {action}MsgCnfm for global links: optional - {action}MsgCnfm will be used if not specified
* {action}Post llp-form-action {html} html code to render before the close </a> tag
* {action}Pre llp-form-action {html} html code to render after the <a... /> tag
* {action}View llp-form-action {view id} the id of the view that should be displayed if the {action}Type bitmask
* includes any of the SRA_LIST_LOOKUP_PROCESSOR_ACTION_TYPE_VIEW* constants
* {action}ViewFwd llp {view id} the id of the view that should be displayed if an action has been invoked successfully
* {action}NonGlobal llp-form-action (1|0) default: 0: whether or not this action cannot be applied globally (NOTE: it will still show up in the global actions links unless explicitely specified otherwise)
* rowCycle llp {cycle id} optional cycle identifier for the classes below. if not specified, "rowClass" will be the identifier
* rowClass llp {html class} comma separated values specifying the classes (in that order) that should be applied to rows in the resulting data table
* rowClassTag llp {html tr attr} an optional alternate "tr" attribute tag that should be used in place of "class" for "rowClass"
* colCycle llp {cycle id} optional cycle identifier for the classes below. if not specified, "colClass" will be the identifier
* colClass llp {html class} comma separated values specifying the classes (in that order) that should be applied to cols in the resulting data table
* colClassTag llp {html tr attr} an optional alternate "td" attribute tag that should be used in place of "class" for "colClass"
* [attr]ColCycle llp {cycle id} the following 3 parameters are for attribute specific column formatting: an optional cycle identifier for the classes below. if not specified, "[attr]ColClass" will be the identifier
* [attr]ColClass llp {html class} comma separated values specifying the classes (in that order) that should be applied to [attr] cols in the resulting data table
* [attr]ColClassTag llp {html tr attr} an optional alternate "td" attribute tag that should be used in place of "class" for "colClass"
* actionsPos llp ([N]|L|R) the position for the actions, either the leftmost (L) or rightmost (R),
* or a numbered column (column #s begin at 0) column
* actionEncl llp {html elem} an html element to enclose the actions in
* actionsColCycle llp {cycle id} if actionsColClass is not specified, "colClass" will be used for the actions column: optional cycle identifier for the actions cell below. if not specified, "actionsColClass" will be the identifier
* actionsColClass llp {html class} comma separated values specifying the classes (in that order) that should be applied to action cols in the resulting data table
* actionsColClassTag llp {html tr attr} an optional alternate "td" attribute tag that should be used in place of "class" for "actionsColClass"
* resultsResource llp {string} results resource string. the following strings will be replaced using SRA_ResourceBundle::getString():
* {$start} : start position of the results
* {$end} : end position of the results
* {$count} : total # of results
* {$page} : current page number
* {$pageCount} : total # of pages
* this string can be displayed in any of the following templates:
* sra-list-table-header.tpl
* sra-list-table-footer.tpl
* sra-list-table-cmds.tpl
* see the corresponding documentation in these template for details
* sortLastSelPrec llp (1|0) whether or not the last sort attribute should be given highest or lowest
* precedence in the sort order sequence. the default value for this parameter
* is FALSE, meaning the last attribute that the user selects to sort on will
* be the last sort column in the sql query that is generated. changing this
* parameter to TRUE (1), will result in that column being the first sort
* column in the sql query
*
*
* a SRA_ListLookupProcessorData instance representing the results data will be
* set in the template context under the variable name SRA_LIST_LOOKUP_PROCESSOR_DEFAULT_TPL_VAR
* at the completion of the lookup method invocation
*
* Comments:
* JOINS: multiple separate constraints are joined using AND. OR joins should
* be specified in a single constraint with comma separated values
* Dyn & Def: dynamic and default constraints work together as follows: if a matching
* constraint type and attribute list is found between the two, the
* default values applied for those dynamic constraints are those
* specified for the default constraints. if there is no matching
* dynamic constraint for a given default, the default constraint will
* behave identical to a fixed constraint.
* fixed: Fixed constraints always take precedence over dynamic and default constraints
* *csv attrs: comma separated list of attribute names (no spaces should be used between values)
* *value: use commas to deliminate multiple possible values (OR join will be applied)
* user id can be specified using the tag: "${user}" which will be
* dynamically substituted for the actual user id as returned by
* SRA_Authenticator::getUserId()
* *field name: if the name specified is "dyn[n]" (where n is a sequential value used so that
* no two "dyn" values are the same), the attributes will be dynamically
* determined based on the field name value specified, where the tag
* "${attr}" located in that value will be the name of the attribute
* and multiple attribute names can be specified using repeating
* attribute tags specified with "${attr|{delim text}}", where
* {delim text} should be the text used to separate each attribute
* name. For example: "attrs_${attr|-}" would signify that attributes
* should be determined for the constraint where the field name starts
* with "attrs_" followed by a dash separated list of attribute names:
* e.g. the value of <input name="attrs_fname-mname-lname" /> would
* be applied as a constraint against the 3 attributes named "fname"
* "mname" and "lname". If the field is an array (auto-cast to an
* array if the end of the field name includes "[]" - e.g. name="fname[]"),
* or if multiple attributes are specified, the join method used
* with the multiple values/attributes will be OR. Multiple separate
* constraints are joined using AND
*
* @author Jason Read <hide@address.com>
* @package sierra.model
*/
class SRA_ListLookupProcessor extends SRA_LookupProcessor {
// {{{ Attributes
// public attributes
// private attributes
/**
* the current column index
* @type int
*/
var $_colIndex = 0;
/**
* used to cycle through classes
* @type array
*/
var $_classCycles = array();
/**
* used to store the data associated with the lookup
* @type SRA_ListLookupProcessorData
*/
var $_llpData;
/**
* used to store unique prefixes for new entities
* @type int
*/
var $_newPrefixes = 1;
// }}}
// {{{ Operations
// SRA_ListLookupProcessor
/**
* invoked parent constructor
* @param util/SRA_Params $params see SRA_LookupProcessor api
* @param string $entityName see SRA_LookupProcessor api
* @access public
*/
function SRA_ListLookupProcessor(& $params, $entityName) {
parent::SRA_LookupProcessor($params, $entityName);
}
// }}}
// public operations
// {{{ lookup
/**
* Returns all of the entities of type {$entityName} applicable to the current
* list view as configured and determined by the values specified in $params
* @access public static
* @return {$entityName}[]
*/
function lookup() {
$formParams =& $this->_params->getTypeSubset('llp-form', TRUE);
$llpParams =& $this->_params->getTypeSubset('llp', TRUE);
$actionParams =& $this->_params->getTypeSubset('llp-form-action', TRUE);
$constraints =& $this->_params->getTypeSubset('llp-constraint', TRUE);
$dconstraints =& $this->_params->getTypeSubset('llp-dconstraint', TRUE);
$fconstraints =& $this->_params->getTypeSubset('llp-fconstraint', TRUE);
$formType = $formParams->getParam('type', SRA_LIST_LOOKUP_PROCESSOR_DEFAULT_FORM_TYPE);
$form =& $_GET;
if ($formType == SRA_LIST_LOOKUP_PROCESSOR_FORM_POST) {
$form =& $_POST;
}
// actions
$actions = array();
$aparams = $actionParams->getParams();
foreach ($aparams as $id => $val) {
if (isset($aparams[$id . 'Type'])) {
$actions[$id] = new SRA_ListLookupProcessorAction($id, $aparams["${id}Apost "],
$aparams["${id}Apre "], $aparams["${id}Class "],
$aparams["${id}Link"], $aparams["${id}Btn "] == '1',
$aparams["${id}Img"], $aparams["${id}ImgClass "],
$aparams["${id}Alt"], $aparams["${id}GlobalAlt"],
$aparams["${id}MsgCmpl"], $aparams["${id}MsgCnfm"],
$aparams["${id}GlobalMsgCmpl"], $aparams["${id}GlobalMsgCnfm"],
$aparams["${id}Post"], $aparams["${id}Pre"],
$aparams["${id}Type"], $aparams["${id}View"],
$aparams["${id}ViewFwd"], $aparams["${id}NonGlobal"] == '1');
}
}
if ($formParams->getParam('globalActions', '0') == '1') {
$actions['select'] = 1;
}
if ($formParams->getParam('actionOrder')) {
$actionOrder = explode(',', $formParams->getParam('actionOrder'));
$orderedActions = array();
foreach($actionOrder as $key) {
$key = trim($key);
if (isset($actions[$key])) {
$orderedActions[] =& $actions[$key];
}
else {
$msg = "SRA_LookupProcessor::lookup: SRA_Error - Unknown action in actionOrder ${key}";
SRA_Error::logError($msg, __FILE__, __LINE__);
}
}
}
else {
$orderedActions =& $actions;
}
if ($formParams->getParam('globalActionOrder')) {
$globalActionOrder = explode(',', $formParams->getParam('globalActionOrder'));
$globalOrderedActions = array();
foreach($globalActionOrder as $key) {
$key = trim($key);
if (isset($actions[$key])) {
$globalOrderedActions[] =& $actions[$key];
}
else {
$msg = "SRA_LookupProcessor::lookup: SRA_Error - Unknown action in globalActionOrder ${key}";
SRA_Error::logError($msg, __FILE__, __LINE__);
}
}
}
else {
$globalOrderedActions =& $orderedActions;
}
// determine limit
$lfield = $dconstraints->getParam('limit');
$limit = $fconstraints->getParam('limit');
if (!$limit && ($lfield && isset($form[$lfield]))) {
$limit = $form[$lfield];
}
if (!$limit) {
if ($this->_params->getParam('limitMin')) {
$limit = $this->_params->getParam('limitMin');
}
else {
$limit = $constraints->getParam('limit', SRA_LIST_LOOKUP_PROCESSOR_DEFAULT_LIMIT);
}
}
// determine offset
$offset = $constraints->getParam('offset', SRA_LIST_LOOKUP_PROCESSOR_DEFAULT_OFFSET);
$pfield = $dconstraints->getParam('page', SRA_LIST_LOOKUP_PROCESSOR_DEFAULT_PAGE);
if (isset($form[$pfield]) && is_numeric($form[$pfield])) {
$page = (int) $form[$pfield];
$offset = (($page - 1) * $limit);
}
$constraints =& $this->_params->getTypeSubset('llp-constraint-', TRUE);
$dconstraints =& $this->_params->getTypeSubset('llp-dconstraint-', TRUE);
$fconstraints =& $this->_params->getTypeSubset('llp-fconstraint-', TRUE);
// determine lookup constraints
$lookupConstraints = array();
// fixed lookup constraints
$keys = array_keys($fconstraints->_params);
foreach ($keys as $key) {
$attrs = explode(',', $key);
sort($attrs);
$lookupConstraints[implode(',', $attrs)] = $fconstraints->_params[$key];
$lookupConstraints[implode(',', $attrs)]['val'] = explode(',', $fconstraints->getParam($key));
}
// default lookup constraints
$keys = array_keys($constraints->_params);
foreach ($keys as $key) {
$attrs = explode(',', $key);
sort($attrs);
$lkey = implode(',', $attrs);
if (!isset($lookupConstraints[$lkey])) {
$lookupConstraints[$lkey] = $constraints->_params[$key];
$lookupConstraints[$lkey]['val'] = explode(',', $constraints->getParam($key));
$lookupConstraints[$lkey]['default'] = TRUE;
}
}
// dynamic lookup constraints
$keys = $dconstraints->getKeys();
$fkeys = array_keys($form);
$fieldVals = array();
foreach ($keys as $key) {
$param = $dconstraints->getParam($key);
$attrs = explode(',', $param);
$vals = FALSE;
if (SRA_Util::beginsWith($key, 'dyn')) {
$vals = array();
preg_match(SRA_LIST_LOOKUP_PROCESSOR_DYN_REGEX, $dconstraints->getParam($key), $matches);
foreach ($fkeys as $fkey) {
if (strpos($fkey, SRA_LIST_LOOKUP_PROCESSOR_UPDATE_FIELD_PREFIX) === FALSE &&
((!$matches[1] || SRA_Util::beginsWith($fkey, $matches[1])) &&
(!$matches[3] || SRA_Util::endsWith($fkey, $matches[3])))) {
$attrName = $fkey;
if ($matches[1]) {
$attrName = substr($attrName, strlen($matches[1]));
}
if ($matches[3]) {
$attrName = substr($attrName, 0, strlen($attrName) - strlen($matches[1]) + 1);
}
if ($matches[2]) {
$attrs = explode(substr($matches[2], 1), $attrName);
}
else {
$attrs = array($attrName);
}
sort($attrs);
$lkey = implode(',', $attrs);
if ((!isset($lookupConstraints[$lkey]) || $lookupConstraints[$lkey]['default']) && isset($form[$fkey]) && strlen($form[$fkey])) {
$lookupConstraints[$lkey] = $dconstraints->_params[$key];
$lookupConstraints[$lkey]['val'] = $form[$fkey];
}
$fieldVals[$fkey] = $lookupConstraints[$lkey]['val'];
}
}
}
else {
sort($attrs);
$lkey = implode(',', $attrs);
if ((!isset($lookupConstraints[$lkey]) || $lookupConstraints[$lkey]['default']) && $form[$dconstraints->getParam[$key]]) {
$lookupConstraints[$lkey] = $dconstraints->_params[$key];
$lookupConstraints[$lkey]['val'] = $form[$dconstraints->getParam[$key]];
}
$fieldVals[$dconstraints->getParam[$key]] = $lookupConstraints[$lkey]['val'];
}
}
$queryConstraintGroups = array();
// dynamic sorting constraints
$keys = array_keys($form);
$dynAscAttrs = array();
$dynDescAttrs = array();
$sortOrder = array();
foreach ($keys as $key) {
if ($form[$key] && (SRA_Util::beginsWith($key, SRA_LIST_LOOKUP_PROCESSOR_DYNAMIC_ASC_SORT_CONSTRAINT_PREFIX) ||
SRA_Util::beginsWith($key, SRA_LIST_LOOKUP_PROCESSOR_DYNAMIC_DESC_SORT_CONSTRAINT_PREFIX) ||
SRA_Util::beginsWith($key, SRA_LIST_LOOKUP_PROCESSOR_DYNAMIC_SORT_ORDER_FIELD_PREFIX))) {
if (SRA_Util::beginsWith($key, SRA_LIST_LOOKUP_PROCESSOR_DYNAMIC_ASC_SORT_CONSTRAINT_PREFIX)) {
$dynAscAttrs[] = $form[$key];
}
else if (SRA_Util::beginsWith($key, SRA_LIST_LOOKUP_PROCESSOR_DYNAMIC_DESC_SORT_CONSTRAINT_PREFIX)) {
$dynDescAttrs[] = $form[$key];
}
else {
if (!in_array($form[$key], $sortOrder)) {
$sortOrder[str_replace(SRA_LIST_LOOKUP_PROCESSOR_DYNAMIC_SORT_ORDER_FIELD_PREFIX, '', $key)] = $form[$key];
}
}
}
}
$dynamicSortAttrs = array();
if (count($dynAscAttrs) || count($dynDescAttrs)) {
$queryConstraints = array();
$idx = 0;
$skeys = array_keys($sortOrder);
foreach ($dynAscAttrs as $attr) {
$idx++;
if (count($sortOrder)) {
foreach ($skeys as $skey) {
if ($sortOrder[$skey] == $attr) {
$idx = (int) $skey;
}
}
}
$dynamicSortAttrs[$attr] = SRA_QUERY_BUILDER_SORT_ASC;
$queryConstraints[$idx] = new SRA_QueryBuilderConstraint($attr, SRA_QUERY_BUILDER_CONSTRAINT_TYPE_SORT_ASC, FALSE);
}
foreach ($dynDescAttrs as $attr) {
$idx++;
if (count($sortOrder)) {
foreach ($skeys as $skey) {
if ($sortOrder[$skey] == $attr) {
$idx = (int) $skey;
}
}
}
$dynamicSortAttrs[$attr] = SRA_QUERY_BUILDER_SORT_DESC;
$queryConstraints[$idx] = new SRA_QueryBuilderConstraint($attr, SRA_QUERY_BUILDER_CONSTRAINT_TYPE_SORT_DESC, FALSE);
}
if ($llpParams->getParam('sortLastSelPrec', '0') == '1') {
ksort($queryConstraints);
}
else {
krsort($queryConstraints);
}
$queryConstraintGroups[] = new SRA_QueryBuilderConstraintGroup($queryConstraints);
}
// create constraint groups
$keys = array_keys($lookupConstraints);
foreach ($keys as $key) {
$queryConstraints = array();
$attrs = explode(',', $key);
$pieces = explode('-', $lookupConstraints[$key]['type']);
$type = (int) $pieces[2];
foreach ($attrs as $attr) {
$queryConstraints[] = new SRA_QueryBuilderConstraint($attr, $type, $lookupConstraints[$key]['val']);
}
$queryConstraintGroups[] = new SRA_QueryBuilderConstraintGroup($queryConstraints);
}
// determine if action has occurred
$actionComplete = FALSE;
if ($form[SRA_LIST_LOOKUP_PROCESSOR_SELECT_ACTION_FIELD_NAME] && isset($actions[$form[SRA_LIST_LOOKUP_PROCESSOR_SELECT_ACTION_FIELD_NAME]])) {
$aidx = $form[SRA_LIST_LOOKUP_PROCESSOR_SELECT_ACTION_FIELD_NAME];
$vpks = array();
if ($form[SRA_LIST_LOOKUP_PROCESSOR_SELECT_FIELD_NAME]) {
$vpks[] = $form[SRA_LIST_LOOKUP_PROCESSOR_SELECT_FIELD_NAME];
}
if ($form[SRA_LIST_LOOKUP_PROCESSOR_SELECT_ACTION_GLOBAL_FIELD_NAME] == '1' && !$actions[$aidx]->nonGlobal) {
$vpks = array();
foreach ($fkeys as $fkey) {
if ($form[$fkey] && SRA_Util::beginsWith($fkey, SRA_LIST_LOOKUP_PROCESSOR_GLOBAL_ACTION_SELECT_FIELD_NAME_PREFIX)) {
$vpks[] = $form[$fkey];
}
}
$gkeys = array_keys($globalOrderedActions);
$gActionFound = FALSE;
foreach ($gkeys as $gkey) {
if ($globalOrderedActions[$gkey]->id == $aidx) {
$gActionFound = TRUE;
}
}
$aidx = $gActionFound ? $aidx : FALSE;
}
if ($aidx && ($actions[$aidx]->type & SRA_LIST_LOOKUP_PROCESSOR_ACTION_TYPE_NEW) && !count($vpks)) {
$vpks[] = SRA_LIST_LOOKUP_PROCESSOR_UPDATE_FIELD_PREFIX . SRA_LIST_LOOKUP_PROCESSOR_NEW_PK;
}
if ($aidx !== FALSE && (count($vpks) || $actions[$aidx]->type & SRA_LIST_LOOKUP_PROCESSOR_ACTION_TYPE_NEW)) {
$baseEntities = array();
$dao =& SRA_DaoFactory::getDao($this->_entityName);
$queryConstraints = array();
$pkFound = FALSE;
foreach ($vpks as $pk) {
if (!SRA_Util::beginsWith($pk, SRA_LIST_LOOKUP_PROCESSOR_UPDATE_FIELD_PREFIX . SRA_LIST_LOOKUP_PROCESSOR_NEW_PK)) {
$queryConstraints[] = new SRA_QueryBuilderConstraint($dao->getPkName(), SRA_QUERY_BUILDER_CONSTRAINT_TYPE_EQUAL, $pk);
$pkFound = TRUE;
}
else if ($orderedActions[$key]->type != SRA_LIST_LOOKUP_PROCESSOR_ACTION_TYPE_DELETE) {
$baseEntities[$pk] =& $dao->newInstance();
}
}
$queryConstraintGroups[] = new SRA_QueryBuilderConstraintGroup($queryConstraints);
$builder = new SRA_QueryBuilder($this->_entityName, $queryConstraintGroups, $limit, $offset);
if ($builder->getResultCount() || count($baseEntities)) {
if ($actions[$aidx]->type & (SRA_LIST_LOOKUP_PROCESSOR_ACTION_TYPE_VIEW + SRA_LIST_LOOKUP_PROCESSOR_ACTION_TYPE_NEW)) {
// remove unnecessary fields
$myForm = $form;
foreach ($fkeys as $fkey) {
if (SRA_Util::beginsWith($fkey, SRA_LIST_LOOKUP_PROCESSOR_IGNORE_PREFIX) || SRA_Util::beginsWith($fkey, SRA_LIST_LOOKUP_PROCESSOR_UPDATE_FIELD_PREFIX)) {
unset($myForm[$fkey]);
}
}
$tpl =& SRA_Controller::getAppTemplate();
$tpl->assign('formName', $formParams->getParam('name', SRA_LIST_LOOKUP_PROCESSOR_DEFAULT_FORM_NAME));
$tpl->assign('formType', $formType);
$tpl->assignByRef('form', $myForm);
$tpl->display('model/llp/sra-list-duplicate-form.tpl');
}
$entities = array();
if ($builder->getResultCount() && $pkFound) {
$entities =& $builder->getEntities();
}
$bkeys = array_keys($baseEntities);
foreach ($bkeys as $bkey) {
$entities[$bkey] =& $baseEntities[$bkey];
}
$ekeys = array_keys($entities);
$displayErrMsg = FALSE;
foreach ($ekeys as $ekey) {
if ($entities[$ekey]->getPrimaryKey()) {
$fieldPrefix = SRA_LIST_LOOKUP_PROCESSOR_UPDATE_FIELD_PREFIX . $entities[$ekey]->getPrimaryKey();
}
else {
$fieldPrefix = SRA_LIST_LOOKUP_PROCESSOR_UPDATE_FIELD_PREFIX . SRA_LIST_LOOKUP_PROCESSOR_NEW_PK . $this->_newPrefixes++;
}
// update
if ($actions[$aidx]->type & (SRA_LIST_LOOKUP_PROCESSOR_ACTION_TYPE_UPDATE + SRA_LIST_LOOKUP_PROCESSOR_ACTION_TYPE_NEW)) {
foreach ($fkeys as $fkey) {
if (SRA_Util::beginsWith($fkey, $fieldPrefix)) {
if ($entities[$ekey]->getPrimaryKey() && !($actions[$aidx]->type & SRA_LIST_LOOKUP_PROCESSOR_ACTION_TYPE_NEW)) {
$form[$fieldPrefix . $dao->getPkName()] = $entities[$ekey]->getPrimaryKey();
}
$entities[$ekey] =& $entities[$ekey]->newInstanceFromForm($formType, NULL, $fieldPrefix);
if (!$entities[$ekey]->validate()) {
$displayErrMsg = $entities[$ekey]->validateErrors;
}
else {
if (!SRA_Error::isError($dao->update($entities[$ekey]))) {
$entities[$ekey] =& $dao->findByPk($entities[$ekey]->getPrimaryKey(), TRUE);
$actionComplete = TRUE;
}
else {
$displayErrMsg = $entities[$ekey]->getSysErrorString();
}
}
break;
}
}
}
// delete
if ($actions[$aidx]->type & SRA_LIST_LOOKUP_PROCESSOR_ACTION_TYPE_DELETE) {
if ($entities[$ekey]->getPrimaryKey()) {
$dao->delete($entities[$ekey]);
unset($entities[$ekey]);
$actionComplete = TRUE;
}
continue;
}
// view
if ($actions[$aidx]->type & (SRA_LIST_LOOKUP_PROCESSOR_ACTION_TYPE_VIEW + SRA_LIST_LOOKUP_PROCESSOR_ACTION_TYPE_NEW)) {
SRA_EntityView::getGlobalFieldNamePrefix($fieldPrefix);
$entities[$ekey]->render($actionComplete && $actions[$aidx]->viewFwd ? $actions[$aidx]->viewFwd : $actions[$aidx]->view);
SRA_EntityView::getGlobalFieldNamePrefix('');
}
}
// display confirmation message
$displayMsg = FALSE;
if (!$displayErrMsg && ($cmplMsg = $actions[$aidx]->getMsgComplete($form[SRA_LIST_LOOKUP_PROCESSOR_SELECT_ACTION_GLOBAL_FIELD_NAME] == '1'))) {
if (!($actions[$aidx]->type & SRA_LIST_LOOKUP_PROCESSOR_ACTION_TYPE_EDIT) || ($actions[$aidx]->type & SRA_LIST_LOOKUP_PROCESSOR_ACTION_TYPE_EDIT && $actionComplete)) {
$rb =& SRA_Controller::getAppResources();
$displayMsg = $rb->getString($cmplMsg);
}
}
$this->_displayMsg($displayMsg);
$this->_displayMsg($displayErrMsg);
if ($actions[$aidx]->type & SRA_LIST_LOOKUP_PROCESSOR_ACTION_TYPE_VIEW + SRA_LIST_LOOKUP_PROCESSOR_ACTION_TYPE_NEW) {
echo '</form>';
return;
}
unset($queryConstraintGroups[count($queryConstraintGroups) - 1]);
}
else {
$msg = 'SRA_LookupProcessor::lookup: SRA_Error - action ' . $orderedActions[$key]->fieldName . " failed because no results produced for ${entityName} or a security violation has occurred for user: " . (class_exists('SRA_Authenticator') ? SRA_Authenticator::getUserId() : 'unknown');
return SRA_Error::logError($msg, __FILE__, __LINE__);
}
}
}
// instantiate query builder and perform query
$builder = new SRA_QueryBuilder($this->_entityName, $queryConstraintGroups, $limit, $offset);
$tpl =& SRA_Controller::getAppTemplate();
$currentPage = ($offset/$limit) + 1;
if (!$offset) {
$currentPage = 1;
}
$this->_llpData = new SRA_ListLookupProcessorData($this->_entityName, $orderedActions, $globalOrderedActions, $currentPage, $fieldVals, $limit, $builder->getResultCount(), $formParams->getParam('name', SRA_LIST_LOOKUP_PROCESSOR_DEFAULT_FORM_NAME), $formType, $lfield, $pfield, $dynamicSortAttrs, $sortOrder, $form[SRA_LIST_LOOKUP_PROCESSOR_GLOBAL_ACTION_SELECT_FIELD_NAME], $llpParams->getParam('actionsPos'), $llpParams->getParam('resultsResource'), isset($actions['select']), $this->_params);
$tpl->assign(SRA_LIST_LOOKUP_PROCESSOR_DEFAULT_TPL_VAR, $this->_llpData);
return $builder->getEntities();
}
// }}}
// {{{ renderHeader
/**
* Renders html that should be output before any entities
* @access public
* @return void
*/
function renderHeader() {
$tpl =& SRA_Controller::getAppTemplate();
$tpl->display('model/llp/sra-list-table-header.tpl');
}
// }}}
// {{{ renderFooter
/**
* Renders html that should be output after all entities
* @access public
* @return void
*/
function renderFooter() {
$tpl =& SRA_Controller::getAppTemplate();
$tpl->display('model/llp/sra-list-table-footer.tpl');
}
// }}}
// {{{ renderEntityPostfix
/**
* Renders html that should be output after each entity returned by this processor
* @param Object $entity a reference to the entity being rendered
* @access public
* @return String
*/
function renderEntityPostfix(& $entity) {
$actionsPos = $this->_params->getParam('actionsPos');
if ($actionsPos !== FALSE && $actionsPos !== NULL && $actionsPos != 'L' && ((int) $actionsPos) === $this->_colIndex || $actionsPos === 'R') {
$this->_renderActions();
}
print('</tr>');
}
// }}}
// {{{ renderEntityPrefix
/**
* Renders html that should be output before each entity returned by this processor
* @param Object $entity a reference to the entity being rendered
* @access public
* @return String
*/
function renderEntityPrefix(& $entity) {
if ($entity->getPrimaryKey()) {
$fieldPrefix = SRA_LIST_LOOKUP_PROCESSOR_UPDATE_FIELD_PREFIX . $entity->getPrimaryKey();
}
else {
$fieldPrefix = SRA_LIST_LOOKUP_PROCESSOR_UPDATE_FIELD_PREFIX . SRA_LIST_LOOKUP_PROCESSOR_NEW_PK . $this->_newPrefixes++;
}
SRA_EntityView::getGlobalFieldNamePrefix($fieldPrefix);
$params =& $this->_params->getTypeSubset('llp');
$key = $params->getParam('rowCycle') ? $params->getParam('rowCycle') : $params->getParam('rowClass');
$classTag = $this->_getClassTag($key, 'row');
print("<tr{$classTag}>");
$actionsPos = $params->getParam('actionsPos');
if ($actionsPos === 'L') {
$this->_renderActions();
}
}
// }}}
// {{{ renderAttributePostfix
/**
* Renders html that should be output after each entity attribute
* @param Object $entity a reference to the entity being rendered
* @param mixed $attr a reference to the attribute being rendered
* @param string $attrName the name of the attribute being rendered
* @access public
* @return String
*/
function renderAttributePostfix(& $entity, & $attr, $attrName) {
SRA_EntityView::getGlobalFieldNamePrefix('');
print('</td>');
}
// }}}
// {{{ renderAttributePrefix
/**
* Renders html that should be output before each entity attribute
* @param Object $entity a reference to the entity being rendered
* @param mixed $attr a reference to the attribute being rendered
* @param string $attrName the name of the attribute being rendered
* @access public
* @return String
*/
function renderAttributePrefix(& $entity, & $attr, $attrName) {
$params =& $this->_params->getTypeSubset('llp');
$key = $params->getParam("${attrName}ColCycle") ? $params->getParam("${attrName}ColCycle") : $params->getParam("${attrName}ColClass");
if (!$key) {
$key = $params->getParam('colCycle') ? $params->getParam('colCycle') : $params->getParam('colClass');
$prefix = 'col';
}
else {
$prefix = "${attrName}Col";
}
$classTag = $this->_getClassTag($key, $prefix, $attrName);
$actionsPos = $params->getParam('actionsPos');
if ($actionsPos !== FALSE && $actionsPos !== NULL && $actionsPos != 'L' && $actionsPos != 'R' && ((int) $actionsPos) === $this->_colIndex) {
$this->_renderActions();
}
print("<td{$classTag}>");
$this->_colIndex++;
}
// }}}
// {{{ _displayMsg
/**
* used to display a message in a javascript popup
* @param string $msg the message to display. if FALSE, no message will be displayed
* @access private
* @return void
*/
function _displayMsg($msg) {
if ($msg) {
$msg = is_array($msg) ? implode('\n', $msg) : $msg;
$msg = str_replace('"', '\"', $msg);
print("\n<script type=\"text/javascript\">\n<!--\nalert(\"" . $msg . "\");\n//-->\n</script>\n");
}
}
// }}}
// {{{ _getClassTag
/**
* returns the class tag (or empty string if not applicable)
* @param string $key class key
* @param string $prefix key prefix
* @param string $attr optional attr name
* @access private
* @return string
*/
function _getClassTag($key, $prefix, $attr = '') {
$params =& $this->_params->getTypeSubset('llp');
$classTag = '';
if ($key) {
if (!isset($this->_classCycles[$key])) {
$this->_classCycles[$key] = array('ptr' => 0, 'classes' => explode(',', $params->getParam("${prefix}Class")));
}
$this->_classCycles[$key]['ptr'] = $this->_classCycles[$key]['ptr'] == count($this->_classCycles[$key]['classes']) ? 0 : $this->_classCycles[$key]['ptr'];
$tag = $params->getParam("${prefix}ClassTag") ? $params->getParam("${prefix}ClassTag") : 'class';
if ($this->_classCycles[$key]['classes'][$this->_classCycles[$key]['ptr']]) {
$classTag = " ${tag}=\"" . $this->_classCycles[$key]['classes'][$this->_classCycles[$key]['ptr']] . "\"";
$classTag = str_replace('{$attr}', $attr, $classTag);
if ($classTag == " ${tag}=\"\"") {
$classTag = '';
}
}
$this->_classCycles[$key]['ptr']++;
}
return $classTag;
}
// }}}
// {{{ _renderActions
/**
* Renders html for an entity actions
* @access public
* @return void
*/
function _renderActions() {
$params =& $this->_params->getTypeSubset('llp');
$key = $params->getParam("actionsColCycle") ? $params->getParam("actionsColCycle") : $params->getParam("actionsColClass");
if (!$key) {
$key = $params->getParam('colCycle') ? $params->getParam('colCycle') : $params->getParam('colClass');
$prefix = 'col';
}
else {
$prefix = "actionsCol";
}
$classTag = $this->_getClassTag($key, $prefix);
print("<td{$classTag}>");
if ($params->getParam('actionEncl')) {
print('<' . $params->getParam('actionEncl') . '>');
}
$tpl =& SRA_Controller::getAppTemplate();
$actions =& $this->_llpData->getActions();
$keys = array_keys($actions);
foreach ($keys as $key) {
$tpl->assign('action', $actions[$key]);
$tpl->display('model/llp/sra-list-action.tpl');
}
if ($params->getParam('actionEncl')) {
print('</' . $params->getParam('actionEncl') . '>');
}
print('</td>');
}
// }}}
// {{{ toString
/**
* Returns a string representation of this object
* @access public
* @return String
*/
function toString() {
return SRA_Util::objectToString($this);
}
// }}}
// Static methods
// {{{ isValid()
/**
* Static method that returns true if the object parameter is a SRA_ListLookupProcessor object.
*
* @param Object $object The object to validate
* @access public
* @return boolean
*/
function isValid( & $object ) {
return (is_object($object) && (!isset($object->err) || !SRA_Error::isError($object->err)) && strtolower(get_class($object)) == 'sra_listlookupprocessor');
}
// }}}
// private operations
}
// }}}
?>