/class.atknode.inc
PHP | 5170 lines | 2788 code | 502 blank | 1880 comment | 426 complexity | a93e335754f5b4346fe3b5a867ab3dd6 MD5 | raw file
Possible License(s): LGPL-2.0, LGPL-2.1, MPL-2.0-no-copyleft-exception, LGPL-3.0
Large files files are truncated, but you can click here to view the full file
- <?php
- /**
- * This file is part of the Achievo ATK distribution.
- * Detailed copyright and licensing information can be found
- * in the doc/COPYRIGHT and doc/LICENSE files which should be
- * included in the distribution.
- *
- * @package atk
- *
- * @copyright (c)2000-2007 Ivo Jansch
- * @copyright (c)2000-2008 Ibuildings.nl BV
- * @license http://www.achievo.org/atk/licensing ATK Open Source License
- *
- * @version $Revision$
- */
- /**
- * some includes
- */
- atkimport("atk.attributes.atkattribute");
- atkimport("atk.atkcontroller");
- atkimport("atk.modules.atkmodule");
- /**
- * Define some flags for nodes. Use the constructor of the atkNode
- * class to set the flags. (concatenate multiple flags with '|')
- */
- /**
- * No new records may be added
- */
- define("NF_NO_ADD", 1);
- /**
- * Records may not be edited
- */
- define("NF_NO_EDIT", 2);
- /**
- * Records may not be deleted
- */
- define("NF_NO_DELETE", 4);
- /**
- * Immediately after you add a new record,
- * you get the editpage for that record
- */
- define("NF_EDITAFTERADD", 8);
- /**
- * Records may not be searched
- */
- define("NF_NO_SEARCH", 16);
- /**
- * Ignore addFilter filters
- */
- define("NF_NO_FILTER", 32);
- /**
- * Doesn't show an add form on the admin page
- * but a link to the form
- */
- define("NF_ADD_LINK", 64);
- /**
- * Records may not be viewed
- */
- define("NF_NO_VIEW", 128);
- /**
- * Records / trees may be copied
- */
- define("NF_COPY", 256);
- /**
- * If this flag is set and only one record is
- * present on a selectpage, atk automagically
- * selects it and moves on to the target
- */
- define("NF_AUTOSELECT", 512);
- /**
- * If set, atk stores the old values of
- * a record as ["atkorgrec"] in the $rec that
- * gets passed to the postUpdate
- */
- define("NF_TRACK_CHANGES", 1024);
- /**
- * Quick way to disable accessright checking
- * for an entire node. (Everybody may access this node)
- */
- define("NF_NO_SECURITY", 2048);
- /**
- * Extended search feature is turned off
- */
- define("NF_NO_EXTENDED_SEARCH", 4096);
- /**
- * Multi-selection of records is turned on
- */
- define("NF_MULTI_RECORD_ACTIONS", 8192);
- /**
- * Multi-priority-selection of records is turned on
- */
- define("NF_MRPA", 16384);
- /**
- * Add locking support to node, if one user is editing a record,
- * no one else may edit it.
- */
- define("NF_LOCK", 32768);
- /**
- * Multi-language support
- */
- define("NF_ML", 65536);
- /**
- * Quick way to ensable the csv import feature
- */
- define("NF_IMPORT", 131072);
- /**
- * Add CSV export ability to the node.
- */
- define("NF_EXPORT", 262144);
- /**
- * Disable csv import feature
- * @deprecated since ATK 5.2
- */
- define("NF_NO_IMPORT", 0);
- /**
- * Enable extended sorting (multicolumn sort)
- */
- define("NF_EXT_SORT", 524288);
- /**
- * Makes a node cache it's recordlist
- */
- define("NF_CACHE_RECORDLIST", 1048576);
- /**
- * After adding a new record add another one instantaniously.
- */
- define("NF_ADDAFTERADD", 2097152);
- /**
- * No sorting possible.
- */
- define("NF_NO_SORT", 4194304);
- /**
- * Use the dialog popup box when adding a new record for this node.
- */
- define("NF_ADD_DIALOG", 8388608);
- /**
- * Use the dialog add-or-copy popup box when adding a new record for this node.
- */
- define("NF_ADDORCOPY_DIALOG", 16777216);
- /**
- * Specific node flag 1
- */
- define("NF_SPECIFIC_1", 33554432);
- /**
- * Specific node flag 2
- */
- define("NF_SPECIFIC_2", 67108864);
- /**
- * Specific node flag 3
- */
- define("NF_SPECIFIC_3", 134217728);
- /**
- * Specific node flag 4
- */
- define("NF_SPECIFIC_4", 268435456);
- /**
- * Specific node flag 5
- */
- define("NF_SPECIFIC_5", 536870912);
- /**
- * Records may be copied and open for editing
- */
- define("NF_EDITAFTERCOPY", 1073741824);
- /**
- * Alias for NF_MULTI_RECORD_ACTIONS flag (shortcut)
- */
- define("NF_MRA", NF_MULTI_RECORD_ACTIONS);
- /**
- * Alias for NF_ML flag (typed out)
- */
- define("NF_MULTILANGUAGE", NF_ML);
- /**
- * Aggregate flag to quickly create readonly nodes
- */
- define("NF_READONLY", NF_NO_ADD|NF_NO_DELETE|NF_NO_EDIT);
- /**
- * action status flags
- * Note that these have binary numbers, even though an action could never have
- * two statusses at the same time.
- * This is done however, so the flags can be used as a mask in the setFeedback
- * function.
- */
- /**
- * The action is cancelled
- *
- * action status flag
- */
- define("ACTION_CANCELLED", 1);
- /**
- * The action failed to accomplish it's goal
- *
- * action status flag
- */
- define("ACTION_FAILED", 2);
- /**
- * The action is a success
- *
- * action status flag
- */
- define("ACTION_SUCCESS", 4);
- /**
- * Trigger flags
- */
- define("TRIGGER_NONE", 0);
- define("TRIGGER_AUTO", 1);
- define("TRIGGER_PRE", 2);
- define("TRIGGER_POST", 4);
- define("TRIGGER_ALL", TRIGGER_PRE|TRIGGER_POST);
- /**
- * Multi-record-actions selection modes. These
- * modes are mutually exclusive.
- */
- /**
- * Multiple selections possible.
- */
- define("MRA_MULTI_SELECT", 1);
- /**
- * Only one selection possible.
- */
- define("MRA_SINGLE_SELECT", 2);
- /**
- * No selection possible (e.g. action is always for all (visible) records!).
- */
- define("MRA_NO_SELECT", 3);
- /**
- * The atkNode class represents a piece of information that is part of an
- * application. This class provides standard functionality for adding,
- * editing and deleting nodes.
- * This class must be seen as an abstract base class: For every piece of
- * information in an application, a class must be derived from this class
- * with specific implementations for that type of node.
- *
- * @author Ivo Jansch <ivo@achievo.org>
- * @package atk
- */
- class atkNode
- {
- /**
- * reference to the class which is used to validate atknodes
- * the validator is overridable by changing this variabele
- *
- * @access private
- * @var String
- */
- var $m_validate_class = "atk.atknodevalidator";
- /**
- * Unique field sets of a certain node.
- *
- * Indicates which field combinations should be unique.
- * It doesn't contain the unique fields which have been set by flag
- * AF_UNIQUE.
- *
- * @access private
- * @var array
- */
- var $m_uniqueFieldSets = array();
- /**
- * Nodes must be initialised using the init() function before they can be
- * used. This member indicated whether the node has been initialised.
- * @access private
- * @var boolean
- */
- var $m_initialised = false;
- /**
- * Check to prevent double execution of setAttribSizes on pages with more
- * than one form.
- * @access private
- * @var boolean
- */
- var $m_attribsizesset = false;
- /**
- * The list of attributes of a node. These should be of the class
- * atkAttribute or one of its derivatives.
- * @access private
- * @var array
- */
- var $m_attribList = array();
- /**
- * Index list containing the attributes in the order in which they will
- * appear on screen.
- * @access private
- * @var array
- */
- var $m_attribIndexList = array();
- /**
- * Reference to the page on which the node is rendering its output.
- * @access private
- * @var atkPage
- */
- var $m_page = NULL;
- /**
- * List of available tabs. Associative array structured like this:
- * array($action=>$arrayOfTabnames)
- * @access private
- * @var array
- */
- var $m_tabList = array();
- /**
- * List of available sections. Associative array structured like this:
- * array($action=>$arrayOfSectionnames)
- * @access private
- * @var array
- */
- var $m_sectionList = array();
- /**
- * Keep track of tabs per attribute.
- * @access private
- * @var array
- */
- var $m_attributeTabs = array();
- /**
- * Keep track if a tab contains attribs (checkEmptyTabs function)
- * @access private
- * @var array
- */
- var $m_filledTabs = array();
- /**
- * The nodetype.
- * @access protected
- * @var String
- */
- var $m_type;
- /**
- * The module of the node.
- * @access protected
- * @var String
- */
- var $m_module;
- /**
- * The database that the node is using for storing and loading its data.
- * @access protected
- * @var mixed
- */
- var $m_db = NULL;
- /**
- * The table to use for data storage.
- * @access protected
- * @var String
- */
- var $m_table;
- /**
- * The name of the sequence used for autoincrement fields.
- * @access protected
- * @var String
- */
- var $m_seq;
- /**
- * Name of the attribute that contains the language of a record.
- * Used with ATK's data internationalization feature.
- * @access private
- * @var String
- */
- var $m_lngfield;
- /**
- * List of names of the attributes that form this node's primary key.
- * @access protected
- * @var array
- */
- var $m_primaryKey = array();
- /**
- * The postvars (or getvars) that are passed to a page will be passed
- * to the class using the dispatch function. We store them in a member
- * variable for easy access.
- * @access protected
- * @var array
- */
- var $m_postvars = array();
- /**
- * The action that the node is currently performing.
- * @access protected
- * @var String
- */
- var $m_action;
- /**
- * Contains the definition of what needs to rendered partially.
- * If set to NULL not in partial rendering mode.
- */
- var $m_partial = NULL;
- /**
- * The active action handler.
- * @access protected
- * @var atkActionHandler
- */
- var $m_handler = NULL;
- /**
- * Default order by statement.
- * @access protected
- * @var String
- */
- var $m_default_order = "";
- /**
- * var used for tracking relation within this node.
- * @todo Remove this member, it's using memory while it's used only in
- * the case of multilanguage node, and even then only on one
- * occasion.
- * @access private
- * @var array
- */
- var $m_relations = array();
- /**
- * Bitwise mask of node flags (NF_* flags).
- * @var int
- */
- var $m_flags;
- /*
- * Name of the field that is used for creating an alphabetical index in
- * admin/select pages.
- * @access private
- * @var String
- */
- var $m_index = "";
- /**
- * Default tab being displayed in add/edit mode.
- * @access private
- * @var String
- */
- var $m_default_tab = "default";
- /**
- * Default sections that are expanded.
- * @access private
- * @var String
- */
- var $m_default_expanded_sections = array();
- /**
- * Record filters, in attributename/required value pairs.
- * @access private
- * @var array
- */
- var $m_filters = array();
- /**
- * Record filters, as a list of sql statements.
- * @access private
- * @var array
- */
- var $m_fuzzyFilters = array();
- /**
- * For speed, we keep track of a list of attributes that we don't have to
- * load in recordlists.
- * @access protected
- * @var array
- */
- var $m_listExcludes = array();
- /**
- * For speed, we keep track of a list of attributes that we don't have to
- * load when in view pages.
- * @todo This can probably be moved to the view handler.
- * @access protected
- * @var array
- */
- var $m_viewExcludes = array();
- /**
- * For speed, we keep track of a list of attributes that have the cascade
- * delete flag set.
- * @todo This should be moved to the delete handler, or should not be
- * cached at all. (caching this on each load is slower than just
- * retrieving the list when it's needed)
- * @access private
- * @var array
- */
- var $m_cascadingAttribs = array();
- /**
- * Actions are mapped to security units.
- *
- * For example, both actions "save" and "add" require access "add". If an
- * item is not in this list, it's treated 'as-is'. Derived nodes may add
- * more mappings to tell the systems that some custom actions require the
- * same privilege as others.
- * Structure: array($action=>$requiredPrivilege)
- * @access protected
- * @var array
- */
- var $m_securityMap = array("save"=>"add",
- "update"=>"edit",
- "multiupdate"=>"edit",
- "copy"=>"add",
- "import"=>"add",
- "editcopy"=>"add",
- "search"=>"admin",
- "smartsearch"=>"admin");
- /**
- * The right to execute certain actions can be implied by the fact that you
- * have some other right. For example, if you have the right to access a
- * feature (admin right), you may also view that record, and don't need
- * explicit rights to view it. So the 'view' right is said to be 'implied'
- * by the 'admin' right.
- * This is a subtle difference with m_securityMap.
- * @access protected
- * @var array
- */
- var $m_securityImplied = array("view"=>"admin");
- /**
- * Name of the node that is used for privilege checking.
- *
- * If a class is named 'project', then by default, if the system needs to
- * know whether a user may edit a record, the securitymanager searches
- * for 'edit' access on 'project'. However, if an alias is set here, the
- * securitymanger searches for 'edit' on that alias.
- * @access private
- * @var String
- */
- var $m_securityAlias = "";
- /*
- * Nodes can specify actions that require no access level
- * Note: for the moment, the "select" action is always allowed.
- * @todo This may not be correct. We have to find a way to bind the
- * select action to the action that follows after the select.
- * @access private
- * @var array
- */
- var $m_unsecuredActions = array("select", "multiselect", "feedback");
- /*
- *
- * Boolean that is set to true when the stacktrace is displayed, so it
- * is displayed only once.
- * @deprecated This member is as deprecated as the statusbar() method.
- * @access private
- * @var boolean
- */
- var $m_statusbarDone = false;
- /**
- * Auto search-actions; action that will be performed if only one record
- * is found.
- * @access private
- * @var array
- */
- var $m_search_action;
- /**
- * Priority actions
- * @access private
- * @todo This, and the priority_min/max members, should be moved
- * to the recordlist
- * @var array
- */
- var $m_priority_actions = array();
- /**
- * Minimum for the mra priority select
- * @access private
- * @var int
- */
- var $m_priority_min = 1;
- /**
- * Maximum for the mra priority select
- * @access private
- * @var int
- */
- var $m_priority_max = 0;
- /**
- * The lock instance
- * @access protected
- * @var atkLock
- */
- var $m_lock = NULL;
- /**
- * List of actions that should give success/failure feedback
- * @access private
- * @var array
- */
- var $m_feedback = array();
- /**
- * Default language used by Multilanguage Nodes.
- * @access protected
- * @var String
- */
- var $m_defaultlanguage = "";
- /**
- * Number to use with numbering
- * @access protected
- * @var mixed
- */
- var $m_numbering = null;
- /**
- * Descriptor template.
- * @access protected
- * @var String
- */
- var $m_descTemplate = NULL;
- /**
- * Descriptor handler.
- * @access protected
- * @var Object
- */
- var $m_descHandler = NULL;
- /**
- * List of action listeners
- * @access protected
- * @var Array
- */
- var $m_actionListeners = array();
- /**
- * List of trigger listeners
- * @access protected
- * @var Array
- */
- var $m_triggerListeners = array();
- /**
- * List of callback functions to manipulate the record actions
- *
- * @var array
- */
- protected $m_recordActionsCallbacks = array();
- /**
- * List of callback functions to add css class to row.
- * See details in atkDGList::getRecordlistData() method
- *
- * @var array
- */
- protected $m_rowClassCallback = array();
- /**
- * Tracker variable to see if we are currently in 'modifier mode' (running inside
- * the scope of a modname_nodename_modifier() method). The variable contains the
- * name of the modifying module.
- * @access private
- * @var String
- */
- var $m_modifier = "";
- /**
- * Extended search action. The action which is called if the user
- * wants to perform an extended search.
- *
- * @access private
- * @var String
- */
- var $m_extended_search_action = NULL;
- /**
- * List of editable list attributes.
- * @access private
- * @var Array
- */
- var $m_editableListAttributes = array();
- /**
- * Multi-record actions, selection mode.
- * @access private
- * @var int
- */
- var $m_mraSelectionMode = MRA_MULTI_SELECT;
- /**
- * The default edit fieldprefix to use for atk
- * @access private
- * @var String
- */
- var $m_edit_fieldprefix = '';
- /**
- * Lock mode.
- *
- * @var int
- */
- private $m_lockMode = 'exclusive'; // atkLock::EXCLUSIVE (would mean atkLock needs to be available!)
- /**
- * Default column name (null means across all columns)
- *
- * @var string
- */
- private $m_defaultColumn = null;
- /**
- * Current maximum attribute order value.
- *
- * @var int
- */
- private $m_attribOrder = 0;
- /**
- * Constructor.
- *
- * This initialises the node. Derived classes should always call their
- * parent constructor ($this->atkNode($name, $flags), to initialize the
- * base class.
- * <br>
- * <b>Example:</b>
- * <code>$this->atkNode('test',NF_NO_EDIT);</code>
- * @param String $type The nodetype (by default equal to the classname)
- * @param int $flags Bitmask of node flags (NF_*).
- */
- function atkNode($type="", $flags=0)
- {
- if ($type=="") $type = strtolower(get_class($this));
- atkdebug("Creating a new atkNode for $type");
- $this->m_type = $type;
- $this->m_flags = $flags;
- $this->m_module = atkModule::getModuleScope();
- $this->setEditFieldPrefix(atkconfig('edit_fieldprefix', ''));
- }
- /**
- * Resolve section. If a section is only prefixed by
- * a dot this means we need to add the default tab
- * before the dot.
- *
- * @param string $section section name
- * @return resolved section name
- */
- function resolveSection($section)
- {
- list($part1, $part2) = (strpos($section, ".") !== false) ? explode('.', $section) : array($section, "");
- if ($part2 != NULL && strlen($part2) > 0 && strlen($part1) == 0)
- return $this->m_default_tab.".".$part2;
- else if (strlen($part2) == 0 && strlen($part1) == 0)
- return $this->m_default_tab;
- else return $section;
- }
- /**
- * Resolve sections.
- *
- * @param array $sections section list
- * @return array resolved section list
- *
- * @see resolveSection
- */
- function resolveSections($sections)
- {
- $result = array();
- foreach ($sections as $section)
- {
- $result[] = $this->resolveSection($section);
- }
- return $result;
- }
- /**
- * Returns the default column name.
- *
- * @return string default column name
- */
- public function getDefaultColumn()
- {
- return $this->m_defaultColumn;
- }
- /**
- * Set default column name.
- *
- * @param string name default column name
- */
- public function setDefaultColumn($name)
- {
- $this->m_defaultColumn = $name;
- }
- /**
- * Resolve column for sections.
- *
- * If one of the sections contains something after a double
- * colon (:) than that's used as column name, else the default
- * column name will be used.
- *
- * @param array $sections sections
- *
- * @return string column name
- */
- protected function resolveColumn(&$sections)
- {
- $column = $this->getDefaultColumn();
- if (!is_array($sections))
- {
- return $column;
- }
- foreach ($sections as &$section)
- {
- if (strpos($section, ":") !== false)
- {
- list($section, $column) = explode(':', $section);
- }
- }
- return $column;
- }
- /**
- * Resolve sections, tabs and the order based on the given
- * argument to the attribute add method.
- *
- * @param mixed $sections
- * @param mixed $tabs
- * @param mixed $order
- */
- function resolveSectionsTabsOrder(&$sections, &$tabs, &$column, &$order)
- {
- // Because sections/tabs will probably be used more than the order override option
- // the API for this method now favours the $sections argument. For backwards
- // compatibility we still support the old API ($attribute,$order=0).
- if ($sections !== NULL && is_int($sections))
- {
- $order = $sections;
- $sections = array($this->m_default_tab);
- }
- // If no section/tab is specified or tabs are disabled, we use the current default tab
- // (specified with the setDefaultTab method, or "default" otherwise)
- elseif ($sections === NULL || (is_string($sections) && strlen($sections) == 0) || !atkconfig("tabs"))
- {
- $sections = array($this->m_default_tab);
- }
- // Sections should be an array.
- else if ($sections != "*" && !is_array($sections))
- {
- $sections = array($sections);
- }
- $column = $this->resolveColumn($sections);
- if (is_array($sections))
- {
- $sections = $this->resolveSections($sections);
- }
- // Filter tabs from section names.
- $tabs = $this->getTabsFromSections($sections);
- }
- /**
- * Add an atkAttribute (or one of its derivatives) to the node.
- * @param atkAttribute $attribute The attribute you want to add
- * @param mixed $sections The sections/tab(s) on which the attribute should be
- * displayed. Can be a tabname (String) or a list of
- * tabs (array) or "*" if the attribute should be
- * displayed on all tabs.
- * @param int $order The order at which the attribute should be displayed.
- * If ommitted, this defaults to 100 for the first
- * attribute, and 100 more for each next attribute that
- * is added.
- * @return atkAttribute the attribute just added
- */
- public function add($attribute,$sections=NULL,$order=0)
- {
- $tabs = null;
- $column = null;
- $attribute->m_owner = $this->m_type;
- // If we're running inside modifier scope, we have to tell the attribute
- // what module he originated from.
- if ($this->m_modifier!="") $attribute->m_module = $this->m_modifier;
- if (!atkReadOptimizer())
- {
- $this->resolveSectionsTabsOrder($sections, $tabs, $column, $order);
- // check for parent fieldname (treeview)
- if($attribute->hasFlag(AF_PARENT))
- {
- $this->m_parent = $attribute->fieldName();
- }
- // check for cascading delete flag
- if ($attribute->hasFlag(AF_CASCADE_DELETE))
- {
- $this->m_cascadingAttribs[]=$attribute->fieldName();
- }
- if ($attribute->hasFlag(AF_HIDE_LIST)&&!$attribute->hasFlag(AF_PRIMARY))
- {
- if (!in_array($attribute->fieldName(),$this->m_listExcludes))
- {
- $this->m_listExcludes[]=$attribute->fieldName();
- }
- }
- if ($attribute->hasFlag(AF_HIDE_VIEW)&&!$attribute->hasFlag(AF_PRIMARY))
- {
- if (!in_array($attribute->fieldName(),$this->m_viewExcludes))
- {
- $this->m_viewExcludes[]=$attribute->fieldName();
- }
- }
- }
- else
- {
- // when the read optimizer is enabled there is no active tab
- // we circument this by putting all attributes on all tabs
- if ($sections !== NULL && is_int($sections))
- $order = $sections;
- $tabs = "*";
- $sections = "*";
- $column = $this->getDefaultColumn();
- }
- // NOTE: THIS SHOULD WORK. BUT, since add() is called from inside the $this
- // constructor, m_ownerInstance ends up being a copy of $this, rather than
- // a reference. Don't ask me why, it has something to do with the way PHP
- // handles the constructor.
- // To work around this, we reassign the this pointer to the attributes as
- // soon as possible AFTER the constructor. (the dispatcher function)
- $attribute->setOwnerInstance($this);
- if ($attribute->hasFlag(AF_PRIMARY))
- {
- if (!in_array($attribute->fieldName(),$this->m_primaryKey))
- {
- $this->m_primaryKey[] = $attribute->fieldName();
- }
- }
- if($attribute->hasFlag(AF_MULTILANGUAGE))
- {
- $this->m_lngfield = $attribute->fieldName();
- }
- $attribute->init();
- $exist=false;
- if(isset($this->m_attribList[$attribute->fieldName()])&&is_object($this->m_attribList[$attribute->fieldName()]))
- {
- $exist=true;
- // if order is set, overwrite it with new order, last order will count
- if($order!=0)
- {
- $this->m_attribIndexList[$this->m_attribList[$attribute->fieldName()]->m_index]["order"]=$order;
- }
- $attribute->m_index = $this->m_attribList[$attribute->fieldName()]->m_index;
- }
- if(!$exist)
- {
- if ($order == 0)
- {
- $this->m_attribOrder += 100;
- $order = $this->m_attribOrder;
- }
- if (!atkReadOptimizer())
- {
- // add new tab(s) to the tab list ("*" isn't a tab!)
- if ($tabs != "*")
- {
- if (!$attribute->hasFlag(AF_HIDE_ADD)) $this->m_tabList["add"] = isset($this->m_tabList["add"]) ? atk_array_merge($this->m_tabList["add"], $tabs) : $tabs;
- if (!$attribute->hasFlag(AF_HIDE_EDIT)) $this->m_tabList["edit"] = isset($this->m_tabList["edit"]) ? atk_array_merge($this->m_tabList["edit"], $tabs) : $tabs;
- if (!$attribute->hasFlag(AF_HIDE_VIEW)) $this->m_tabList["view"] = isset($this->m_tabList["view"]) ? atk_array_merge($this->m_tabList["view"], $tabs) : $tabs;
- }
- if ($sections != "*")
- {
- if (!$attribute->hasFlag(AF_HIDE_ADD)) $this->m_sectionList["add"] = isset($this->m_sectionList["add"]) ? atk_array_merge($this->m_sectionList["add"], $sections) : $sections;
- if (!$attribute->hasFlag(AF_HIDE_EDIT)) $this->m_sectionList["edit"] = isset($this->m_sectionList['edit']) ? atk_array_merge($this->m_sectionList["edit"], $sections) : $sections;
- if (!$attribute->hasFlag(AF_HIDE_VIEW)) $this->m_sectionList["view"] = isset($this->m_sectionList['view']) ? atk_array_merge($this->m_sectionList["view"], $sections) : $sections;
- }
- }
- $attribute->m_order = $order;
- $this->m_attribIndexList[] = array("name"=>$attribute->fieldName(),"tabs"=>$tabs,"sections"=>$sections,"order"=>$attribute->m_order);
- $attribute->m_index = max(array_keys($this->m_attribIndexList)); // might contain gaps
- $attribute->setTabs($tabs);
- $attribute->setSections($sections);
- $this->m_attributeTabs[$attribute->fieldname()] = $tabs;
- }
- // Order the tablist
- $this->m_attribList[$attribute->fieldName()]=&$attribute;
- if(is_subclass_of($attribute,"atkrelation"))
- {
- $this->m_relations[strtolower(get_class($attribute))][$attribute->fieldName()]=&$attribute;
- }
- $attribute->setTabs($this->m_attributeTabs[$attribute->fieldName()]);
- $attribute->setSections($this->m_attribIndexList[$attribute->m_index]['sections']);
- $attribute->setColumn($column);
- return $attribute;
- }
- /**
- * Add fieldset.
- *
- * To include an attribute label use [attribute.label] inside your
- * template. To include an attribute edit/display field use
- * [attribute.field] inside your template.
- *
- * @param string $name name
- * @param string $template template string
- * @param int $flags attribute flags
- * @param mixed $sections The sections/tab(s) on which the attribute should be
- * displayed. Can be a tabname (String) or a list of
- * tabs (array) or "*" if the attribute should be
- * displayed on all tabs.
- * @param int $order The order at which the attribute should be displayed.
- * If ommitted, this defaults to 100 for the first
- * attribute, and 100 more for each next attribute that
- * is added.
- */
- public function addFieldSet($name, $template, $flags=0, $sections=NULL, $order=0)
- {
- useattrib('atkfieldset');
- $this->add(new atkFieldSet($name, $template, $flags), $sections, $order);
- }
- /**
- * Retrieve the tabnames from the sections string (tab.section).
- *
- * @param mixed $sections An array with sections or a section string
- */
- function getTabsFromSections($sections)
- {
- if($sections == "*" || $sections===NULL)
- return $sections;
- $tabs = array();
- if(!isset($sections))
- $section = array();
- elseif(!is_array($sections))
- $sections = array($sections);
- foreach($sections as $section)
- {
- $tabs[] = $this->getTabFromSection($section);
- }
- //when using the tab.sections notation, we can have duplicate tabs
- //strip them out.
- return array_unique($tabs);
- }
- /**
- * Strip section part from a section and return the tab.
- *
- * If no tab name is provided, the default tab is returned.
- *
- * @param string $section The section to get the tab from
- */
- function getTabFromSection($section)
- {
- $tab = ($section==NULL) ? "" : $section;
- if (strstr($tab,".") !== false)
- list($tab) = explode(".", $tab);
- return (($tab=="") ? $this->m_default_tab : $tab);
- }
- /**
- * Remove an attribute.
- *
- * Completely removes an attribute from a node.
- * Note: Since other functionality may already depend on the attribute
- * that you are about to remove, it's often better to just hide an
- * attribute if you don't need it.
- * @param String $attribname The name of the attribute to remove.
- */
- function remove($attribname)
- {
- if (is_object($this->m_attribList[$attribname]))
- {
- atkdebug("removing attribute $attribname");
- $listindex = $this->m_attribList[$attribname]->m_index;
- unset($this->m_attribList[$attribname]);
- foreach($this->m_listExcludes as $i => $name)
- {
- if ($name == $attribname) unset($this->m_listExcludes[$i]);
- }
- foreach($this->m_viewExcludes as $i => $name)
- {
- if ($name == $attribname) unset($this->m_viewExcludes[$i]);
- }
- foreach($this->m_cascadingAttribs as $i => $name)
- {
- if ($name == $attribname)
- {
- unset($this->m_cascadingAttribs[$i]);
- $this->m_cascadingAttribs = array_values($this->m_cascadingAttribs);
- }
- }
- unset($this->m_attribIndexList[$listindex]);
- unset($this->m_attributeTabs[$attribname]);
- }
- }
- /**
- * Returns the table name for this node.
- *
- * @return string table name
- */
- function getTable()
- {
- return $this->m_table;
- }
- /**
- * Get an attribute by name.
- * @param String $name The name of the attribute to retrieve.
- * @return atkAttribute The attribute.
- */
- function &getAttribute($name)
- {
- $returnValue = isset($this->m_attribList[$name]) ? $this->m_attribList[$name] : NULL;
- return $returnValue;
- }
- /**
- * Checks if the user has filled in something:
- * return true if he has, otherwise return false
- *
- * @param -
- * @return boolean.
- */
- function &filledInForm()
- {
- if (is_null($this->getAttributes())) return false;
- $postvars = atkGetPostVar();
- foreach ($this->m_attribList AS $name => $value)
- if (!$value->hasFlag(AF_HIDE_LIST))
- if (!is_array($value->fetchValue($postvars)) && $value->fetchValue($postvars)!=="")
- return true;
- return false;
- }
- /**
- * Gets all the attributes.
- * @return array Array with the attributes.
- */
- function &getAttributes()
- {
- if (isset($this->m_attribList))
- return $this->m_attribList;
- else return NULL;
- }
- /**
- * Returns a list of attribute names.
- *
- * @return array attribute names
- */
- function getAttributeNames()
- {
- return array_keys($this->m_attribList);
- }
- /**
- * Gets the attribute order.
- *
- * @param string $name The name of the attribute
- */
- function getAttributeOrder($name)
- {
- return $this->m_attribIndexList[$this->m_attribList[$name]->m_index]["order"];
- }
- /**
- * Sets an attributes order
- *
- * @param string $name The name of the attribute
- * @param int $order The order of the attribute
- */
- function setAttributeOrder($name, $order)
- {
- $this->m_attribList[$name]->m_order = $order;
- $this->m_attribIndexList[$this->m_attribList[$name]->m_index]["order"] = $order;
- }
- /**
- * Checks if the node has a certain flag set.
- * @param int $flag The flag to check.
- * @return boolean True if the node has the flag.
- */
- function hasFlag($flag)
- {
- return (($this->m_flags & $flag) == $flag);
- }
- /**
- * Add a flag to the node.
- * @param int $flag The flag to add.
- */
- function addFlag($flag)
- {
- $this->m_flags |= $flag;
- }
- /**
- * Removes a flag from the node.
- *
- * @param int $flag The flag to remove from the attribute
- */
- function removeFlag($flag)
- {
- if($this->hasFlag($flag)) $this->m_flags ^= $flag;
- }
- /**
- * Returns the node flags.
- * @return Integer node flags
- */
- function getFlags()
- {
- return $this->m_flags;
- }
- /**
- * Set node flags.
- *
- * @param int $flags node flags
- */
- public function setFlags($flags)
- {
- $this->m_flags = $flags;
- }
- /**
- * Returns the current partial name.
- *
- * @return string partial name
- */
- public function getPartial()
- {
- return $this->m_partial;
- }
- /**
- * Is partial request?
- *
- * @return boolean is partial
- */
- function isPartial()
- {
- return $this->m_partial;
- }
- /**
- * Sets the editable list attributes. If you supply this method
- * with one or more string arguments, all arguments are collected in
- * an array. Else the first parameter will be used.
- *
- * @param array $attrs list of attribute names
- */
- function setEditableListAttributes($attrs)
- {
- if (is_array($attrs))
- $this->m_editableListAttributes = $attrs;
- else $this->m_editableListAttributes = func_get_args();
- }
- /**
- * Sets the multi-record-action selection mode. Can either be
- * MRA_MULTI_SELECT (default), MRA_SINGLE_SELECT or
- * MRA_NO_SELECT.
- *
- * @param string $mode selection mode
- */
- function setMRASelectionMode($mode)
- {
- $this->m_mraSelectionMode = $mode;
- }
- /**
- * Returns the multi-record-action selection mode.
- * @return Integer multi-record-action selection mode
- */
- function getMRASelectionMode()
- {
- return $this->m_mraSelectionMode;
- }
- /**
- * Returns the primary key sql expression of a record.
- * @param array $rec The record for which the primary key is calculated.
- * @return String the primary key of the record.
- */
- function primaryKey($rec)
- {
- $primKey="";
- $nrOfElements = count($this->m_primaryKey);
- for ($i=0;$i<$nrOfElements;$i++)
- {
- $p_attrib = &$this->m_attribList[$this->m_primaryKey[$i]];
- $primKey.=$this->m_table.".".$this->m_primaryKey[$i]."='".$p_attrib->value2db($rec)."'";
- if ($i<($nrOfElements-1)) $primKey.=" AND ";
- }
- return $primKey;
- }
- /**
- * Retrieve the name of the primary key attribute.
- *
- * Note: If a node has a primary key that consists of multiple attributes,
- * this method will retrieve only the first attribute!
- * @return String First primary key attribute
- */
- function primaryKeyField()
- {
- if (count($this->m_primaryKey) === 0)
- {
- atkwarning($this->atkNodeType()."::primaryKeyField() called, but there are no primary key fields defined!");
- return null;
- }
- return $this->m_primaryKey[0];
- }
- /**
- * Returns a primary key template.
- *
- * Like primaryKey(), this method returns a sql expression, but in this
- * case, no actual data is used. Instead, template fields are inserted
- * into the expression. This is useful for rendering multiple primary
- * keys later with a record and a template parser.
- *
- * @return String Primary key template
- */
- function primaryKeyTpl()
- {
- $primKey="";
- $nrOfElements = count($this->m_primaryKey);
- for ($i=0;$i<$nrOfElements;$i++)
- {
- $primKey.=$this->m_primaryKey[$i]."='[".$this->m_primaryKey[$i]."]'";
- if ($i<($nrOfElements-1)) $primKey.=" AND ";
- }
- return $primKey;
- }
- /**
- * Set default sort order for the node.
- * @param String $orderby Default order by. Can be an attribute name or a
- * SQL expression.
- */
- function setOrder($orderby)
- {
- $this->m_default_order = $orderby;
- }
- /**
- * Get default sort order for the node.
- * @return String $orderby Default order by. Can be an attribute name or a
- * SQL expression.
- */
- function getOrder()
- {
- return $this->m_default_order;
- }
- /**
- * Set the table that the node should use.
- *
- * Note: This should be called in the constructor of derived classes,
- * after the base class constructor is called.
- * @param String $tablename The name of the table to use.
- * @param String $seq The name of the sequence to use for autoincrement
- * attributes.
- * @param mixed $db The database connection to use. If ommitted, this
- * defaults to the default database connection.
- * So in apps using only one database, it's not necessary
- * to pass this parameter.
- * You can pass either a connection (atkDb instance), or
- * a string containing the name of the connection to use.
- */
- function setTable($tablename,$seq="",$db=NULL)
- {
- $this->m_table = $tablename;
- if ($seq=="") $seq = $tablename;
- $this->m_seq = $seq;
- $this->m_db = $db;
- }
- /**
- * Sets the database connection.
- *
- * @param string|atkDb $db database name or object
- */
- public function setDb($db)
- {
- $this->m_db = $db;
- }
- /**
- * Get the database connection for this node.
- * @return atkDb Database connection instance
- */
- function getDb()
- {
- if ($this->m_db == NULL)
- {
- return atkGetDb();
- }
- else if (is_object($this->m_db))
- {
- return $this->m_db;
- }
- else
- {
- // must be a named connection
- return atkGetDb($this->m_db);
- }
- }
- /**
- * Create an alphabetical index.
- *
- * Any string- or textbased attribute can be used to create an
- * alphabetical index in admin- and selectpages.
- * @param String $attribname The name of the attribute for which to create
- * the alphabetical index.
- */
- function setIndex($attribname)
- {
- $this->m_index = $attribname;
- }
- /**
- * Set tab index
- *
- * @param string $tabname Tabname
- * @param int $index Index number
- * @param string $action Action name (add,edit,view)
- */
- function setTabIndex($tabname,$index,$action="")
- {
- atkdebug("atkNode::setTabIndex($tabname,$index,$action)");
- $actionList=array("add","edit","view");
- if($action!="") $actionList = array($action);
- foreach($actionList as $action)
- {
- $new_index = $index;
- $list = &$this->m_tabList[$action];
- if($new_index<0) $new_index=0;
- if($new_index>count($list)) $new_index = count($list);
- $current_index = array_search($tabname,$list);
- if($current_index!==NULL)
- {
- $tmp = array_splice($list, $current_index, 1);
- array_splice($list, $new_index, 0, $tmp);
- }
- }
- }
- /**
- * Set default tab being displayed in view/add/edit mode.
- * After calling this method, all attributes which are added after the
- * method call without specification of tab will be placed on the default
- * tab. This means you should use this method before you add any
- * attributes to the node.
- * If you accept the default name for the first tab ("default") you do not
- * need to call this method.
- * @param String $tab the name of the default tab
- */
- function setDefaultTab($tab="default")
- {
- $this->m_default_tab = $tab;
- }
- /**
- * Get a list of tabs for a certain action.
- * @param String $action The action for which you want to retrieve the
- * list of tabs.
- * @return array The list of tabnames.
- *
- */
- function getTabs($action)
- {
- $list = &$this->m_tabList[$action];
- $disable = $this->checkTabRights($list);
- $tabCode = "";
- if (!is_array($list))
- {
- // fallback to view tabs.
- $list = &$this->m_tabList["view"];
- }
- // Attributes can also add tabs to the tablist.
- $this->m_filledTabs = array();
- foreach(array_keys($this->m_attribList) as $attribname)
- {
- $p_attrib = &$this->m_attribList[$attribname];
- if ($p_attrib->hasFlag(AF_HIDE)) continue; // attributes to which we don't have access are explicitly hidden
- // Only display the attribute if the attribute
- // resides on at least on visible tab
- for($i=0, $_i=sizeof($p_attrib->m_tabs); $i<$_i; $i++)
- {
- if ((is_array($list) && in_array($p_attrib->m_tabs[$i],$list)) || (!is_array($disable) || !in_array($p_attrib->m_tabs[$i],$disable)))
- {
- break;
- }
- }
- if(is_object($p_attrib))
- {
- $additional = $p_attrib->getAdditionalTabs($action);
- if(is_array($additional) && count($additional)>0)
- {
- $list = atk_array_merge($list, $additional);
- $this->m_filledTabs = atk_array_merge($this->m_filledTabs, $additional);
- }
- // Keep track of the tabs that containg attribs
- // so we only display none-empty tabs
- $tabCode = $this->m_attributeTabs[$attribname][0];
- if(!in_array($tabCode,$this->m_filledTabs))
- {
- $this->m_filledTabs[]=$tabCode;
- }
- }
- else
- {
- atkdebug("atknode::getTabs() Warning: $attribname is not an object!?");
- }
- }
- // Check if the currently known tabs all containg attributes
- // so we don't end up with empty tabs
- return $this->checkEmptyTabs($list);
- }
- /**
- * Retrieve the sections for the active tab.
- *
- * @param String $action
- * @return array The active sections.
- */
- function getSections($action)
- {
- $sections = array();
- if (is_array($this->m_sectionList[$action]))
- {
- foreach ($this->m_sectionList[$action] as $element)
- {
- list($tab,$sec) = (strpos($element, ".") !== false) ? explode(".",$element) : array($element, null);
- //if this section is on an active tab, we return it.
- if($tab == $this->getActiveTab() && $sec!==NULL)
- $sections[] = $sec;
- }
- }
- //we do not want duplicate sections on the same tab.
- return array_unique($sections);
- }
- /**
- * Add sections that must be expanded by default.
- *
- */
- function addDefaultExpandedSections()
- {
- $sections = func_get_args();
- $sections = $this->resolveSections($sections);
- $this->m_default_expanded_sections = array_unique(array_merge($sections, $this->m_default_expanded_sections));
- }
- /**
- * Remove sections that must be expanded by default.
- *
- */
- function removeDefaultExpandedSections()
- {
- $sections = func_get_args();
- $this->m_default_expanded_sections = array_diff($this->m_default_expanded_sections, $sections);
- }
- /**
- * Check if the user has the rights to access existing tabs and
- * removes tabs from the list that may not be accessed
- *
- * @param array $tablist Array containing the current tablist
- * @return array with disable tabs
- */
- function checkTabRights(&$tablist)
- {
- global $g_nodes;
- $disable = array();
- if (empty($this->m_module))
- return $disable;
- for ($i=0, $_i=count($tablist); $i<$_i; $i++)
- {
- if ($tablist[$i] == "" || $tablist[$i] == "default") continue;
- $secMgr = &atkGetSecurityManager();
- // load the $g_nodes array to find out what tabs are required
- if (!isset($g_nodes[$this->m_module][$this->m_type]))
- {
- include_once(atkconfig("atkroot") . "atk/atknodetools.inc");
- $module = &getModule($this->m_module);
- $module->getNodes();
- }
- $priv = "tab_" . $tablist[$i];
- if (isset($g_nodes[$this->m_module][$this->m_type]) && atk_in_array($priv,$g_nodes[$this->m_module][$this->m_type]))
- {
- // authorisation is required
- if (!$secMgr->allowed($this->m_module.".".$this->m_type,"tab_" . $tablist[$i]))
- {
- atkdebug("Removing TAB ". $tablist[$i] . " because access to this tab was denied");
- $disable[] = $tablist[$i];
- unset($tablist[$i]);
- }
- }
- }
- if (is_array($tablist))
- {
- // we might have now something like:
- // [0]=>tabA,[3]=>tabD
- // we convert this to a 'normal' array:
- // [0]=>tabA,[1]=>tabD;
- $newarray = array();
- foreach($tablist as $tab)
- $newarray[] = $tab;
- $tablist = $newarray;
- }
- return $disable;
- }
- /**
- * Remove tabs without attribs from the tablist
- * @param array $list The list of tabnames
- * @return array The list of tabnames without the empty tabs.
- *
- */
- function checkEmptyTabs($list)
- {
- $tabList = array();
- if (is_array($list))
- {
- foreach ($list AS $tabEntry)
- {
- if (in_array($tabEntry, $this->m_filledTabs))
- {
- $tabList[] = $tabEntry;
- }
- else
- {
- atkdebug("Removing TAB ".$tabEntry." because it had no attributes assigned");
- }
- }
- }
- return $tabList;
- }
- /**
- * Returns the currently active tab.
- *
- * Note that in themes which use dhtml tabs (tabs without reloads), this
- * method will always return the name of the first tab.
- * @return String The name of the currently visible tab.
- */
- function getActiveTab()
- {
- global $ATK_VARS;
- $tablist = $this->getTabs($ATK_VARS["atkaction"]);
- // Note: we may not read atktab from $this->m_postvars, because $this->m_postvars is not filled if this is
- // a nested node (in a relation for example).
- if (!empty($ATK_VARS["atktab"]) && in_array($ATK_VARS["atktab"], $tablist)) $tab = $ATK_VARS["atktab"];
- elseif (!empty($this->m_default_tab) && in_array($this->m_default_tab, $tablist)) $tab = $this->m_default_tab;
- else $tab = $tablist[0];
- return $tab;
- }
- /**
- * Get the active sections.
- *
- * @param string $tab The currently active tab
- * @param string $mode The current mode ("edit", "add", etc.)
- */
- function getActiveSections($tab, $mode)
- {
- $activeSections = array();
- if (is_array($this->m_sectionList[$mode]))
- {
- foreach ($this->m_sectionList[$mode] as $section)
- {
- if (substr($section, 0, strlen($tab)) == $tab)
- {
- atkimport("atk.session.atkstate");
- $sectionName = 'section_'.str_replace('.', '_', $section);
- $key = array("nodetype" => $this->atknodetype(), "section" => $sectionName);
- $defaultOpen = in_array($section, $this->m_default_expanded_sections);
- if (atkState::get($key, $defaultOpen ? 'opened' : 'closed') != 'closed')
- {
- $activeSections[] = $section;
- }
- }
- }
- …
Large files files are truncated, but you can click here to view the full file