/** * Converts the given node flags to recordlist flags where possible. * * @param int $flags * @static * * @return int */ public function convertFlags($flags) { $result = Tools::hasFlag($flags, Node::NF_MRA) ? self::RL_MRA : 0; $result |= Tools::hasFlag($flags, Node::NF_MRPA) ? self::RL_MRPA : 0; $result |= Tools::hasFlag($flags, Node::NF_NO_SEARCH) ? self::RL_NO_SEARCH : 0; $result |= Tools::hasFlag($flags, Node::NF_NO_EXTENDED_SEARCH) ? self::RL_NO_EXTENDED_SEARCH : 0; $result |= Tools::hasFlag($flags, Node::NF_EXT_SORT) ? self::RL_EXT_SORT : 0; return $result; }
/** * Constructor. * * @param string $name The name of the attribute * @param int $flags The flags for this attribute * @param string $text The text to display */ public function __construct($name, $flags = 0, $text = '') { // A Dummy attrikbute should not be searchable and sortable $flags |= self::AF_HIDE_SEARCH | self::AF_NO_SORT; // Add the self::AF_BLANKLABEL flag unless the self::AF_DUMMY_SHOW_LABEL flag wasn't present if (!Tools::hasFlag($flags, self::AF_DUMMY_SHOW_LABEL)) { $flags |= self::AF_BLANKLABEL; } parent::__construct($name, $flags); // base class constructor $this->m_text = $text; }
/** * Adds the self::AF_OBLIGATORY flag to the attribute. * * @param int $flags The flag to add to the attribute * * @return Attribute The instance of this Attribute */ public function addFlag($flags) { // setting self::AF_OBLIGATORY has no use, so prevent setting it. if (Tools::hasFlag($flags, self::AF_OBLIGATORY)) { $flags &= ~self::AF_OBLIGATORY; } // except if someone really really really wants to show this attribute is obligatory if (Tools::hasFlag($flags, self::AF_BOOL_OBLIGATORY)) { $flags |= self::AF_OBLIGATORY; } return parent::addFlag($flags); }
/** * Convert values from an HTML form posting to an internal value for * this attribute. * * For the regular Attribute, this means getting the field with the * same name as the attribute from the html posting. * * @param array $postvars The array with html posted values ($_POST, for * example) that holds this attribute's value. * * @return string The internal value */ public function fetchValue($postvars) { $vars = Tools::atkArrayNvl($postvars, $this->fieldName()); if (!is_array($vars)) { $result = []; foreach ($this->m_values as $value) { if (Tools::hasFlag($vars, $value)) { $result[] = $value; } } return $result; } else { return $vars; } }
public function addFlag($flag) { $ret = parent::addFlag($flag); if (Tools::hasFlag($this->m_flags, self::AF_ONETOMANY_SHOW_ADD)) { $this->removeFlag(self::AF_HIDE_ADD); } return $ret; }
public function addFlag($flag) { parent::addFlag($flag); if (Config::getGlobal('manytoone_autocomplete_large', true) && Tools::hasFlag($flag, self::AF_LARGE)) { $this->m_flags |= self::AF_RELATION_AUTOCOMPLETE; } return $this; }
/** * Is/are the given flag(s) set for this grid? * * @param int $flag grid flag(s) * * @return bool flag(s) is/are set */ public function hasFlag($flag) { return Tools::hasFlag($this->m_flags, $flag); }
/** * Build one or more ALTER TABLE queries and return them as an array of * strings. * * @return array of ALTER TABLE queries. */ public function buildAlter() { $result = []; if ($this->m_table != '') { // PostgreSQL only supports ALTER TABLE statements which // add a single column or constraint. $fields = []; $notNullFields = []; // At this time PostgreSQL does not support NOT NULL constraints // as part of the field construct, so a separate ALTER TABLE SET NULL // statement is needed. foreach ($this->m_fields as $fieldname => $fieldconfig) { if ($fieldname != '' && $fieldconfig['type'] != '' && $this->getType($fieldconfig['type']) != '') { $fields[] = $this->buildField($fieldname, $fieldconfig['type'], $fieldconfig['size'], $fieldconfig['flags'] & ~self::DDL_NOTNULL, $fieldconfig['default']); if (Tools::hasFlag($fieldconfig['flags'], self::DDL_NOTNULL)) { $notNullFields[] = $fieldname; } } } foreach ($fields as $field) { $result[] = 'ALTER TABLE ' . $this->m_table . ' ADD ' . $field; } foreach ($notNullFields as $field) { $result[] = 'ALTER TABLE ' . $this->m_table . ' ALTER COLUMN ' . $field . ' SET NOT NULL'; } $constraints = $this->_buildConstraintsArray(); foreach ($constraints as $constraint) { $result[] = 'ALTER TABLE ' . $this->m_table . ' ADD ' . $constraint; } } return count($result) > 0 ? $result : ''; }
/** * Determine the url for the feedbackpage. * * Output is dependent on the feedback configuration. If feedback is not * enabled for the action, this method returns an empty string, so the * result of this method can be passed directly to the redirect() method * after completing the action. * * The $record parameter is ignored by the default implementation, but * derived classes may override this method to perform record-specific * feedback. * * @param string $action The action that was performed * @param int $status The status of the action. * @param array $record The record on which the action was performed. * @param string $message An optional message to pass to the feedbackpage, * for example to explain the reason why an action * failed. * @param int $levelskip Number of levels to skip * * @return string The feedback url. */ public function feedbackUrl($action, $status, $record = [], $message = '', $levelskip = null) { $sm = SessionManager::getInstance(); $vars = []; $atkNodeUri = ''; $sessionStatus = SessionManager::SESSION_BACK; if (isset($this->m_feedback[$action]) && Tools::hasFlag($this->m_feedback[$action], $status) || $status == ActionHandler::ACTION_FAILED) { $vars = array('atkaction' => 'feedback', 'atkfbaction' => $action, 'atkactionstatus' => $status, 'atkfbmessage' => $message); $atkNodeUri = $this->atkNodeUri(); $sessionStatus = SessionManager::SESSION_REPLACE; // The level skip given is based on where we should end up after the // feedback action is shown to the user. This means that the feedback // action should be shown one level higher in the stack, hence the -1. // Default the feedback action is shown on the current level, so in that // case we have a simple SessionManager::SESSION_REPLACE with a level skip of null. $levelskip = $levelskip == null ? null : $levelskip - 1; } $dispatch_url = Tools::dispatch_url($atkNodeUri, Tools::atkArrayNvl($vars, 'atkaction', ''), $vars); return $sm->sessionUrl($dispatch_url, $sessionStatus, $levelskip); }
/** * Function outputs an array with all information necessary to output a recordlist. * * @param array $recordset List of records that need to be displayed * @param string $prefix Prefix for each column name (used for subcalls) * @param array $actions List of default actions for each record * @param array $suppress An array of fields that you want to hide * * The result array contains the following information: * "name" => the name of the recordlist * "heading" => for each visible column an array containing: "title" {, "url"} * "search" => for each visible column HTML input field(s) for searching * "rows" => list of rows, per row: "data", "actions", "mra", "record" * "totalraw" => for each totalisable column the sum value field(s) (raw) * "total" => for each totalisable column the sum value (display) * "mra" => list of all multi-record actions * * @return array see above */ private function listArray(&$recordset, $prefix = '', $actions = [], $suppress = array()) { $grid = $this->getGrid(); $flags = $this->convertDataGridFlags(); if (!is_array($suppress)) { $suppress = []; } $result = array('name' => $grid->getName(), 'heading' => [], 'search' => [], 'rows' => [], 'totalraw' => [], 'total' => [], 'mra' => []); $columnConfig = $grid->getNode()->getColumnConfig($grid->getName()); if (!Tools::hasFlag($flags, RecordList::RL_NO_SEARCH) || $grid->isEditing()) { $grid->getNode()->setAttribSizes(); } $this->_addListArrayHeader($result, $prefix, $suppress, $flags, $columnConfig); /* actions array can contain multi-record-actions */ if (count($actions) == 2 && count(array_diff(array_keys($actions), array('actions', 'mra'))) == 0) { $mra = $actions['mra']; $actions = $actions['actions']; } else { $mra = $grid->getNode()->hasFlag(Node::NF_NO_DELETE) ? [] : array('delete'); } /* get the rows */ for ($i = 0, $_i = count($recordset); $i < $_i; ++$i) { $result['rows'][$i] = array('columns' => [], 'actions' => $actions, 'mra' => $mra, 'record' => &$recordset[$i], 'data' => []); $result['rows'][$i]['selector'] = $grid->getNode()->primaryKey($recordset[$i]); $result['rows'][$i]['type'] = 'data'; $row =& $result['rows'][$i]; /* actions / mra */ $grid->getNode()->collectRecordActions($row['record'], $row['actions'], $row['mra']); // filter actions we are allowed to execute foreach ($row['actions'] as $name => $url) { if (!empty($url) && $grid->getNode()->allowed($name, $row['record'])) { /* dirty hack */ $atkencoded = strpos($url, '_15B') > 0; $url = str_replace('%5B', '[', $url); $url = str_replace('%5D', ']', $url); $url = str_replace('_1' . '5B', '[', $url); $url = str_replace('_1' . '5D', ']', $url); if ($atkencoded) { $url = str_replace('[pk]', Tools::atkurlencode(rawurlencode($row['selector']), false), $url); } else { $url = str_replace('[pk]', rawurlencode($row['selector']), $url); } $parser = new StringParser($url); $url = $parser->parse($row['record'], true, false); $row['actions'][$name] = $url; } else { unset($row['actions'][$name]); } } // filter multi-record-actions we are allowed to execute foreach ($row['mra'] as $j => $name) { if (!$grid->getNode()->allowed($name, $row['record'])) { unset($row['mra'][$j]); } } $row['mra'] = array_values($row['mra']); $result['mra'] = array_merge($result['mra'], $row['mra']); /* columns */ $editAllowed = $grid->getPostvar('atkgridedit', false) && $grid->getNode()->allowed('edit', $result['rows'][$i]['record']); $result['rows'][$i]['edit'] = $editAllowed; $this->_addListArrayRow($result, $prefix, $suppress, $flags, $i, $editAllowed); } // override totals if (is_array($result['total']) && count($result['total']) > 0) { $selector = $grid->getNode()->select()->ignoreDefaultFilters(); foreach ($grid->getFilters() as $filter) { $selector->where($filter['filter'], $filter['params']); } $result['totalraw'] = $selector->getTotals(array_keys($result['total'])); foreach ($result['totalraw'] as $attrName => $value) { $result['total'][$attrName] = $grid->getNode()->getAttribute($attrName)->getView('list', $result['totalraw']); } } if (Tools::hasFlag($flags, RecordList::RL_EXT_SORT) && $columnConfig->hasSubTotals()) { $totalizer = new Totalizer($grid->getNode(), $columnConfig); $result['rows'] = $totalizer->totalize($result['rows']); } if (Tools::hasFlag($flags, RecordList::RL_MRA)) { $result['mra'] = array_values(array_unique($result['mra'])); } return $result; }
/** * Returns a displayable string for this value, to be used in HTML pages. * * In this case, the timestamp is returned in human readable format. * * @param array $record The record that holds the value for this attribute * @param string $mode The display mode ("view" for viewpages, or "list" * for displaying in recordlists). The regular * Attribute does not use this parameter, but * derived attributes may use it to distinguish * between the two display modes. * * @return string HTML String */ public function display($record, $mode) { $result = ''; $value = (int) $record[$this->fieldName()]; $max = 7 + count($this->m_extra); for ($i = 1; $i <= $max; ++$i) { $day = pow(2, $i - 1); if (Tools::hasFlag($value, $day)) { if ($i <= 7) { $weekday = $this->m_mapping[$day]; if ($mode == 'list') { $weekday = substr($weekday, 0, 3); } $weekday = Tools::atktext($weekday); } else { $weekday = $this->m_extra[$i - 8]; } $result .= (empty($result) ? '' : ($mode == 'list' ? ', ' : '<br>')) . $weekday; } } if (empty($result)) { return Tools::atktext('none'); } else { return $result; } }
/** * Adds the attribute / field to the list header. This includes the column name and search field. * * @param string $action the action that is being performed on the node * @param array $arr reference to the the recordlist array * @param string $fieldprefix the fieldprefix * @param int $flags the recordlist flags * @param array $atksearch the current ATK search list (if not empty) * @param string $atkorderby Order by string * * @see Node::listArray */ public function addToListArrayHeader($action, &$arr, $fieldprefix, $flags, $atksearch, $atkorderby) { if (!$this->hasFlag(self::AF_HIDE_LIST) && !($this->hasFlag(self::AF_HIDE_SELECT) && $action == 'select')) { $arr['heading'][$fieldprefix . $this->fieldName()]['title'] = $this->label(); if (!Tools::hasFlag($flags, RecordList::RL_NO_SORT) && !$this->hasFlag(self::AF_NO_SORT)) { $rec = []; foreach ($this->m_displayfields as $field) { $rec[] = $this->m_ownerInstance->m_table . '.' . $field; } $order = implode(', ', $rec); if ($atkorderby == $order) { $order = implode(' DESC,', $rec); $order .= ' DESC'; } $sm = SessionManager::getInstance(); $arr['heading'][$fieldprefix . $this->fieldName()]['url'] = $sm->sessionUrl(Config::getGlobal('dispatcher') . '?atknodeuri=' . $this->m_ownerInstance->atkNodeUri() . '&atkaction=' . $action . '&atkorderby=' . rawurlencode($order)); } if (!Tools::hasFlag($flags, RecordList::RL_NO_SEARCH) && $this->hasFlag(self::AF_SEARCHABLE)) { $arr['search'][$fieldprefix . $this->fieldName()] = $this->search($atksearch, false, $fieldprefix); $arr['search'][$fieldprefix . $this->fieldName()] .= '<input type="hidden" name="atksearchmode[' . $this->fieldName() . ']" value="' . $this->getSearchMode() . '">'; } } }
/** * Checks if this attribute is really not null in the database. * This method does not look at the self::AF_OBLIGATORY flag, it only * checks in the database if the attribute's column is really not null. * * @return bool attribute's database column not null? */ public function isNotNullInDb() { $db = $this->getDb(); $meta = $db->tableMeta($this->m_ownerInstance->m_table); return Tools::hasFlag($meta[$this->fieldName()]['flags'], Db::MF_NOT_NULL); }
/** * Render the complete page, including head and body. * * @param string $title Title of the HTML page. * @param bool|int $flags (bool) Set to true to generate <body> tags. It is useful * to set this to false only when rendering content * that either already had its own <body></body> * statement, or content that needs no body * statements, like a frameset. (DEPRICATED !!) * (int) Flags for the render function * @param string $extrabodyprops Extra attributes to add to the <body> tag. * @param string $extra_header HTML code of extra headers to add to the head section * * @return string The HTML page, including <html> and </html> tags. */ public function render($title = null, $flags = self::HTML_STRICT, $extrabodyprops = '', $extra_header = '') { if ($title == null) { $title = $this->m_title != '' ? $this->m_title : Tools::atktext('app_title'); } $ui = Ui::getInstance(); if (is_bool($flags) && $flags == true) { $flags = self::HTML_STRICT; } elseif (is_bool($flags) && $flags == false) { $flags = self::HTML_HEADER | self::HTML_DOCTYPE; } elseif (Tools::hasFlag($flags, self::HTML_PARTIAL)) { return $this->renderPartial(); } $this->m_content = $ui->render('page.tpl', array('content' => $this->m_content)); $layout = []; $layout['title'] = $title; if (Tools::hasFlag($flags, self::HTML_HEADER)) { $layout['head'] = $this->head() . $extra_header; } if (Tools::hasFlag($flags, self::HTML_BODY)) { $layout['extrabodyprops'] = $extrabodyprops; $layout['body'] = $this->m_content . "\n"; } $layout['hiddenvars'] = $this->hiddenVars(); $layout['atkversion'] = Atk::VERSION; return $ui->render('layout.tpl', $layout); }
/** * Add's a sequence field to the query. * * @param string $fieldName field name * @param int $value field to store the new sequence value in, note certain drivers * might populate this field only after the insert query has been * executed * @param string $seqName sequence name (optional for certain drivers) * * @return Query */ public function addSequenceField($fieldName, &$value, $seqName = null) { $meta = $this->getDb()->tableMeta($this->m_tables[0]); if (!Tools::hasFlag($meta[$fieldName]['flags'], Db::MF_AUTO_INCREMENT)) { return parent::addSequenceField($fieldName, $value, $seqName); } $this->m_seqValue =& $value; $this->m_seqValue = -1; $this->m_seqField = $fieldName; $this->m_returnSeqValue = true; return $this; }
/** * Add the checkall, checknone and checkinvert links. * * @param string $fieldprefix The fieldprefix * * @return string a piece of htmlcode with the links */ public function _addLinks($fieldprefix) { if (count($this->m_values) > 4 && !Tools::hasFlag($this->m_flags, self::AF_NO_TOGGLELINKS)) { return '<div align="left"> [<a href="javascript:void(0)" onclick="profile_checkAll(\'' . $fieldprefix . $this->fieldName() . '\'); return false;">' . Tools::atktext('check_all') . '</a> <a href="javascript:void(0)" onclick="profile_checkNone(\'' . $fieldprefix . $this->fieldName() . '\'); return false;">' . Tools::atktext('check_none') . '</a> <a href="javascript:void(0)" onclick="profile_checkInvert(\'' . $fieldprefix . $this->fieldName() . '\'); return false;">' . Tools::atktext('invert_selection') . '</a>]</div>'; } return ''; }
/** * Returns the attributes for each load type (Attribute::PRELOAD, Attribute::ADDTOQUERY, Attribute::POSTLOAD). * * @return array attributes by load type */ protected function _getAttributesByLoadType() { $isSearching = $this->_isSearching(); $result = array(Attribute::PRELOAD => [], Attribute::ADDTOQUERY => [], Attribute::POSTLOAD => array()); foreach ($this->_getNode()->getAttributes() as $attr) { if (!$this->_isAttributeLoadRequired($attr)) { continue; } $loadType = $attr->loadType($this->m_mode); if (Tools::hasFlag($loadType, Attribute::PRELOAD)) { $result[Attribute::PRELOAD][$attr->fieldName()] = $attr; } if (Tools::hasFlag($loadType, Attribute::ADDTOQUERY)) { $result[Attribute::ADDTOQUERY][$attr->fieldName()] = $attr; } if (Tools::hasFlag($loadType, Attribute::POSTLOAD)) { $result[Attribute::POSTLOAD][$attr->fieldName()] = $attr; } } return $result; }
/** * Generate a string for a field, to be used inside a CREATE TABLE * statement. * This function tries to be generic, so it will work in the largest * number of databases. Databases that won't work with this syntax, * should override this method in the database specific ddl class. * * @param string $name The name of the field * @param string $generictype The datatype of the field (should be one of the * generic types supported by ATK). * @param int $size The size of the field (if appropriate) * @param int $flags The self::DDL_ flags for this field. * @param mixed $default The default value to be used when inserting new rows. * * @return string */ public function buildField($name, $generictype, $size = 0, $flags = 0, $default = null) { $res = $this->m_db->quoteIdentifier($name) . ' ' . $this->getType($generictype); if ($size > 0 && $this->needsSize($generictype)) { $res .= '(' . $size . ')'; } if ($default !== null) { if ($this->needsQuotes($generictype)) { $default = "'" . $default . "'"; } $res .= ' DEFAULT ' . $default; } if (Tools::hasFlag($flags, self::DDL_NOTNULL)) { $res .= ' NOT NULL'; } return $res; }