/** * The decryption method for decrypting data with the bajus algorithm. * * @param mixed $input the data we want to encrypt * @param mixed $key the key we want to encrypt the data with * * @return mixed the encrypted data */ public function decrypt($input, $key) { $input = $this->addbackslashes($input); $keys = $this->getKeys($key); $key = openssl_get_privatekey($keys['private']); if ($key) { Tools::atkerror('OpenSSLEncryption::decrypt << not a valid key passed'); } else { echo "decrypt for: input:{$input}, decrypted: {$decrypted}, key: {$key}"; openssl_private_decrypt($input, $decrypted, $key); } return $decrypted; }
/** * With this function you can set the "custom" list with a array of country ISO codes * that are KNOWN to this class. (they should be in the world list atleast). * * @param array $countries CountryIso codes, like NL BE LU etc... * * @return bool It will return false when the resulting custom list is empty. */ public function setList($countries) { $custom_list = []; foreach ($countries as $countryIso) { $countryIso = strtoupper($countryIso); if (in_array($countryIso, $this->m_world_countries)) { array_push($custom_list, $countryIso); } else { Tools::atkwarning('atkCountryAttribute: setList: ' . $countryIso . ' is a unknown country and will be ignored'); } } if (count($custom_list) == 0) { Tools::atkerror('atkCountryAttribute: setList: empty custom country list'); return false; } $this->m_custom_countries = $custom_list; return true; }
/** * Converts the internal attribute value to one that is understood by the * database. * * For this attribute the data is not written to a database but to a file * * @param array $record The record that holds this attribute's value. * * @return string The database compatible value */ public function value2db($record) { // Note1 : regardless of mode (update or add), we always overwrite the // file with the current contents. // Note 2: even if contents is "", we write the file, since the file // might exist and contain old information. $contents = $record[$this->fieldName()]; $parser = new StringParser($this->m_filename); if (!$parser->isComplete($record)) { // record does not contain all data. Let's lazy load. Tools::atkdebug('[atkfilewriter] Lazy loading rest of record to complete filename.'); $record = $this->m_ownerInstance->select($record['atkprimkey'])->getFirstRow(); } $filename = $parser->parse($record); $fp = @fopen($filename, 'w'); if ($fp == false) { Tools::atkerror('[' . $this->fieldName() . "] couldn't open {$filename} for writing!"); } else { fwrite($fp, $contents); fclose($fp); Tools::atkdebug('[' . $this->fieldName() . "] succesfully wrote {$filename}.."); } return $this->escapeSQL($contents); }
/** * Get the Smarty instance. * * @return \Smarty The one and only instance. */ public static function getInstance() { static $s_smarty = null; if ($s_smarty == null) { Tools::atkdebug('Creating Smarty instance'); $tplcompiledir = Config::getGlobal('tplcompiledir'); if (!is_dir($tplcompiledir) && !mkdir($tplcompiledir, 0755, true)) { Tools::atkerror("Unable to create template compile directory: {$tplcompiledir}"); } $tplcompiledir = realpath($tplcompiledir); $s_smarty = new Smarty(); $s_smarty->setTemplateDir(Config::getGlobal('template_dir')); // name of directory for templates $s_smarty->autoload_filters = []; // indicates which filters will be auto-loaded $s_smarty->setCompileDir($tplcompiledir); // name of directory for compiled templates $s_smarty->setForceCompile(Config::getGlobal('tplforcecompile')); // force templates to compile every time, $s_smarty->addPluginsDir(__DIR__ . '/plugins'); Tools::atkdebug('Instantiated new Smarty'); } return $s_smarty; }
/** * Check unique field combinations. * The function is called by the validate() method automatically. It is * not necessary to call this manually in a validation process. * Errors that are found are stored in the $record parameter. * * @param array $record The record to validate */ public function validateUniqueFieldSets(&$record) { $db = $this->m_nodeObj->getDb(); foreach ($this->m_nodeObj->m_uniqueFieldSets as $uniqueFieldSet) { $query = $db->createQuery(); $query->addField('*'); $query->addTable($this->m_nodeObj->m_table); $attribs = []; foreach ($uniqueFieldSet as $field) { $attrib = $this->m_nodeObj->m_attribList[$field]; if ($attrib) { $attribs[] = $attrib; if (method_exists($attrib, 'createDestination') && isset($attrib->m_refKey) && is_array($attrib->m_refKey) && count($attrib->m_refKey) > 1) { $attrib->createDestination(); foreach ($attrib->m_refKey as $refkey) { $query->addCondition($query->quoteField($refkey) . " = '" . $db->escapeSQL($record[$attrib->fieldName()][$refkey]) . "'"); } } else { if (!$attrib->isNotNullInDb() && $attrib->isEmpty($record)) { $query->addCondition($query->quoteField($field) . ' IS NULL'); } else { $query->addCondition($query->quoteField($field) . " = '" . $attrib->value2db($record) . "'"); } } } else { Tools::atkerror("Field {$field} is mentioned in uniquefieldset but does not exist in " . $this->m_nodeObj->atkNodeUri()); } } if ($this->m_mode != 'add') { $query->addCondition('NOT (' . $this->m_nodeObj->primaryKey($record) . ')'); } if (count($db->getRows($query->buildSelect())) > 0) { Tools::atkTriggerError($record, $attribs, 'error_uniquefieldset'); } } }
public function edit($record, $fieldprefix, $mode) { if (!$this->createDestination()) { Tools::atkerror("Could not create destination for destination: {$this} -> m_destination!"); return; } $recordset = $this->m_selectableRecords; if ($recordset === null && $this->hasFlag(self::AF_RELATION_AUTOCOMPLETE) && $this->m_autocomplete_minrecords > -1) { $recordset = $this->_getSelectableRecords($record, $mode); } $isAutocomplete = is_array($recordset) && count($recordset) > $this->m_autocomplete_minrecords || $this->m_autocomplete_minrecords == -1; if ($this->hasFlag(self::AF_RELATION_AUTOCOMPLETE) && is_object($this->m_ownerInstance) && $isAutocomplete) { return $this->drawAutoCompleteBox($record, $fieldprefix, $mode); } $result = ''; $options = []; $id = $this->getHtmlId($fieldprefix); $name = $this->getHtmlName($fieldprefix); $htmlAttributes = []; $editflag = true; $value = isset($record[$this->fieldName()]) ? $record[$this->fieldName()] : null; $currentPk = $value != null ? $this->getDestination()->primaryKey($value) : null; $selValues = $currentPk != null ? [$currentPk] : []; if ($this->hasFlag(self::AF_LARGE)) { //no select list, but a link for select $editflag = false; $result = ''; $result .= '<span class="atkmanytoonerelation-large-container">'; $destrecord = $record[$this->fieldName()]; if (is_array($destrecord)) { $result .= '<span id="' . $id . '_current">'; if ($this->hasFlag(self::AF_RELATION_AUTOLINK) && $this->m_destInstance->allowed('view') && !$this->m_destInstance->hasFlag(Node::NF_NO_VIEW)) { $url = Tools::dispatch_url($this->m_destination, 'view', ['atkselector' => $this->m_destInstance->primaryKey($record[$this->fieldName()])]); $descriptor = $this->m_destInstance->descriptor($destrecord); $result .= $descriptor . ' ' . Tools::href($url, Tools::atktext('view'), SessionManager::SESSION_NESTED, true, 'class="atkmanytoonerelation-link"'); } else { $result .= $this->m_destInstance->descriptor($destrecord); } $result .= ' '; if (!$this->hasFlag(self::AF_OBLIGATORY)) { $result .= '<a href="#" onClick="jQuery(\'#' . $id . '\').val(\'\');jQuery(\'#' . $id . '_current\').hide();" class="atkmanytoonerelation atkmanytoonerelation-link">' . Tools::atktext('unselect') . '</a> '; } $result .= '</span>'; } $result .= $this->hide($record, $fieldprefix, $mode); $result .= $this->_getSelectLink($name, $this->parseFilter($this->m_destinationFilter, $record)); } else { //normal dropdown if ($recordset == null) { $recordset = $this->_getSelectableRecords($record, $mode); } if (count($recordset) == 0) { $editflag = false; } // autoselect if there is only one record (if obligatory is not set, // we don't autoselect, since user may wist to select 'none' instead // of the 1 record. if (count($recordset) == 0) { $result = $this->getNoneLabel(); } else { // relation may be empty, so we must provide an empty selectable.. $hasNullOption = false; $emptyValue = ''; if ($this->hasFlag(self::AF_MANYTOONE_OBLIGATORY_NULL_ITEM) || !$this->hasFlag(self::AF_OBLIGATORY) && !$this->hasFlag(self::AF_RELATION_NO_NULL_ITEM) || Config::getGlobal('list_obligatory_null_item') && !is_array($value)) { $hasNullOption = true; $noneLabel = $this->getNoneLabel($mode); $options[$emptyValue] = $noneLabel; } foreach ($recordset as $selectable) { $pk = $this->getDestination()->primaryKey($selectable); $options[$pk] = $this->m_destInstance->descriptor($selectable); } $selectOptions = []; $selectOptions['enable-select2'] = true; $selectOptions['minimum-results-for-search'] = 10; $selectOptions['dropdown-auto-width'] = true; if ($hasNullOption) { $selectOptions['with-empty-value'] = $emptyValue; } if (!empty($this->getWidth())) { $selectOptions['width'] = $this->getWidth(); } else { $selectOptions['width'] = 'resolve'; } $selectOptions = array_merge($selectOptions, $this->m_select2Options['edit']); if (count($this->m_onchangecode)) { $this->_renderChangeHandler($fieldprefix); $htmlAttributes['onchange'] = $this->getHtmlId($fieldprefix) . '_onChange(this)'; } $result .= $this->drawSelect($id, $name, $options, $selValues, $selectOptions, $htmlAttributes); } } $autolink = $this->getRelationAutolink($id, $name, $this->parseFilter($this->m_destinationFilter, $record)); $result .= $editflag && isset($autolink['edit']) ? $autolink['edit'] : ''; $result .= isset($autolink['add']) ? $autolink['add'] : ''; if ($this->hasFlag(self::AF_LARGE)) { $result .= '</span>'; // atkmanytoonerelation-large-container } return $result; }
/** * This method sets a state value. A state value can either be saved in the * current user's session (in the global session, so not in a specific stack!) * or in a cookie (by default in a cookie), the atk state cookie. Whatever * mechanism is used depends on the $type parameter. The key doesn't necessarily * have to be a string (this is also true for the get method). This means that * if you get an array as key you probably have to flatten the key to something * useful because if you want to save a value in the session or in a cookie * the key needs to be a simple string. You could use, for example * print_r($key, true) to get a nice string representation. For cookies it might * be even more safe to md5 this string so that they key doesn't say anything to * the user and doesn't get too big. * * @param mixed $key The key name * @param string $value The value of key * @param string $type The namespace from which to retrieve the value * * @return mixed The storage method type. */ public static function set($key, $value, $type = 'cookie') { $key = self::getKey($key); switch ($type) { case 'cookie': self::_set_using_cookie($key, $value); break; case 'session': self::_set_using_session($key, $value); break; default: Tools::atkerror("set method don't exists"); } }
/** * This method returns a form that the user can use to search records. * * @param array $record A record containing default values to put into * the search fields. * * @return string The searchform in html form. */ public function searchForm($record = null) { $node = $this->m_node; $ui = $this->getUi(); if (is_object($ui)) { $node->setAttribSizes(); $criteria = $this->fetchCriteria(); $name = $this->handleSavedCriteria($criteria); $params = []; $params['searchmode_title'] = Tools::atktext('search_mode', 'atk'); $params['searchmode_and'] = '<input type="radio" name="atksearchmethod" class="atkradio" value="AND" checked>' . Tools::atktext('search_and', 'atk'); $params['searchmode_or'] = '<input type="radio" name="atksearchmethod" class="atkradio" value="OR">' . Tools::atktext('search_or', 'atk'); $params['saved_criteria'] = $this->getSavedCriteria($name); $params['fields'] = []; foreach ($node->getAttributeNames() as $attribname) { $p_attrib = $node->m_attribList[$attribname]; if (!$p_attrib->hasFlag(Attribute::AF_HIDE_SEARCH)) { $p_attrib->addToSearchformFields($params['fields'], $node, $record, '', true); } } return $ui->render($node->getTemplate('search', $record), $params); } else { Tools::atkerror('ui object error'); } }
/** * Empty all database tables. */ public function deleteAll() { $tables = $this->table_names(false); $count = count($tables); do { $prevCount = $count; $count = 0; foreach ($tables as $table) { $query = $this->createQuery(); $query->addTable($table['table_name']); if (!$query->executeDelete()) { ++$count; } } } while ($count < $prevCount && $count > 0); if ($count > 0) { Tools::atkerror(__CLASS__ . '::deleteAll failed, probably because of circular dependencies'); } }
/** * Generic method invoker. * * Handler methods invoked with invoke() instead of directly, have a major * advantage: the handler automatically searches for an override in the * node. For example, If a handler calls its getSomething() method using * the invoke method, the node may implement its own version of * getSomething() and that method will then be called instead of the * original. The handler is passed by reference to the override function * as first parameter, so if necessary, you can call the original method * from inside the override. * * The function accepts a variable number of parameters. Any parameter * that you would pass to the method, can be passed to invoke(), and * invoke() will pass the parameters on to the method. * * There is one limitation: you can't pass parameters by reference if * you use invoke(). * * <b>Example:</b> * * <code> * $handler->invoke("editPage", $record, $mode); * </code> * * This will call editPage(&$handler, $record, $mode) on your node class * if present, or editPage($record, $mode) in the handler if the node has * no override. * * @param string $methodname The name of the method to call. * * @return mixed The method returns the return value of the invoked * method. */ public function invoke($methodname) { $arguments = func_get_args(); // Put arguments in a variable (php won't let us pass func_get_args() to other functions directly. // the first argument is $methodname, which we already defined by name. array_shift($arguments); if ($this->m_node !== null && method_exists($this->m_node, $methodname)) { Tools::atkdebug("Invoking '{$methodname}' override on node"); // We pass the original object as first parameter to the override. array_unshift($arguments, $this); $arguments[0] =& $this; // reference copy workaround; return call_user_func_array(array(&$this->m_node, $methodname), $arguments); } else { if (method_exists($this, $methodname)) { Tools::atkdebug("Invoking '{$methodname}' on ActionHandler for action " . $this->m_action); return call_user_func_array(array(&$this, $methodname), $arguments); } } Tools::atkerror("Undefined method '{$methodname}' in ActionHandler"); return; }
/** * Create the instance of the destination. * * If succesful, the instance is stored in the m_destInstance member variable. * * @return bool true if succesful, false if something went wrong. */ public function createDestination() { if (!is_object($this->m_destInstance)) { $atk = Atk::getInstance(); $cache_id = $this->m_owner . '.' . $this->m_name; $this->m_destInstance = $atk->atkGetNode($this->m_destination, true, $cache_id); // Validate if destination was created succesfully if (!is_object($this->m_destInstance)) { Tools::atkerror("Relation with unknown nodetype '" . $this->m_destination . "' (in node '" . $this->m_owner . "')"); $this->m_destInstance = null; return false; } if ($this->hasFlag(self::AF_NO_FILTER)) { $this->m_destInstance->m_flags |= Node::NF_NO_FILTER; } foreach (array_keys($this->m_destInstance->m_attribList) as $key) { $attribute = $this->m_destInstance->m_attribList[$key]; if (is_subclass_of($attribute, 'Relation') && is_object($this->m_ownerInstance) && $attribute->m_destination == $this->m_ownerInstance->atkNodeUri()) { $attribute->m_destInstance = $this->m_ownerInstance; if (count($attribute->m_tabs) == 1 && $attribute->m_tabs[0] == 'default') { $attribute->setTabs($this->m_tabs); } } } if (!empty($this->m_descHandler)) { $this->m_destInstance->setDescriptorHandler($this); } if (!empty($this->m_descTemplate)) { $this->m_destInstance->setDescriptorTemplate($this->m_descTemplate); } } return true; }
/** * Returns an htmlpage displaying all displayable attributes. * * @param array $record The record to display. * @param Node $node The node for which a viewPage is displayed. * @param bool $renderbox Render this action in a renderbox or just output the HTML * * @return string The html page with a reaonly view of relevant fields. */ public function viewPage($record, $node, $renderbox = true) { $ui = $this->getUi(); if (is_object($ui)) { $params = $node->getDefaultActionParams(); $tab = $node->getActiveTab(); $innerform = $this->viewForm($record, 'view'); $params['activeTab'] = $tab; $params['header'] = $this->invoke('viewHeader', $record); $params['title'] = $node->actionTitle($this->m_action, $record); $params['content'] = $node->tabulate('view', $innerform); $params['formstart'] = $this->getFormStart($record); $params['buttons'] = $this->getFormButtons($record); $params['formend'] = '</form>'; $output = $ui->renderAction('view', $params); if (!$renderbox) { return $output; } $this->getPage()->setTitle(Tools::atktext('app_shorttitle') . ' - ' . $node->actionTitle($this->m_action, $record)); $vars = array('title' => $node->actionTitle($this->m_action, $record), 'content' => $output); $total = $ui->renderBox($vars, $this->m_boxTemplate); return $total; } else { Tools::atkerror('ui object error'); } }
/** * Display a tabbed pane with attributes. * * @param array $record Array with fields * @param string $mode The mode * * @return string html code */ public function display($record, $mode) { // get active tab $active_tab = $this->getDefaultTab(); $fields = []; $tab = ''; $node = $this->m_ownerInstance; $ui = $node->getUi(); // For all attributes we use the display() function to display the // attributes current value. This may be overridden by supplying // an <attributename>_display function in the derived classes. foreach ($this->m_attribsList as $name => $tab) { $p_attrib = $node->getAttribute($name); if (is_object($p_attrib)) { $tplfield = []; if (!$p_attrib->hasFlag(self::AF_HIDE_VIEW)) { $fieldtab = $this->m_attribsList[$name]; $tplfield['class'] = "tabbedPaneAttr tabbedPaneTab{$fieldtab}"; $tplfield['rowid'] = 'tabbedPaneAttr_' . Tools::getUniqueId('anonymousattribrows'); // The id of the containing row $tplfield['tab'] = $tplfield['class']; // for backwards compatibility $tplfield['initial_on_tab'] = $fieldtab == $active_tab; // An <attributename>_display function may be provided in a derived // class to display an attribute. If it exists we will use that method // else we will just use the attribute's display method. $funcname = $p_attrib->m_name . '_display'; if (method_exists($node, $funcname)) { $editsrc = $node->{$funcname}($record, 'view'); } else { $editsrc = $p_attrib->display($record, 'view'); } $tplfield['full'] = $editsrc; $tplfield['widget'] = $editsrc; // in view mode, widget and full are equal // The Label of the attribute (can be suppressed with self::AF_NOLABEL or self::AF_BLANKLABEL) // For each attribute, a txt_<attributename> must be provided in the language files. if (!$p_attrib->hasFlag(self::AF_NOLABEL) && !$this->isAttributeSingleOnTab($name)) { if ($p_attrib->hasFlag(self::AF_BLANKLABEL)) { $tplfield['label'] = ''; } else { $tplfield['label'] = $p_attrib->label(); } } else { // Make the rest fill up the entire line $tplfield['label'] = ''; $tplfield['line'] = $tplfield['full']; } $fields[] = $tplfield; } } else { Tools::atkerror("Attribute {$name} not found!"); } } $innerform = $ui->render($node->getTemplate('view', $record, $tab), array('fields' => $fields)); return $this->tabulate('view', $innerform); }
/** * This function overrides the deleteDb function to delete a file * from the selected directory. * * @param string $selector The identifier of the file that should be deleted * * @return bool The result of the file deletion */ public function deleteDb($selector) { $sessmngr = SessionManager::getInstance(); $this->m_dir = $this->stripDir($sessmngr->stackVar('dirname')); $decodedselector = Tools::decodeKeyValuePair($selector); $filename = $decodedselector['dummy.filename']; Tools::atk_var_dump($this->m_dir, 'm_dir'); Tools::atk_var_dump($filename, 'filename'); if (strpos($filename, '..') === false) { unlink($this->m_dir . $filename); Tools::atkdebug('Deleted ' . $this->m_dir . $filename); } else { Tools::atkerror('Cannot unlink relative files. Possible hack attempt detected!'); } return true; }
/** * Writes a cached recordlist to the rlcache directory. * * @param string $output The HTML output of the recordlist * @param string $actionloader The actionloader js part of the recordlist */ public function writeCache($output, $actionloader) { if (!$this->noCaching()) { $sm = SessionManager::getInstance(); $stackID = $sm->atkStackID(); $output = str_replace($stackID, '*|REPLACESTACKID|*', $output); $actionloader = str_replace($stackID, '*|REPLACESTACKID|*', $actionloader); if (file_exists($this->m_cacheid)) { unlink($this->m_cacheid); } $fp =& fopen($this->m_cacheid, 'a+'); if ($fp) { fwrite($fp, $output); fclose($fp); } else { Tools::atkerror("Couldn't open {$this->m_cacheid} for writing!"); return; } $fp =& fopen($this->m_cacheid . '_actionloader', 'a+'); if ($fp) { fwrite($fp, $actionloader); fclose($fp); } else { return Tools::atkerror("Couldn't open {$this->m_cacheid}_actionloader for writing!"); } Tools::atkdebug("New cache created for {$this->m_node->m_module}.{$this->m_node->m_type} and written to: {$this->m_cacheid}"); } }
/** * Add file to archive with optional filepath. * * @param string $archive archive-path * @param string $filename file to add * @param string $filepath path where file will be placed in (optional, and only for zipmode "internal") * * @return bool $result */ public function add($archive, $filename, $filepath = '') { if (!$this->test()) { Tools::atkerror('atkZip->add: Could not add, system is not capable of add to a ZIP archive'); } if ($this->m_zipmode == 'internal') { $zip = new ZipArchive(); if ($zip->open($archive) === true) { Tools::atkdebug('AtkZip::add|adding ' . $filepath . basename($filename) . " to {$archive}"); $zip->addFile($filename, $filepath . basename($filename)); $zip->close(); return true; } else { Tools::atkerror("atkZip->add: Error while opening the zip archive ({$archive})"); return false; } } if ($this->m_zipmode == 'infozip') { $params = " -j {$archive} {$filename}"; $returncode = $this->runInfozipCommand(self::ATKZIP_ZIP, $params); if ($returncode <= 0) { return true; } else { Tools::atkerror(sprintf('atkZip->add: Infozip returned an error: %s (return code %d)', $this->getInfozipError(self::ATKZIP_ZIP, $returncode), $returncode)); return false; } } return false; }
public function store($db, $record, $mode) { if ($mode == 'update' && !empty($record[$this->fieldName()]['postdel'])) { $file = $this->m_dir . $record[$this->fieldName()]['postdel']; return $this->deleteFile($file); } $filename = $record[$this->fieldName()]['filename']; if ($record[$this->fieldName()]['tmpfile'] && $this->m_dir . $filename != $record[$this->fieldName()]['tmpfile']) { if ($filename != '') { $dirname = dirname($this->m_dir . $filename); if (!$this->mkdir($dirname)) { Tools::atkerror("File could not be saved, unable to make directory '{$dirname}'"); return false; } if (@copy($record[$this->fieldName()]['tmpfile'], $this->m_dir . $filename)) { $this->processFile($this->m_dir, $filename); return $this->escapeSQL($filename); } else { Tools::atkerror("File could not be saved, unable to copy file '{$record[$this->fieldName()]['tmpfile']}' to destination '{$this->m_dir}{$filename}'"); return false; } } } return true; }
/** * Attribute handler. * * @param string $partial full partial * * @return string */ public function partial_attribute($partial) { list($type, $attribute, $partial) = explode('.', $partial); $attr = $this->m_node->getAttribute($attribute); if ($attr == null) { Tools::atkerror("Unknown / invalid attribute '{$attribute}' for node '" . $this->m_node->atkNodeUri() . "'"); return ''; } return $attr->partial($partial, 'admin'); }
/** * Add callback function for add css class to row. * * @param mixed $callback name of a function or array with an object * and the name of a method or closure * * @return bool */ public function setRowClassCallback($callback) { $res = false; if (is_callable($callback, false, $callableName)) { if (is_array($callback) && !method_exists($callback[0], $callback[1])) { Tools::atkerror("The registered row class callback method '{$callableName}' doesn't exist"); } else { $this->m_rowClassCallback[] = $callback; $res = true; } } else { if (is_array($callback)) { if (!method_exists($callback[0], $callback[1])) { Tools::atkerror("The registered row class callback method '{$callableName}' doesn't exist"); } } Tools::atkerror("The registered row class callback '{$callableName}' is not callable"); } return $res; }
/** * Delete existing link record. * * @param array $record link record * * @return bool */ protected function _deleteRecord($record) { $selector = $this->getLink()->primaryKey($record); if (empty($selector)) { Tools::atkerror('primaryKey-selector for link node is empty. Did you add an self::AF_PRIMARY flag to the primary key field(s) of the intermediate node? Deleting records aborted to prevent dataloss.'); return false; } // append the store deletion filter (if set) if (!empty($this->m_store_deletion_filter)) { $selector = "({$selector}) AND ({$this->m_store_deletion_filter})"; } return $this->getLink()->deleteDb($selector); }
/** * Build DROP VIEW query. * * @param string $name - name of view * * @return string CREATE VIEW query string */ public function dropView($name) { Tools::atkerror("dropView don't support by this db or by this db driver"); return ''; }