v7‰PNG  IHDR Ÿ f Õ†C1 sRGB ®Îé gAMA ± üa pHYs à ÃÇo¨d GIDATx^íÜL”÷ð÷Yçªö("Bh_ò«®¸¢§q5kÖ*:þ0A­ºšÖ¥]VkJ¢M»¶f¸±8\k2íll£1]q®ÙÔ‚ÆT PKN\( DataSource/Array.phpnu[array[$this->getHash($a)] = $a; } public function getFoundRows() { return count($this->array); } public function selectPageRecords($page, $itemCountPerPage) { return array_map(function($a) {return (object)$a;}, array_slice($this->array, $page*$itemCountPerPage, $itemCountPerPage)); } public function setOrder($fieldNameOrRaw, $desc=null) { switch (is_null($desc)) { case true : if ($fieldNameOrRaw) { $this->_setOrderRaw($fieldNameOrRaw); } break; case false : $this->_setOrder($fieldNameOrRaw, $desc); break; } } protected function _setOrder($fieldName, $desc) { uasort($this->array, function($a, $b) use ($fieldName, $desc) { return ($desc ? -1 : 1) * strcmp($a->{$fieldName}, $b->{$fieldName}); }); } protected function _setOrderRaw($raw) { //@todo Parse Raw Order and use _setOrder } //this method is only for use in Am_Grid_Filter public function _friendGetArray() { return $this->array; } //this method is only for use in Am_Grid_Filter public function _friendSetArray($records) { return $this->array = $records; } public function getDataSourceQuery() { throw new Am_Exception_NotImplemented(__METHOD__); } public function getIdForRecord($record) { return $this->getHash($record); } protected function getHash($record) { return md5(serialize(get_object_vars($record))); } public function createRecord() { return new stdClass; } public function deleteRecord($id, $record) { unset($this->array[$id]); } public function getRecord($id) { return (object)$this->array[$id]; } public function insertRecord($record, $valuesFromForm) { throw new Am_Exception_NotImplemented(__METHOD__); } public function updateRecord($record, $valuesFromForm) { throw new Am_Exception_NotImplemented(__METHOD__); } }PKN\e!DataSource/Interface/Editable.phpnu[di = $table->getDi(); $this->config_key = $table->getCustomFieldsConfigKey(); $this->table = $table->getName(true); $this->pk = $table->getKeyField(); } public function insertRecord($record, $valuesFromForm) { $fields = $this->di->config->get($this->config_key, array()); $recordForStore = $this->getRecordForStore($valuesFromForm); $recordForStore['name'] = $valuesFromForm['name']; $fields[] = $recordForStore; Am_Config::saveValue($this->config_key, $fields); $this->di->config->set($this->config_key, $fields); if ($recordForStore['sql']) $this->addSqlField($recordForStore['name'], $recordForStore['additional_fields']['sql_type']); } public function updateRecord($record, $valuesFromForm) { $fields = $this->di->config->get($this->config_key); foreach ($fields as $k => $v) { if ($v['name'] == $record->name) { $recordForStore = $this->getRecordForStore($valuesFromForm); $recordForStore['name'] = $record->name; $fields[$k] = $recordForStore; } } Am_Config::saveValue($this->config_key, $fields); $this->di->config->set($this->config_key, $fields); if ($record->sql != $recordForStore['sql']) { if ($recordForStore['sql']) { $this->convertFieldToSql($record->name, $recordForStore['additional_fields']['sql_type']); } else { $this->convertFieldFromSql($record->name); } } elseif ($recordForStore['sql'] && $record->sql_type != $recordForStore['additional_fields']['sql_type']) { $this->changeSqlField($record->name, $recordForStore['additional_fields']['sql_type']); } } public function deleteRecord($id, $record) { $record = $this->getRecord($id); if (in_array($record->type, array('upload', 'multi_upload'))) { if ($record->sql) { $col = $this->di->db->selectCol("SELECT ?# FROM ?_{$this->table} WHERE ?# IS NOT NULL AND ?#<>'' AND ?#<>'a:0:{}'", $record->name, $record->name, $record->name, $record->name); } else { $col = $this->di->db->selectCol("SELECT `blob` FROM ?_data WHERE `table`=? AND `key`=? AND `blob` IS NOT NULL AND `blob`<>'' AND `blob`<>'a:0:{}'", $this->table, $record->name); } foreach ($col as $f) { $files = ($f[0] == 'a') ? unserialize($f) : array($f); foreach ($files as $id) { $file = $this->di->uploadTable->load($id, false); if ($file) $file->delete(); } } } $fields = $this->di->config->get($this->config_key); foreach ($fields as $k => $v) { if ($v['name'] == $record->name) unset($fields[$k]); } Am_Config::saveValue($this->config_key, $fields); $this->di->config->set($this->config_key, $fields); if ($record->sql) { $this->dropSqlField($record->name); } else { $this->dropDataField($record->name); } } public function createRecord() { $o = new stdClass; $o->name = null; $o->options = array(); $o->default = null; return $o; } protected function getRecordForStore($values) { if (($values['type'] == 'text') || ($values['type'] == 'textarea') || ($values['type'] == 'date')) { $default = $values['default']; } else { $default = array_intersect($values['values']['default'], array_keys($values['values']['options'])); if ($values['type'] == 'radio') $default = $default[0]; } if ($values['type'] == 'select') $values['size'] = 1; $recordForStore['title'] = $values['title']; $recordForStore['description'] = $values['description']; $recordForStore['sql'] = $values['sql']; $recordForStore['type'] = $values['type']; $recordForStore['validate_func'] = $values['validate_func']; $recordForStore['additional_fields'] = array( 'sql' => intval($values['sql']), 'sql_type' => $values['sql_type'], 'size' => $values['size'], 'default' => $default, 'options' => $values['values']['options'], 'cols' => $values['cols'], 'rows' => $values['rows'], ); $default_fields = array( 'type' => 1, 'default' => 1, 'values' => 1, 'size' => 1, 'title' => 1, 'description' => 1, 'validate_func' => 1, 'sql' => 1, 'sql_type' => 1, 'cols' => 1, 'rows' => 1); foreach ($values as $k => $v) { if (!isset($default_fields[$k]) && $k[0] != '_') { $recordForStore['additional_fields'][$k] = $v; } } return $recordForStore; } protected function addSqlField($name, $type) { $this->di->db->query("ALTER TABLE ?_{$this->table} ADD ?# $type", $name); } protected function dropSqlField($name) { $this->di->db->query("ALTER TABLE ?_{$this->table} DROP ?#", $name); } protected function dropDataField($name) { $this->di->db->query("DELETE FROM ?_data WHERE `table`=? AND `key`=?", $this->table, $name); } protected function changeSqlField($name, $type) { $this->di->db->query("ALTER TABLE ?_{$this->table} CHANGE ?# ?# $type", $name, $name); } protected function convertFieldToSql($name, $type) { $this->addSqlField($name, $type); $this->di->db->query("UPDATE ?_{$this->table} t SET ?# = (SELECT CASE `type` WHEN ? THEN `blob` WHEN ? THEN `blob` ELSE `value` END FROM ?_data WHERE `table`='{$this->table}' AND `key`= ? AND `id`=t.{$this->pk} LIMIT 1)", $name, Am_DataFieldStorage::TYPE_BLOB, Am_DataFieldStorage::TYPE_SERIALIZED, $name); $this->dropDataField($name); } protected function convertFieldFromSql($name) { $this->di->db->query("INSERT INTO ?_data (`table`, `key`, `id`, `type`, `value`, `blob`) " . "(SELECT '{$this->table}', ?, {$this->pk}, " . "IF(SUBSTRING(?#,1,2) = 'a:', 1, 0), " . "IF(SUBSTRING(?#,1,2) = 'a:', NULL, ?#), " . "IF(SUBSTRING(?#,1,2) = 'a:', ?#, NULL) " . "FROM ?_{$this->table} WHERE ?# IS NOT NULL)", $name, $name, $name, $name, $name, $name, $name); $this->dropSqlField($name); } public function getDataSourceQuery() { return null; } }PKN\ǂEditable/Content.phpnu[joinSort($this->createAdapter()); parent::__construct('_'.$this->getContentGridId(), $this->getTitle(), $adapter, $request, $view); $this->setEventId('gridContent' . ucfirst($this->getContentGridId())); $this->addCallback(self::CB_AFTER_INSERT, array($this, 'afterInsert')); $this->addCallback(self::CB_AFTER_UPDATE, array($this, 'afterInsert')); $this->addCallback(self::CB_VALUES_TO_FORM, array($this, '_valuesToForm')); foreach ($this->getActions() as $action) $action->setTarget('_top'); } /** * Add join to resource_access_sort and sort field * to be present in the result */ protected function joinSort(Am_Query $q) { $q->getTable()->addDefaultSort($q); return $q; } public function getTitle() { return ___(ucfirst($this->getContentGridId())); } public function getContentGridId() { $id = preg_split('#[\\\\_]#', get_class($this)); $id = strtolower(array_pop($id)); return $id; } function renderAccessTitle(ResourceAbstract $r) { $title = $this->escape($r->title); if (!empty($r->hide)) $title = "$title"; return $this->renderTd($title, false); } protected function initGridFields() { $this->addField(new Am_Grid_Field_Expandable('_access', ___('Products'), false)) ->setPlaceholder(array($this, 'getPlaceholder')) ->setRenderFunction(array($this, 'renderProducts')) ->setGetFunction(array($this, 'getProducts')) ->setMaxLength(200); $this->addField('_link', ___('Link'), false)->setRenderFunction(array($this, 'renderLink')); $this->actionAdd(new Am_Grid_Action_SortContent()); parent::initGridFields(); } public function renderLink(ResourceAbstract $resource) { $html = ""; $url = $resource->getUrl(); if (!empty($url)) $html = sprintf('%s', $this->escape($url), ___('link')); return $this->renderTd($html, false); } public function renderProducts($obj, $fieldName, $controller, $field) { return $this->renderTd($field->get($obj, $controller), false); } public function renderCategory(ResourceAbstract $e) { $res = array(); $options = $this->getDi()->resourceCategoryTable->getOptions(); foreach ($e->getCategories() as $resc_id) { $res[] = $options[$resc_id]; } return $this->renderTd(implode(", ", $res)); } public function getProducts(ResourceAbstract $resource) { $s = ""; foreach ($resource->getAccessList() as $access) { $l = ""; if ($access->getStart()) $l .= " from " . $access->getStart(); if ($access->getStop()) $l .= " to " . $access->getStop(); $s .= sprintf("%s %s %s
\n", $access->getClassTitle(), $access->getTitle(), $l); } return $s; } public function getPlaceholder($val, ResourceAbstract $resource) { return ___('%d access records…', count($resource->getAccessList())); } public function afterInsert(array & $values, ResourceAbstract $record) { $record->setAccess($values['_access']); } public function _valuesToForm(array & $values, Am_Record $record) { $values['_access'] = $this->getRecord()->getAccessList(); } public function renderPath(ResourceAbstractFile $file) { $upload = $file->getUpload(); try{ $file->isLocal(); } catch (Exception $e) { if (!$upload) return $this->renderTd( '' . ___('The file has been removed from disk or corrupted. Please re-upload it.') . '' . ' (' . ___('Error from Storage Engine') . ': ' . $this->escape($e->getMessage()) . ')' . '
' . ___('Real Path') . ': ' . $this->escape($file->path), false); } return $upload && !file_exists($upload->getFullPath()) ? $this->renderTd( '
' . ___('The file has been removed from disk or corrupted. Please re-upload it.') . ''. '
' . $this->escape($upload->getName() . '/' . $upload->getFilename()) . '
' . '
', false) : $this->renderTd(sprintf('%s (%s)', $this->escape($file->getDisplayFilename()), $file->getStorageId()), false); } protected function getTemplateOptions() { $folders = array( AM_APPLICATION_PATH . '/default/views/' => 1, AM_APPLICATION_PATH . '/default/themes/' . $this->getDi()->config->get('theme') => 2, ); $ret = array( null => 'layout.phtml' ); foreach (array_keys($folders) as $f) { foreach ((array) glob($f . '/layout*.phtml') as $file) { if (!strlen($file)) continue; $file = basename($file); if ($file == 'layout.phtml') continue; $ret[$file] = $file; } } return $ret; } protected function addCategoryToForm($form) { $category = $form->addCategory('_category', null, array( 'base_url' => 'admin-resource-categories', 'link_title' => ___('Edit Categories'), 'title' => ___('Content Categories'), 'options' => Am_Di::getInstance()->resourceCategoryTable->getOptions())) ->setLabel(___("Content Categories\n" . "these categories will be shown in user's menu if user has access to " . "resources in this category. You can uses these categories to organize " . "your content by pages")); } } PKN\,j(Action/Group/Callback.phpnu[id = $id; $this->title = $title; $this->callback = $callback; parent::__construct(); } public function handleRecord($id, $record) { call_user_func($this->callback, $id, $record, $this, $this->grid); } }PKN\X==Action/Group/Abstract.phpnu[confirmationText = ___("Do you really want to %s %s %s records"); parent::__construct($id, $title); } /** * @return array int */ public function getIds() { $ids = $this->grid->getRequest()->get(Am_Grid_Editable::GROUP_ID_KEY); $ids = explode(",", $ids); if (in_array(self::ALL, $ids)) return array(self::ALL); $ids = array_filter(array_map('intval', $ids)); return $ids; } public function getConfirmationText() { return ___($this->confirmationText, $this->getTitle(), $this->getTextCount(), $this->grid->getRecordTitle() ) . '?'; } public function getDoneText(){ return ___("DONE").". "; } public function getTextCount() { $ids = $this->getIds(); if (in_array(self::ALL, $ids)) return $this->grid->getDataSource()->getFoundRows(); return count($ids); } public function run() { // we do not accept GET requests by security reasons. so nobody can say give a link that deletes all users if ($this->needConfirmation && (!$this->grid->getRequest()->isPost() || !$this->grid->getRequest()->get('confirm'))) { echo $this->renderConfirmation(); } else { echo $this->renderRun($this->getIds()); } } public function renderRun($ids) { echo ___("Running %s", $this->getTitle()) . '...'; $this->doRun($ids); } public function renderDone() { return $this->getDoneText() . sprintf('%s', $this->grid->escape($this->grid->getBackUrl()), ___("Return")); } public function doRun(array $ids) { if ($ids[0] == self::ALL) $this->handleAll(); else { $ds = $this->grid->getDataSource(); foreach ($ids as $id) { $record = $ds->getRecord($id); if (!$record) trigger_error ("Cannot load record [$id]", E_USER_WARNING); $this->handleRecord($id, $record); } echo $this->renderDone(); } $this->log(); } public function _handleAll(& $context, Am_BatchProcessor $batch) { $ds = $this->grid->getDataSource(); list($item, $processed) = explode('-', $context); $done = 0; $totalBefore = $ds->getFoundRows(); $page = ceil($item/$this->batchCount); $currentItem = $page * $this->batchCount; foreach ($ds->selectPageRecords($page, $this->batchCount) as $record) { if ($currentItem >= $item) { $id = $ds->getIdForRecord($record); $this->handleRecord($id, $record); $done++; } $currentItem++; } $ds->selectPageRecords(0, 1); //to clear fornRows cache $totalAfter = $ds->getFoundRows(); $item = $currentItem - $totalBefore + $totalAfter; $processed += $done; $context = implode('-', array($item, $processed)); if ($done == 0) return true; // no more records } public function handleAll() { $batch = new Am_BatchProcessor(array($this, '_handleAll')); $context = $this->grid->getRequest()->getParam('group_context', '0-0'); if ($batch->run($context)) { echo $this->renderDone(); } else { list(,$processed) = explode('-', $context); echo $processed . " " . ___('records processed.'); echo $this->getAutoClickScript(3, 'input#group-action-continue'); echo $this->renderContinueForm(___('Continue'), $context); } } abstract public function handleRecord($id, $record); public function log($message = null, $tablename = null, $record_id = null) { if ($record_id === null) { $ids = $this->getIds(); if (empty($ids)) return; if ($ids[0] == self::ALL) $record_id = 'several records'; else $record_id = implode(',', $ids); } parent::log($message, $tablename, $record_id); } }PKN\THAction/Group/Delete.phpnu[title = ___('Delete'); parent::__construct($id, $title); } public function handleRecord($id, $record) { $args = array($record, $this->grid); $this->grid->runCallback(Am_Grid_Editable::CB_BEFORE_DELETE, $args); $this->grid->getDataSource()->deleteRecord($id, $record); $this->grid->runCallback(Am_Grid_Editable::CB_AFTER_DELETE, $args); } }PKN\$pAction/Url.phpnu[id = $id; $this->title = $title; $this->url = $url; parent::__construct(); } public function getUrl($record = null, $id = null) { $url = str_replace(array('__ID__',), array($id,), $this->url); //backward compatibility $url = preg_replace_callback('#^__ROOT__(.+)#', array($this, '_replaceRootUrl'), $url); return $this->parseTpl($url, $record); } public function _replaceRootUrl($matches) { $s = $matches[1]; if ($s[0] == '/') $s = substr($s, 1); return Am_Di::getInstance()->url($s,null,false); } protected function parseTpl($url, $record) { $this->_record = $record; $ret = preg_replace_callback('|{(.+?)}|', array($this, '_pregReplace'), $url); unset($this->_record); if ((strpos($ret, 'http')!==0) && ($ret[0] != '/') && (strpos($ret, 'javascript')!== 0)) { $ret = Am_Di::getInstance()->url($ret, false); } return $ret; } public function _pregReplace($matches) { $var = $matches[1]; if ($var == 'THIS_URL') { $ret = $this->grid->getDi()->request->getRequestUri(); } elseif (preg_match('|^(.+)\(\)$|', $var, $regs)) { $ret = call_user_func(array($this->_record, $regs[1])); } else { $ret = $this->_record->{$var}; } return urlencode($ret); } public function run() { //nop } } PKN\ĽAction/Callback.phpnu[id = $id; $this->title = $title; $this->callback = $callback; $this->type = $type; parent::__construct(); } public function run() { call_user_func($this->callback, $this, $this->grid); } } PKN\AˢwwAction/Sort/Abstract.phpnu[hasPermissions()) { $grid->addCallback(Am_Grid_ReadOnly::CB_TR_ATTRIBS, array($this, 'getTrAttribs')); $grid->addCallback(Am_Grid_Editable::CB_RENDER_CONTENT, array($this, 'renderContent')); $grid->prependField(new Am_Grid_Field_Sort('_sort')); } } final public function getTrAttribs(array & $attribs, $obj) { $grid_id = $this->grid->getId(); $params = array( $grid_id . '_' . Am_Grid_ReadOnly::ACTION_KEY => $this->getId(), $grid_id . '_' . Am_Grid_ReadOnly::ID_KEY => $this->grid->getDataSource()->getIdForRecord($obj), ); $attribs['data-params'] = json_encode($params); $attribs['data-sort-record'] = json_encode($this->getRecordParams($obj)); } public function renderContent(& $out, Am_Grid_Editable $grid) { $url = json_encode($grid->makeUrl()); $grid_id = $this->grid->getId(); $msg = ___("Drag&Drop rows to change display order. You may want to temporary change setting '%sRecords per Page (for grids)%s' to some big value so all records were on one page and you can arrange all items.", '',''); $out .= <<$msg CUT; } public function run() { $request = $this->grid->getRequest(); $id = $request->getFiltered('id'); $move_before = $request->getParam('move_before', null); $move_after = $request->getParam('move_after', null); $move_item = $request->getParam('move_item'); $resp = array( 'ok' => true, ); if ($this->callback) $resp['callback'] = $this->callback; try { $this->setSortBetween($move_item, $move_after, $move_before); } catch (Exception $e) { throw $e; $resp = array('ok' => false, ); } Am_Di::getInstance()->response->ajaxResponse($resp); exit(); } protected function getRecordParams($obj) { return array( 'id' => $this->grid->getDataSource()->getIdForRecord($obj), ); } abstract protected function setSortBetween($item, $after, $before); } class Am_Grid_Field_Sort extends Am_Grid_Field { public function __construct($field='_', $title=null, $sortable = true, $align = null, $renderFunc = null, $width = null) { parent::__construct($field, '', false); $this->addDecorator(new Am_Grid_Field_Decorator_Sort()); } public function render($obj, $grid) { /* @var $grid Am_Grid_ReadOnly */ return $grid->getRequest()->getParam('sort') ? '' : ' '; } } class Am_Grid_Field_Decorator_Sort extends Am_Grid_Field_Decorator_Abstract { function renderTitle(& $out, $controller) { /* @var $controller Am_Grid_ReadOnly */ $out = $controller->getRequest()->getParam('sort') ? '' : preg_replace('#^(table = $table->getName(true); } protected function getRecordParams($obj) { return array( 'id' => $obj->name, ); } protected function setSortBetween($item, $after, $before) { $after = $after ? $after['id'] : null; $before = $before ? $before['id'] : null; $id = $item['id']; $db = Am_Di::getInstance()->db; $item = $db->selectRow("SELECT * FROM ?_custom_field_sort WHERE custom_field_name=? AND custom_field_table=? ", $id, $this->table); if ($before) { $beforeItem = $db->selectRow("SELECT * FROM ?_custom_field_sort WHERE custom_field_name=? AND custom_field_table=? ", $before, $this->table); $sign = $beforeItem['sort_order'] > $item['sort_order'] ? '-': '+'; $newSortOrder = $beforeItem['sort_order'] > $item['sort_order'] ? $beforeItem['sort_order']-1: $beforeItem['sort_order']; $db->query("UPDATE ?_custom_field_sort SET sort_order=sort_order{$sign}1 WHERE sort_order BETWEEN ? AND ? AND custom_field_name<>? AND custom_field_table=?", min($newSortOrder, $item['sort_order']), max($newSortOrder, $item['sort_order']), $id, $this->table); $db->query("UPDATE ?_custom_field_sort SET sort_order=? WHERE custom_field_name=? AND custom_field_table=?", $newSortOrder, $id, $this->table); } elseif ($after) { $afterItem = $db->selectRow("SELECT * FROM ?_custom_field_sort WHERE custom_field_name=? AND custom_field_table=? ", $after, $this->table); $sign = $afterItem['sort_order'] > $item['sort_order'] ? '-': '+'; $newSortOrder = $afterItem['sort_order'] > $item['sort_order'] ? $afterItem['sort_order']: $afterItem['sort_order']+1; $db->query("UPDATE ?_custom_field_sort SET sort_order=sort_order{$sign}1 WHERE sort_order BETWEEN ? AND ? AND custom_field_name<>? AND custom_field_table=?", min($newSortOrder, $item['sort_order']), max($newSortOrder, $item['sort_order']), $id, $this->table); $db->query("UPDATE ?_custom_field_sort SET sort_order=? WHERE custom_field_name=? AND custom_field_table=?", $newSortOrder, $id, $this->table); } } }PKN\PAction/Edit.phpnu[title = ___("Edit %s"); parent::__construct($id, $title); } public function showFormAfterSave($flag) { $this->showFormAfterSave = (bool)$flag; return $this; } public function run() { if ($this->_runFormAction(Am_Grid_Editable::ACTION_EDIT)) { $this->log(); return $this->showFormAfterSave ? $this->redirectSelf() : $this->grid->redirectBack(); } } }PKN\/x}Action/Total.phpnu[fields[$field->getFieldName()] = $field; $this->stms[$field->getFieldName()] = $stm; return $this; } public function setGrid(Am_Grid_Editable $grid) { $grid->addCallback(Am_Grid_ReadOnly::CB_RENDER_TABLE, array($this, 'renderOut')); /* @var $ds Am_Query */ $this->ds = clone $grid->getDataSource(); parent::setGrid($grid); } public function renderOut(& $out) { $titles = array(); $this->ds->clearFields() ->clearOrder() ->toggleAutoGroupBy(false); foreach ($this->fields as $field) { /* @var $field Am_Grid_Field */ $name = $field->getFieldName(); $stm = $this->stms[$name]; $this->ds ->addField(sprintf("SUM($stm)", $name), '_' . $name); $titles['_' . $name] = $field->getFieldTitle(); } $totals = array(); foreach ($this->grid->getDi()->db->selectRow($this->ds->getSql()) as $key => $val) { $totals[] = sprintf('%s %s: %s', ___('Total'), $titles[$key], Am_Currency::render($val)); } $html = sprintf('
%s
', implode(',', $totals)); $out = preg_replace('|(