public function view() { $params = array('{$today}', '{$current-time}', '{$this-year}', '{$this-month}', '{$this-day}', '{$timezone}', '{$website-name}', '{$page-title}', '{$root}', '{$workspace}', '{$root-page}', '{$current-page}', '{$current-page-id}', '{$current-path}', '{$current-query-string}', '{$current-url}', '{$cookie-username}', '{$cookie-pass}', '{$page-types}', '{$upload-limit}'); // Get page parameters $pages = PageManager::fetch(true, array('params')); foreach ($pages as $key => $pageparams) { if (empty($pageparams['params'])) { continue; } $pageparams = explode('/', $pageparams['params']); foreach ($pageparams as $pageparam) { $param = '{$' . $pageparam . '}'; if (!in_array($param, $params)) { $params[] = $param; } } } // Get Data Sources output parameters $datasources = DatasourceManager::listAll(); foreach ($datasources as $datasource) { $current = DatasourceManager::create($datasource['handle'], array(), false); $prefix = '{$ds-' . Lang::createHandle($datasource['name']) . '.'; $suffix = '}'; // Get parameters if (is_array($current->dsParamPARAMOUTPUT)) { foreach ($current->dsParamPARAMOUTPUT as $id => $param) { $params[] = $prefix . $param . $suffix; } } } sort($params); $this->_Result = json_encode($params); }
public function __buildPageXML($page, $page_types, $qf) { $lang_code = FLang::getLangCode(); $oPage = new XMLElement('page'); $oPage->setAttribute('handle', $page['handle']); $oPage->setAttribute('id', $page['id']); // keep current first $oPage->appendChild(new XMLElement('item', General::sanitize($page['plh_t-' . $lang_code]), array('lang' => $lang_code, 'handle' => $page['plh_h-' . $lang_code]))); // add others foreach (FLang::getLangs() as $lc) { if ($lang_code != $lc) { $oPage->appendChild(new XMLElement('item', General::sanitize($page['plh_t-' . $lc]), array('lang' => $lc, 'handle' => $page['plh_h-' . $lc]))); } } if (in_array($page['id'], array_keys($page_types))) { $xTypes = new XMLElement('types'); foreach ($page_types[$page['id']] as $type) { $xTypes->appendChild(new XMLElement('type', $type)); } $oPage->appendChild($xTypes); } if ($page['children'] != '0') { if ($children = PageManager::fetch(false, array($qf . 'id, handle, title'), array(sprintf('`parent` = %d', $page['id'])))) { foreach ($children as $c) { $oPage->appendChild($this->__buildPageXML($c, $page_types, $qf)); } } } return $oPage; }
public function grab(&$param_pool = null) { $result = new XMLElement('plh-page'); $langs = FLang::getLangs(); $fields = array('id', 'handle', 'parent'); foreach ($langs as $lc) { $fields[] = "`plh_t-{$lc}`"; $fields[] = "`plh_h-{$lc}`"; } $pages = array(); foreach (PageManager::fetch(null, $fields) as $page) { $pages[$page['id']] = $page; } $this->appendPage($pages, $this->_env['param']['current-page-id'], $langs, $result); return $result; }
private function __getPageParams() { $params = array(); $pages = PageManager::fetch(true, array('params')); foreach ($pages as $key => $pageparams) { if (empty($pageparams['params'])) { continue; } $pageparams = explode('/', $pageparams['params']); foreach ($pageparams as $pageparam) { $param = sprintf($this->template, $pageparam); if (!in_array($param, $params)) { $params[] = $param; } } } return $params; }
public function __buildPageXML($page, $page_types) { $oPage = new XMLElement('page'); $oPage->setAttribute('handle', $page['handle']); $oPage->setAttribute('id', $page['id']); $oPage->appendChild(new XMLElement('name', General::sanitize($page['title']))); if (in_array($page['id'], array_keys($page_types))) { $xTypes = new XMLElement('types'); foreach ($page_types[$page['id']] as $type) { $xTypes->appendChild(new XMLElement('type', $type)); } $oPage->appendChild($xTypes); } if ($page['children'] != '0') { if ($children = PageManager::fetch(false, array('id, handle, title'), array(sprintf('`parent` = %d', $page['id'])))) { foreach ($children as $c) { $oPage->appendChild($this->__buildPageXML($c, $page_types)); } } } return $oPage; }
private function buildTree($parent = null, $indent = 0) { if ($parent == null) { $results = PageManager::fetch(true, array(), array('`parent` IS NULL'), '`sortorder` ASC'); } else { $results = PageManager::fetch(true, array(), array('`parent` = ' . $parent), '`sortorder` ASC'); } $tree = array(); foreach ($results as $result) { // Check if the page should be shown: if (!in_array('ck_hide', $result['type'])) { $prefix = ''; $info = array('handle' => $result['handle'], 'path' => $result['path']); if ($result['path'] == null) { $info['url'] = '/' . $result['handle'] . '/'; $info['title'] = $result['title']; } else { $info['url'] = '/' . $result['path'] . '/' . $result['handle'] . '/'; for ($i = 0; $i < $indent; $i++) { $prefix .= ' '; // Please note: this might look like an empty space (nbsp) but it's an em space (emsp). // This was necessary because kept showing as plain text in the dropdown. } $info['title'] = $prefix . ' › ' . General::sanitize($result['title']); } $tree[] = $info; // Check if there are templates for this page: $tree = array_merge($tree, $this->checkTemplates($result['id'], $prefix . ' ')); // also an emsp // Get the children: $children = $this->buildTree($result['id'], $indent + 1); // Join arrays: $tree = array_merge($tree, $children); } } return $tree; }
/** * Append presets * @param $context */ public function appendPresets($context) { Symphony::Engine()->Page->addScriptToHead(URL . '/extensions/ckeditor/assets/preferences.js', 4676); $wrapper = $context['wrapper']; $fieldset = new XMLElement('fieldset', '', array('class' => 'settings')); $fieldset->appendChild(new XMLElement('legend', __('CKEditor File Browser'))); $sectionManager = new SectionManager($this); $sections = $sectionManager->fetch(); // Check which sections are allowed: $data = Symphony::Configuration()->get('sections', 'ckeditor'); $checkedSections = $data != false ? explode(',', $data) : array(); // If there are no sections found: if ($sections) { $options = array(); foreach ($sections as $section) { $options[] = array($section->get('id'), in_array($section->get('id'), $checkedSections), $section->get('name')); } $label = Widget::Label(__('Permitted sections for the file browser:')); $label->appendChild(Widget::Select('ckeditor_sections[]', $options, array('multiple' => 'multiple'))); $fieldset->appendChild($label); } // Link templates for CKEditor: $sections = SectionManager::fetch(); $dbpages = PageManager::fetch(); $pages = array(); // Filter out the ck_hide: foreach ($dbpages as $page) { $types = PageManager::fetchPageTypes($page['id']); if (!in_array('ck_hide', $types)) { $pages[] = $page; } } // Adjust page title: foreach ($pages as &$_page) { $p = $_page; $title = $_page['title']; while (!is_null($p['parent'])) { $p = PageManager::fetch(false, array(), array('id' => $p['parent'])); $title = $p['title'] . ' : ' . $title; } $_page['title'] = $title; } // Sort the array: $titles = array(); foreach ($pages as $key => $row) { $titles[$key] = strtolower($row['title']); } array_multisort($titles, SORT_ASC, $pages); $this->sections = array(); foreach ($sections as $s) { $a = array('id' => $s->get('id'), 'name' => $s->get('name'), 'fields' => array()); $fields = FieldManager::fetch(null, $s->get('id')); foreach ($fields as $field) { // For now, only allow fields of the type 'input' to be used as a handle: if ($field->get('type') == 'input') { $a['fields'][] = array('id' => $field->get('id'), 'label' => $field->get('label'), 'element_name' => $field->get('element_name')); } } $this->sections[] = $a; } $fieldset->appendChild(new XMLElement('p', __('Link templates:'), array('class' => 'label'))); $ol = new XMLElement('ol'); $ol->setAttribute('class', 'ckeditor-duplicator'); $templates = Symphony::Database()->fetch('SELECT * FROM `tbl_ckeditor_link_templates`;'); if (!is_array($pages)) { $pages = array($pages); } foreach ($pages as $page) { foreach ($templates as $template) { if ($template['page_id'] != $page['id']) { continue; } $duplicator = $this->__buildDuplicatorItem($page, $template); $ol->appendChild($duplicator); } $duplicator = $this->__buildDuplicatorItem($page, NULL); $ol->appendChild($duplicator); } $fieldset->appendChild($ol); // Plugin presets: $fieldset->appendChild(new XMLElement('p', __('Plugin presets:'), array('class' => 'label'))); $ol = new XMLElement('ol'); $ol->setAttribute('class', 'ckeditor-duplicator'); // Create template: $template = new XMLElement('li', null, array('class' => 'template')); $template->appendChild(new XMLElement('header', '<h3>' . __('New Preset') . '</h3>')); $template->appendChild(Widget::Label(__('Name'), Widget::Input('ckeditor_presets[-1][name]'))); $template->appendChild(Widget::Label(__('Toolbar'), Widget::Textarea('ckeditor_presets[-1][toolbar]', 5, 50))); $template->appendChild(Widget::Label(__('Plugins'), Widget::Textarea('ckeditor_presets[-1][plugins]', 5, 50))); $template->appendChild(Widget::Label(__('%s Enable resizing', array(Widget::Input('ckeditor_presets[-1][resize]', 'yes', 'checkbox')->generate())))); $template->appendChild(Widget::Label(__('%s Show outline blocks', array(Widget::Input('ckeditor_presets[-1][outline]', 'yes', 'checkbox')->generate())))); $ol->appendChild($template); // Append all the fields: $presets = Symphony::Database()->fetch('SELECT * FROM `tbl_ckeditor_presets'); $index = 0; foreach ($presets as $preset) { $template = new XMLElement('li'); $template->appendChild(new XMLElement('header', '<h3>' . $preset['name'] . '</h3>')); $template->appendChild(Widget::Label(__('Name'), Widget::Input('ckeditor_presets[' . $index . '][name]', $preset['name']))); $template->appendChild(Widget::Label(__('Toolbar'), Widget::Textarea('ckeditor_presets[' . $index . '][toolbar]', 5, 50, $preset['toolbar']))); $template->appendChild(Widget::Label(__('Plugins'), Widget::Textarea('ckeditor_presets[' . $index . '][plugins]', 5, 50, $preset['plugins']))); $template->appendChild(Widget::Label(__('%s Enable resizing', array(Widget::Input('ckeditor_presets[' . $index . '][resize]', '1', 'checkbox', $preset['resize'] == 1 ? array('checked' => 'checked') : null)->generate())))); $template->appendChild(Widget::Label(__('%s Show outline blocks', array(Widget::Input('ckeditor_presets[' . $index . '][outline]', '1', 'checkbox', $preset['outline'] == 1 ? array('checked' => 'checked') : null)->generate())))); $ol->appendChild($template); $index++; } $fieldset->appendChild($ol); // Styles: $fieldset->appendChild(new XMLElement('p', __('Styles: (one style per line: <code>h3.example { color: #f00; background: #0f0; }</code>) Class name is converted to name (h3.hello-world = Hello World).'), array('class' => 'label'))); $textarea = Widget::Textarea('ckeditor[styles]', 5, 50, Symphony::Configuration()->get('styles', 'ckeditor')); $fieldset->appendChild($textarea); $wrapper->appendChild($fieldset); }
public function __formAction() { $fields = $_POST['fields']; $this->_errors = array(); $providers = Symphony::ExtensionManager()->getProvidersOf(iProvider::EVENT); $providerClass = null; if (trim($fields['name']) == '') { $this->_errors['name'] = __('This is a required field'); } if (trim($fields['source']) == '') { $this->_errors['source'] = __('This is a required field'); } $filters = isset($fields['filters']) ? $fields['filters'] : array(); // See if a Provided Datasource is saved if (!empty($providers)) { foreach ($providers as $providerClass => $provider) { if ($fields['source'] == call_user_func(array($providerClass, 'getSource'))) { call_user_func_array(array($providerClass, 'validate'), array(&$fields, &$this->_errors)); break; } unset($providerClass); } } $classname = Lang::createHandle($fields['name'], 255, '_', false, true, array('@^[^a-z\\d]+@i' => '', '/[^\\w-\\.]/i' => '')); $rootelement = str_replace('_', '-', $classname); $extends = 'SectionEvent'; // Check to make sure the classname is not empty after handlisation. if (empty($classname) && !isset($this->_errors['name'])) { $this->_errors['name'] = __('Please ensure name contains at least one Latin-based character.', array($classname)); } $file = EVENTS . '/event.' . $classname . '.php'; $isDuplicate = false; $queueForDeletion = null; if ($this->_context[0] == 'new' && is_file($file)) { $isDuplicate = true; } elseif ($this->_context[0] == 'edit') { $existing_handle = $this->_context[1]; if ($classname != $existing_handle && is_file($file)) { $isDuplicate = true; } elseif ($classname != $existing_handle) { $queueForDeletion = EVENTS . '/event.' . $existing_handle . '.php'; } } // Duplicate if ($isDuplicate) { $this->_errors['name'] = __('An Event with the name %s already exists', array('<code>' . $classname . '</code>')); } if (empty($this->_errors)) { $multiple = in_array('expect-multiple', $filters); $elements = null; $placeholder = '<!-- GRAB -->'; $source = $fields['source']; $params = array('rootelement' => $rootelement); $about = array('name' => $fields['name'], 'version' => 'Symphony ' . Symphony::Configuration()->get('version', 'symphony'), 'release date' => DateTimeObj::getGMT('c'), 'author name' => Symphony::Author()->getFullName(), 'author website' => URL, 'author email' => Symphony::Author()->get('email')); // If there is a provider, get their template if ($providerClass) { $eventShell = file_get_contents(call_user_func(array($providerClass, 'getTemplate'))); } else { $eventShell = file_get_contents($this->getTemplate('blueprints.event')); $about['trigger condition'] = $rootelement; } $this->__injectAboutInformation($eventShell, $about); // Replace the name $eventShell = str_replace('<!-- CLASS NAME -->', $classname, $eventShell); // Build the templates if ($providerClass) { $eventShell = call_user_func(array($providerClass, 'prepare'), $fields, $params, $eventShell); } else { $this->__injectFilters($eventShell, $filters); // Add Documentation require_once CONTENT . '/content.ajaxeventdocumentation.php'; $ajaxEventDoc = new contentAjaxEventDocumentation(); $documentation = null; $doc_parts = array(); // Add Documentation (Success/Failure) $ajaxEventDoc->addEntrySuccessDoc($doc_parts, $rootelement, $fields['source'], $filters); $ajaxEventDoc->addEntryFailureDoc($doc_parts, $rootelement, $fields['source'], $filters); // Filters $ajaxEventDoc->addDefaultFiltersDoc($doc_parts, $rootelement, $fields['source'], $filters); // Frontend Markup $ajaxEventDoc->addFrontendMarkupDoc($doc_parts, $rootelement, $fields['source'], $filters); $ajaxEventDoc->addSendMailFilterDoc($doc_parts, $rootelement, $fields['source'], $filters); /** * Allows adding documentation for new filters. A reference to the $documentation * array is provided, along with selected filters * @delegate AppendEventFilterDocumentation * @param string $context * '/blueprints/events/(edit|new|info)/' * @param array $selected * An array of all the selected filters for this Event * @param array $documentation * An array of all the documentation XMLElements, passed by reference */ Symphony::ExtensionManager()->notifyMembers('AppendEventFilterDocumentation', '/blueprints/events/' . $rootelement . '/', array('selected' => $filters, 'documentation' => &$doc_parts)); $documentation = join(PHP_EOL, array_map(create_function('$x', 'return rtrim($x->generate(true, 4));'), $doc_parts)); $documentation = str_replace('\'', '\\\'', $documentation); $eventShell = str_replace('<!-- CLASS EXTENDS -->', $extends, $eventShell); $eventShell = str_replace('<!-- DOCUMENTATION -->', General::tabsToSpaces($documentation, 4), $eventShell); } $eventShell = str_replace('<!-- ROOT ELEMENT -->', $rootelement, $eventShell); $eventShell = str_replace('<!-- CLASS NAME -->', $classname, $eventShell); $eventShell = str_replace('<!-- SOURCE -->', $source, $eventShell); // Remove left over placeholders $eventShell = preg_replace(array('/<!--[\\w ]++-->/'), '', $eventShell); if ($this->_context[0] == 'new') { /** * Prior to creating an Event, the file path where it will be written to * is provided and well as the contents of that file. * * @delegate EventsPreCreate * @since Symphony 2.2 * @param string $context * '/blueprints/events/' * @param string $file * The path to the Event file * @param string $contents * The contents for this Event as a string passed by reference * @param array $filters * An array of the filters attached to this event */ Symphony::ExtensionManager()->notifyMembers('EventPreCreate', '/blueprints/events/', array('file' => $file, 'contents' => &$eventShell, 'filters' => $filters)); } else { /** * Prior to editing an Event, the file path where it will be written to * is provided and well as the contents of that file. * * @delegate EventPreEdit * @since Symphony 2.2 * @param string $context * '/blueprints/events/' * @param string $file * The path to the Event file * @param string $contents * The contents for this Event as a string passed by reference * @param array $filters * An array of the filters attached to this event */ Symphony::ExtensionManager()->notifyMembers('EventPreEdit', '/blueprints/events/', array('file' => $file, 'contents' => &$eventShell, 'filters' => $filters)); } // Write the file if (!is_writable(dirname($file)) || !($write = General::writeFile($file, $eventShell, Symphony::Configuration()->get('write_mode', 'file')))) { $this->pageAlert(__('Failed to write Event to disk.') . ' ' . __('Please check permissions on %s.', array('<code>/workspace/events</code>')), Alert::ERROR); // Write successful } else { if (function_exists('opcache_invalidate')) { opcache_invalidate($file, true); } // Attach this event to pages $connections = $fields['connections']; ResourceManager::setPages(RESOURCE_TYPE_EVENT, is_null($existing_handle) ? $classname : $existing_handle, $connections); if ($queueForDeletion) { General::deleteFile($queueForDeletion); $pages = PageManager::fetch(false, array('events', 'id'), array("\n `events` REGEXP '[[:<:]]" . $existing_handle . "[[:>:]]'\n ")); if (is_array($pages) && !empty($pages)) { foreach ($pages as $page) { $page['events'] = preg_replace('/\\b' . $existing_handle . '\\b/i', $classname, $page['events']); PageManager::edit($page['id'], $page); } } } if ($this->_context[0] == 'new') { /** * After creating the Event, the path to the Event file is provided * * @delegate EventPostCreate * @since Symphony 2.2 * @param string $context * '/blueprints/events/' * @param string $file * The path to the Event file */ Symphony::ExtensionManager()->notifyMembers('EventPostCreate', '/blueprints/events/', array('file' => $file)); } else { /** * After editing the Event, the path to the Event file is provided * * @delegate EventPostEdit * @since Symphony 2.2 * @param string $context * '/blueprints/events/' * @param string $file * The path to the Event file * @param string $previous_file * The path of the previous Event file in the case where an Event may * have been renamed. To get the handle from this value, see * `EventManager::__getHandleFromFilename` */ Symphony::ExtensionManager()->notifyMembers('EventPostEdit', '/blueprints/events/', array('file' => $file, 'previous_file' => $queueForDeletion ? $queueForDeletion : null)); } redirect(SYMPHONY_URL . '/blueprints/events/edit/' . $classname . '/' . ($this->_context[0] == 'new' ? 'created' : 'saved') . '/'); } } }
/** * Given a resource type, a handle and a page, this function detaches * the given handle (which represents either a datasource or event) to that page. * * @param integer $type * The resource type, either `RESOURCE_TYPE_EVENT` or `RESOURCE_TYPE_DS` * @param string $r_handle * The handle of the resource. * @param integer $page_id * The ID of the page. */ public static function detach($type, $r_handle, $page_id) { $col = self::getColumnFromType($type); $pages = PageManager::fetch(false, array($col), array(sprintf('`id` = %d', $page_id))); if (is_array($pages) && count($pages) == 1) { $result = $pages[0][$col]; $values = explode(',', $result); $idx = array_search($r_handle, $values, false); if ($idx !== false) { array_splice($values, $idx, 1); $result = implode(',', $values); return PageManager::edit($page_id, array($col => MySQL::cleanValue($result))); } } return false; }
/** * Append presets * @param $context */ public function appendPresets($context) { Symphony::Engine()->Page->addScriptToHead(URL . '/extensions/ckeditor/assets/preferences.js', 4676); $wrapper = $context['wrapper']; $fieldset = new XMLElement('fieldset', '', array('class' => 'settings')); $fieldset->appendChild(new XMLElement('legend', __('CKEditor File Browser'))); $sectionManager = new SectionManager($this); $sections = $sectionManager->fetch(); // Check which sections are allowed: $data = Symphony::Configuration()->get('sections', 'ckeditor'); $checkedSections = $data != false ? explode(',', $data) : array(); // If there are no sections found: if ($sections) { $options = array(); foreach ($sections as $section) { $options[] = array($section->get('id'), in_array($section->get('id'), $checkedSections), $section->get('name')); } $label = Widget::Label(__('Permitted sections for the file browser:')); $label->appendChild(Widget::Select('ckeditor_sections[]', $options, array('multiple' => 'multiple'))); $fieldset->appendChild($label); } // Link templates for CKEditor: $sections = SectionManager::fetch(); $dbpages = PageManager::fetch(); $pages = array(); // Filter out the ck_hide: foreach ($dbpages as $page) { $types = PageManager::fetchPageTypes($page['id']); if (!in_array('ck_hide', $types)) { $pages[] = $page; } } // Adjust page title: foreach ($pages as &$_page) { $p = $_page; $title = $_page['title']; while (!is_null($p['parent'])) { $p = PageManager::fetch(false, array(), array('id' => $p['parent'])); $title = $p['title'] . ' : ' . $title; } $_page['title'] = $title; } // Sort the array: $titles = array(); foreach ($pages as $key => $row) { $titles[$key] = strtolower($row['title']); } array_multisort($titles, SORT_ASC, $pages); $this->sections = array(); foreach ($sections as $s) { $a = array('id' => $s->get('id'), 'name' => $s->get('name'), 'fields' => array()); $fields = FieldManager::fetch(null, $s->get('id')); foreach ($fields as $field) { // For now, only allow fields of the type 'input' to be used as a handle: if ($field->get('type') == 'input') { $a['fields'][] = array('id' => $field->get('id'), 'label' => $field->get('label'), 'element_name' => $field->get('element_name')); } } $this->sections[] = $a; } $fieldset->appendChild(new XMLElement('p', __('Link templates:'), array('class' => 'label'))); $ol = new XMLElement('ol'); $ol->setAttribute('class', 'ckeditor-duplicator'); $templates = Symphony::Database()->fetch('SELECT * FROM `tbl_ckeditor_link_templates`;'); if (!is_array($pages)) { $pages = array($pages); } foreach ($pages as $page) { foreach ($templates as $template) { if ($template['page_id'] != $page['id']) { continue; } $duplicator = $this->__buildDuplicatorItem($page, $template); $ol->appendChild($duplicator); } $duplicator = $this->__buildDuplicatorItem($page, NULL); $ol->appendChild($duplicator); } $fieldset->appendChild($ol); $wrapper->appendChild($fieldset); }
public function __formAction() { $fields = $_POST['fields']; $this->_errors = array(); $providers = Symphony::ExtensionManager()->getProvidersOf(iProvider::DATASOURCE); $providerClass = null; if (trim($fields['name']) == '') { $this->_errors['name'] = __('This is a required field'); } if ($fields['source'] == 'static_xml') { if (trim($fields['static_xml']) == '') { $this->_errors['static_xml'] = __('This is a required field'); } else { $xml_errors = null; include_once TOOLKIT . '/class.xsltprocess.php'; General::validateXML($fields['static_xml'], $xml_errors, false, new XsltProcess()); if (!empty($xml_errors)) { $this->_errors['static_xml'] = __('XML is invalid.'); } } } elseif (is_numeric($fields['source'])) { if (strlen(trim($fields['max_records'])) == 0 || is_numeric($fields['max_records']) && $fields['max_records'] < 1) { if ($fields['paginate_results'] === 'yes') { $this->_errors['max_records'] = __('A result limit must be set'); } } elseif (!self::__isValidPageString($fields['max_records'])) { $this->_errors['max_records'] = __('Must be a valid number or parameter'); } if (strlen(trim($fields['page_number'])) == 0 || is_numeric($fields['page_number']) && $fields['page_number'] < 1) { if ($fields['paginate_results'] === 'yes') { $this->_errors['page_number'] = __('A page number must be set'); } } elseif (!self::__isValidPageString($fields['page_number'])) { $this->_errors['page_number'] = __('Must be a valid number or parameter'); } // See if a Provided Datasource is saved } elseif (!empty($providers)) { foreach ($providers as $providerClass => $provider) { if ($fields['source'] == call_user_func(array($providerClass, 'getSource'))) { call_user_func_array(array($providerClass, 'validate'), array(&$fields, &$this->_errors)); break; } unset($providerClass); } } $classname = Lang::createHandle($fields['name'], 255, '_', false, true, array('@^[^a-z\\d]+@i' => '', '/[^\\w-\\.]/i' => '')); $rootelement = str_replace('_', '-', $classname); // Check to make sure the classname is not empty after handlisation. if (empty($classname) && !isset($this->_errors['name'])) { $this->_errors['name'] = __('Please ensure name contains at least one Latin-based character.', array($classname)); } $file = DATASOURCES . '/data.' . $classname . '.php'; $isDuplicate = false; $queueForDeletion = null; if ($this->_context[0] == 'new' && is_file($file)) { $isDuplicate = true; } elseif ($this->_context[0] == 'edit') { $existing_handle = $this->_context[1]; if ($classname != $existing_handle && is_file($file)) { $isDuplicate = true; } elseif ($classname != $existing_handle) { $queueForDeletion = DATASOURCES . '/data.' . $existing_handle . '.php'; } } // Duplicate if ($isDuplicate) { $this->_errors['name'] = __('A Data source with the name %s already exists', array('<code>' . $classname . '</code>')); } if (empty($this->_errors)) { $filters = array(); $elements = null; $source = $fields['source']; $params = array('rootelement' => $rootelement); $about = array('name' => $fields['name'], 'version' => 'Symphony ' . Symphony::Configuration()->get('version', 'symphony'), 'release date' => DateTimeObj::getGMT('c'), 'author name' => Symphony::Author()->getFullName(), 'author website' => URL, 'author email' => Symphony::Author()->get('email')); // If there is a provider, get their template if ($providerClass) { $dsShell = file_get_contents(call_user_func(array($providerClass, 'getTemplate'))); } else { $dsShell = file_get_contents($this->getTemplate('blueprints.datasource')); } // Author metadata self::injectAboutInformation($dsShell, $about); // Do dependencies, the template file must have <!-- CLASS NAME --> $dsShell = str_replace('<!-- CLASS NAME -->', $classname, $dsShell); // If there is a provider, let them do the prepartion work if ($providerClass) { $dsShell = call_user_func(array($providerClass, 'prepare'), $fields, $params, $dsShell); } else { switch ($source) { case 'authors': $extends = 'AuthorDatasource'; if (isset($fields['filter']['author'])) { $filters = $fields['filter']['author']; } $elements = $fields['xml_elements']; $params['order'] = $fields['order']; $params['redirectonempty'] = $fields['redirect_on_empty']; $params['redirectonforbidden'] = $fields['redirect_on_forbidden']; $params['redirectonrequired'] = $fields['redirect_on_required']; $params['requiredparam'] = trim($fields['required_url_param']); $params['negateparam'] = trim($fields['negate_url_param']); $params['paramoutput'] = $fields['param']; $params['sort'] = $fields['sort']; break; case 'navigation': $extends = 'NavigationDatasource'; if (isset($fields['filter']['navigation'])) { $filters = $fields['filter']['navigation']; } $params['order'] = $fields['order']; $params['redirectonempty'] = $fields['redirect_on_empty']; $params['redirectonforbidden'] = $fields['redirect_on_forbidden']; $params['redirectonrequired'] = $fields['redirect_on_required']; $params['requiredparam'] = trim($fields['required_url_param']); $params['negateparam'] = trim($fields['negate_url_param']); break; case 'static_xml': $extends = 'StaticXMLDatasource'; $fields['static_xml'] = trim($fields['static_xml']); if (preg_match('/^<\\?xml/i', $fields['static_xml']) == true) { // Need to remove any XML declaration $fields['static_xml'] = preg_replace('/^<\\?xml[^>]+>/i', null, $fields['static_xml']); } $params['static'] = sprintf('%s', trim($fields['static_xml'])); break; default: $extends = 'SectionDatasource'; $elements = $fields['xml_elements']; if (is_array($fields['filter']) && !empty($fields['filter'])) { $filters = array(); foreach ($fields['filter'] as $f) { foreach ($f as $key => $val) { $filters[$key] = $val; } } } $params['order'] = $fields['order']; $params['group'] = $fields['group']; $params['paginateresults'] = $fields['paginate_results']; $params['limit'] = $fields['max_records']; $params['startpage'] = $fields['page_number']; $params['redirectonempty'] = $fields['redirect_on_empty']; $params['redirectonforbidden'] = $fields['redirect_on_forbidden']; $params['redirectonrequired'] = $fields['redirect_on_required']; $params['requiredparam'] = trim($fields['required_url_param']); $params['negateparam'] = trim($fields['negate_url_param']); $params['paramoutput'] = $fields['param']; $params['sort'] = $fields['sort']; $params['htmlencode'] = $fields['html_encode']; $params['associatedentrycounts'] = $fields['associated_entry_counts']; break; } $this->__injectVarList($dsShell, $params); $this->__injectIncludedElements($dsShell, $elements); self::injectFilters($dsShell, $filters); if (preg_match_all('@(\\$ds-[0-9a-z_\\.\\-]+)@i', $dsShell, $matches)) { $dependencies = General::array_remove_duplicates($matches[1]); $dsShell = str_replace('<!-- DS DEPENDENCY LIST -->', "'" . implode("', '", $dependencies) . "'", $dsShell); } $dsShell = str_replace('<!-- CLASS EXTENDS -->', $extends, $dsShell); $dsShell = str_replace('<!-- SOURCE -->', $source, $dsShell); } if ($this->_context[0] == 'new') { /** * Prior to creating the Datasource, the file path where it will be written to * is provided and well as the contents of that file. * * @delegate DatasourcePreCreate * @since Symphony 2.2 * @param string $context * '/blueprints/datasources/' * @param string $file * The path to the Datasource file * @param string $contents * The contents for this Datasource as a string passed by reference * @param array $params * An array of all the `$dsParam*` values * @param array $elements * An array of all the elements included in this datasource * @param array $filters * An associative array of all the filters for this datasource with the key * being the `field_id` and the value the filter. * @param array $dependencies * An array of dependencies that this datasource has */ Symphony::ExtensionManager()->notifyMembers('DatasourcePreCreate', '/blueprints/datasources/', array('file' => $file, 'contents' => &$dsShell, 'params' => $params, 'elements' => $elements, 'filters' => $filters, 'dependencies' => $dependencies)); } else { /** * Prior to editing a Datasource, the file path where it will be written to * is provided and well as the contents of that file. * * @delegate DatasourcePreEdit * @since Symphony 2.2 * @param string $context * '/blueprints/datasources/' * @param string $file * The path to the Datasource file * @param string $contents * The contents for this Datasource as a string passed by reference * @param array $dependencies * An array of dependencies that this datasource has * @param array $params * An array of all the `$dsParam*` values * @param array $elements * An array of all the elements included in this datasource * @param array $filters * An associative array of all the filters for this datasource with the key * being the `field_id` and the value the filter. */ Symphony::ExtensionManager()->notifyMembers('DatasourcePreEdit', '/blueprints/datasources/', array('file' => $file, 'contents' => &$dsShell, 'dependencies' => $dependencies, 'params' => $params, 'elements' => $elements, 'filters' => $filters)); } // Remove left over placeholders $dsShell = preg_replace(array('/<!--[\\w ]++-->/', '/(\\t+[\\r\\n]){2,}/', '/(\\r\\n){2,}/'), '$1', $dsShell); // Write the file if (!is_writable(dirname($file)) || !General::writeFile($file, $dsShell, Symphony::Configuration()->get('write_mode', 'file'), 'w', true)) { $this->pageAlert(__('Failed to write Data source to disk.') . ' ' . __('Please check permissions on %s.', array('<code>/workspace/data-sources</code>')), Alert::ERROR); // Write successful } else { if (function_exists('opcache_invalidate')) { opcache_invalidate($file, true); } // Attach this datasources to pages $connections = $fields['connections']; ResourceManager::setPages(ResourceManager::RESOURCE_TYPE_DS, is_null($existing_handle) ? $classname : $existing_handle, $connections); // If the datasource has been updated and the name changed, then adjust all the existing pages that have the old datasource name if ($queueForDeletion) { General::deleteFile($queueForDeletion); // Update pages that use this DS $pages = PageManager::fetch(false, array('data_sources', 'id'), array("\n `data_sources` REGEXP '[[:<:]]" . $existing_handle . "[[:>:]]'\n ")); if (is_array($pages) && !empty($pages)) { foreach ($pages as $page) { $page['data_sources'] = preg_replace('/\\b' . $existing_handle . '\\b/i', $classname, $page['data_sources']); PageManager::edit($page['id'], $page); } } } if ($this->_context[0] == 'new') { /** * After creating the Datasource, the path to the Datasource file is provided * * @delegate DatasourcePostCreate * @since Symphony 2.2 * @param string $context * '/blueprints/datasources/' * @param string $file * The path to the Datasource file */ Symphony::ExtensionManager()->notifyMembers('DatasourcePostCreate', '/blueprints/datasources/', array('file' => $file)); } else { /** * After editing the Datasource, the path to the Datasource file is provided * * @delegate DatasourcePostEdit * @since Symphony 2.2 * @param string $context * '/blueprints/datasources/' * @param string $file * The path to the Datasource file * @param string $previous_file * The path of the previous Datasource file in the case where a Datasource may * have been renamed. To get the handle from this value, see * `DatasourceManager::__getHandleFromFilename` */ Symphony::ExtensionManager()->notifyMembers('DatasourcePostEdit', '/blueprints/datasources/', array('file' => $file, 'previous_file' => $queueForDeletion ? $queueForDeletion : null)); } redirect(SYMPHONY_URL . '/blueprints/datasources/edit/' . $classname . '/' . ($this->_context[0] == 'new' ? 'created' : 'saved') . '/'); } } }
public function __actionEdit() { if ($this->_context[0] != 'new' && !($page_id = (int) $this->_context[1])) { redirect(SYMPHONY_URL . '/blueprints/pages/'); } $parent_link_suffix = NULL; if (isset($_REQUEST['parent']) && is_numeric($_REQUEST['parent'])) { $parent_link_suffix = '?parent=' . $_REQUEST['parent']; } if (@array_key_exists('delete', $_POST['action'])) { $this->__actionDelete($page_id, SYMPHONY_URL . '/blueprints/pages/' . $parent_link_suffix); } if (@array_key_exists('save', $_POST['action'])) { $fields = $_POST['fields']; $this->_errors = array(); $autogenerated_handle = false; if (!isset($fields['title']) || trim($fields['title']) == '') { $this->_errors['title'] = __('This is a required field'); } if (trim($fields['type']) != '' && preg_match('/(index|404|403)/i', $fields['type'])) { $types = preg_split('/\\s*,\\s*/', strtolower($fields['type']), -1, PREG_SPLIT_NO_EMPTY); if (in_array('index', $types) && PageManager::hasPageTypeBeenUsed($page_id, 'index')) { $this->_errors['type'] = __('An index type page already exists.'); } elseif (in_array('404', $types) && PageManager::hasPageTypeBeenUsed($page_id, '404')) { $this->_errors['type'] = __('A 404 type page already exists.'); } elseif (in_array('403', $types) && PageManager::hasPageTypeBeenUsed($page_id, '403')) { $this->_errors['type'] = __('A 403 type page already exists.'); } } if (trim($fields['handle']) == '') { $fields['handle'] = $fields['title']; $autogenerated_handle = true; } $fields['handle'] = PageManager::createHandle($fields['handle']); if (empty($fields['handle']) && !isset($this->_errors['title'])) { $this->_errors['handle'] = __('Please ensure handle contains at least one Latin-based character.'); } /** * Just after the Symphony validation has run, allows Developers * to run custom validation logic on a Page * * @delegate PagePostValidate * @since Symphony 2.2 * @param string $context * '/blueprints/pages/' * @param array $fields * The `$_POST['fields']` array. This should be read-only and not changed * through this delegate. * @param array $errors * An associative array of errors, with the key matching a key in the * `$fields` array, and the value being the string of the error. `$errors` * is passed by reference. */ Symphony::ExtensionManager()->notifyMembers('PagePostValidate', '/blueprints/pages/', array('fields' => $fields, 'errors' => &$errors)); if (empty($this->_errors)) { $autogenerated_handle = false; if ($fields['params']) { $fields['params'] = trim(preg_replace('@\\/{2,}@', '/', $fields['params']), '/'); } // Clean up type list $types = preg_split('/\\s*,\\s*/', $fields['type'], -1, PREG_SPLIT_NO_EMPTY); $types = @array_map('trim', $types); unset($fields['type']); $fields['parent'] = $fields['parent'] != __('None') ? $fields['parent'] : null; $fields['data_sources'] = is_array($fields['data_sources']) ? implode(',', $fields['data_sources']) : NULL; $fields['events'] = is_array($fields['events']) ? implode(',', $fields['events']) : NULL; $fields['path'] = null; if ($fields['parent']) { $fields['path'] = PageManager::resolvePagePath((int) $fields['parent']); } // Check for duplicates: $current = PageManager::fetchPageByID($page_id); if (empty($current)) { $fields['sortorder'] = PageManager::fetchNextSortOrder(); } $where = array(); if (!empty($current)) { $where[] = "p.id != {$page_id}"; } $where[] = "p.handle = '" . $fields['handle'] . "'"; $where[] = is_null($fields['path']) ? "p.path IS NULL" : "p.path = '" . $fields['path'] . "'"; $duplicate = PageManager::fetch(false, array('*'), $where); // If duplicate if (!empty($duplicate)) { if ($autogenerated_handle) { $this->_errors['title'] = __('A page with that title already exists'); } else { $this->_errors['handle'] = __('A page with that handle already exists'); } } else { // New page? if (empty($current)) { $file_created = PageManager::createPageFiles($fields['path'], $fields['handle']); } else { $file_created = PageManager::createPageFiles($fields['path'], $fields['handle'], $current['path'], $current['handle']); } // If the file wasn't created, it's usually permissions related if (!$file_created) { $redirect = null; return $this->pageAlert(__('Page Template could not be written to disk.') . ' ' . __('Please check permissions on %s.', array('<code>/workspace/pages</code>')), Alert::ERROR); } // Insert the new data: if (empty($current)) { /** * Just prior to creating a new Page record in `tbl_pages`, provided * with the `$fields` associative array. Use with caution, as no * duplicate page checks are run after this delegate has fired * * @delegate PagePreCreate * @since Symphony 2.2 * @param string $context * '/blueprints/pages/' * @param array $fields * The `$_POST['fields']` array passed by reference */ Symphony::ExtensionManager()->notifyMembers('PagePreCreate', '/blueprints/pages/', array('fields' => &$fields)); if (!($page_id = PageManager::add($fields))) { $this->pageAlert(__('Unknown errors occurred while attempting to save.') . '<a href="' . SYMPHONY_URL . '/system/log/">' . __('Check your activity log') . '</a>.', Alert::ERROR); } else { /** * Just after the creation of a new page in `tbl_pages` * * @delegate PagePostCreate * @since Symphony 2.2 * @param string $context * '/blueprints/pages/' * @param integer $page_id * The ID of the newly created Page * @param array $fields * An associative array of data that was just saved for this page */ Symphony::ExtensionManager()->notifyMembers('PagePostCreate', '/blueprints/pages/', array('page_id' => $page_id, 'fields' => &$fields)); $redirect = "/blueprints/pages/edit/{$page_id}/created/{$parent_link_suffix}"; } } else { /** * Just prior to updating a Page record in `tbl_pages`, provided * with the `$fields` associative array. Use with caution, as no * duplicate page checks are run after this delegate has fired * * @delegate PagePreEdit * @since Symphony 2.2 * @param string $context * '/blueprints/pages/' * @param integer $page_id * The ID of the Page that is about to be updated * @param array $fields * The `$_POST['fields']` array passed by reference */ Symphony::ExtensionManager()->notifyMembers('PagePreEdit', '/blueprints/pages/', array('page_id' => $page_id, 'fields' => &$fields)); if (!PageManager::edit($page_id, $fields, true)) { return $this->pageAlert(__('Unknown errors occurred while attempting to save.') . '<a href="' . SYMPHONY_URL . '/system/log/">' . __('Check your activity log') . '</a>.', Alert::ERROR); } else { /** * Just after updating a page in `tbl_pages` * * @delegate PagePostEdit * @since Symphony 2.2 * @param string $context * '/blueprints/pages/' * @param integer $page_id * The ID of the Page that was just updated * @param array $fields * An associative array of data that was just saved for this page */ Symphony::ExtensionManager()->notifyMembers('PagePostEdit', '/blueprints/pages/', array('page_id' => $page_id, 'fields' => $fields)); $redirect = "/blueprints/pages/edit/{$page_id}/saved/{$parent_link_suffix}"; } } } // Only proceed if there was no errors saving/creating the page if (empty($this->_errors)) { /** * Just before the page's types are saved into `tbl_pages_types`. * Use with caution as no further processing is done on the `$types` * array to prevent duplicate `$types` from occurring (ie. two index * page types). Your logic can use the PageManger::hasPageTypeBeenUsed * function to perform this logic. * * @delegate PageTypePreCreate * @since Symphony 2.2 * @see toolkit.PageManager#hasPageTypeBeenUsed * @param string $context * '/blueprints/pages/' * @param integer $page_id * The ID of the Page that was just created or updated * @param array $types * An associative array of the types for this page passed by reference. */ Symphony::ExtensionManager()->notifyMembers('PageTypePreCreate', '/blueprints/pages/', array('page_id' => $page_id, 'types' => &$types)); // Assign page types: PageManager::addPageTypesToPage($page_id, $types); // Find and update children: if ($this->_context[0] == 'edit') { PageManager::editPageChildren($page_id, $fields['path'] . '/' . $fields['handle']); } if ($redirect) { redirect(SYMPHONY_URL . $redirect); } } } // If there was any errors, either with pre processing or because of a // duplicate page, return. if (is_array($this->_errors) && !empty($this->_errors)) { return $this->pageAlert(__('An error occurred while processing this form. See below for details.'), Alert::ERROR); } } }
public function __formAction() { $fields = $_POST['fields']; $this->_errors = array(); $providers = Symphony::ExtensionManager()->getProvidersOf(iProvider::EVENT); $providerClass = null; if (trim($fields['name']) == '') { $this->_errors['name'] = __('This is a required field'); } if (trim($fields['source']) == '') { $this->_errors['source'] = __('This is a required field'); } $filters = isset($fields['filters']) ? $fields['filters'] : array(); // See if a Provided Datasource is saved if (!empty($providers)) { foreach ($providers as $providerClass => $provider) { if ($fields['source'] == call_user_func(array($providerClass, 'getSource'))) { call_user_func_array(array($providerClass, 'validate'), array(&$fields, &$this->_errors)); break; } unset($providerClass); } } $classname = Lang::createHandle($fields['name'], 255, '_', false, true, array('@^[^a-z\\d]+@i' => '', '/[^\\w-\\.]/i' => '')); $rootelement = str_replace('_', '-', $classname); $extends = 'SectionEvent'; // Check to make sure the classname is not empty after handlisation. if (empty($classname) && !isset($this->_errors['name'])) { $this->_errors['name'] = __('Please ensure name contains at least one Latin-based character.', array($classname)); } $file = EVENTS . '/event.' . $classname . '.php'; $isDuplicate = false; $queueForDeletion = NULL; if ($this->_context[0] == 'new' && is_file($file)) { $isDuplicate = true; } else { if ($this->_context[0] == 'edit') { $existing_handle = $this->_context[1]; if ($classname != $existing_handle && is_file($file)) { $isDuplicate = true; } else { if ($classname != $existing_handle) { $queueForDeletion = EVENTS . '/event.' . $existing_handle . '.php'; } } } } // Duplicate if ($isDuplicate) { $this->_errors['name'] = __('An Event with the name %s already exists', array('<code>' . $classname . '</code>')); } if (empty($this->_errors)) { $multiple = in_array('expect-multiple', $filters); $elements = NULL; $placeholder = '<!-- GRAB -->'; $source = $fields['source']; $params = array('rootelement' => $rootelement); $about = array('name' => $fields['name'], 'version' => 'Symphony ' . Symphony::Configuration()->get('version', 'symphony'), 'release date' => DateTimeObj::getGMT('c'), 'author name' => Administration::instance()->Author->getFullName(), 'author website' => URL, 'author email' => Administration::instance()->Author->get('email')); // If there is a provider, get their template if ($providerClass) { $eventShell = file_get_contents(call_user_func(array($providerClass, 'getTemplate'))); } else { $eventShell = file_get_contents($this->getTemplate('blueprints.event')); $about['trigger condition'] = $rootelement; } $this->__injectAboutInformation($eventShell, $about); // Replace the name $eventShell = str_replace('<!-- CLASS NAME -->', $classname, $eventShell); // Build the templates if ($providerClass) { $eventShell = call_user_func(array($providerClass, 'prepare'), $fields, $params, $eventShell); } else { $this->__injectFilters($eventShell, $filters); // Add Documentation $documentation = NULL; $documentation_parts = array(); $documentation_parts[] = new XMLElement('h3', __('Success and Failure XML Examples')); $documentation_parts[] = new XMLElement('p', __('When saved successfully, the following XML will be returned:')); if ($multiple) { $code = new XMLElement($rootelement); $entry = new XMLElement('entry', NULL, array('index' => '0', 'result' => 'success', 'type' => 'create | edit')); $entry->appendChild(new XMLElement('message', __('Entry [created | edited] successfully.'))); $code->appendChild($entry); } else { $code = new XMLElement($rootelement, NULL, array('result' => 'success', 'type' => 'create | edit')); $code->appendChild(new XMLElement('message', __('Entry [created | edited] successfully.'))); } $documentation_parts[] = self::processDocumentationCode($code); $documentation_parts[] = new XMLElement('p', __('When an error occurs during saving, due to either missing or invalid fields, the following XML will be returned') . ($multiple ? ' (<strong> ' . __('Notice that it is possible to get mixtures of success and failure messages when using the ‘Allow Multiple’ option') . '</strong>)' : NULL) . ':'); if ($multiple) { $code = new XMLElement($rootelement); $entry = new XMLElement('entry', NULL, array('index' => '0', 'result' => 'error')); $entry->appendChild(new XMLElement('message', __('Entry encountered errors when saving.'))); $entry->appendChild(new XMLElement('field-name', NULL, array('type' => 'invalid | missing'))); $code->appendChild($entry); $entry = new XMLElement('entry', NULL, array('index' => '1', 'result' => 'success', 'type' => 'create | edit')); $entry->appendChild(new XMLElement('message', __('Entry [created | edited] successfully.'))); $code->appendChild($entry); } else { $code = new XMLElement($rootelement, NULL, array('result' => 'error')); $code->appendChild(new XMLElement('message', __('Entry encountered errors when saving.'))); $code->appendChild(new XMLElement('field-name', NULL, array('type' => 'invalid | missing'))); } $code->setValue('...', false); $documentation_parts[] = self::processDocumentationCode($code); if (is_array($filters) && !empty($filters)) { $documentation_parts[] = new XMLElement('p', __('The following is an example of what is returned if any options return an error:')); $code = new XMLElement($rootelement, NULL, array('result' => 'error')); $code->appendChild(new XMLElement('message', __('Entry encountered errors when saving.'))); $code->appendChild(new XMLElement('filter', NULL, array('name' => 'admin-only', 'status' => 'failed'))); $code->appendChild(new XMLElement('filter', __('Recipient not found'), array('name' => 'send-email', 'status' => 'failed'))); $code->setValue('...', false); $documentation_parts[] = self::processDocumentationCode($code); } $documentation_parts[] = new XMLElement('h3', __('Example Front-end Form Markup')); $documentation_parts[] = new XMLElement('p', __('This is an example of the form markup you can use on your frontend:')); $container = new XMLElement('form', NULL, array('method' => 'post', 'action' => '', 'enctype' => 'multipart/form-data')); $container->appendChild(Widget::Input('MAX_FILE_SIZE', (string) min(ini_size_to_bytes(ini_get('upload_max_filesize')), Symphony::Configuration()->get('max_upload_size', 'admin')), 'hidden')); if (is_numeric($fields['source'])) { $section = SectionManager::fetch($fields['source']); if ($section instanceof Section) { $section_fields = $section->fetchFields(); if (is_array($section_fields) && !empty($section_fields)) { foreach ($section_fields as $f) { if ($f->getExampleFormMarkup() instanceof XMLElement) { $container->appendChild($f->getExampleFormMarkup()); } } } } } $container->appendChild(Widget::Input('action[' . $rootelement . ']', __('Submit'), 'submit')); $code = $container->generate(true); $documentation_parts[] = self::processDocumentationCode($multiple ? str_replace('fields[', 'fields[0][', $code) : $code); $documentation_parts[] = new XMLElement('p', __('To edit an existing entry, include the entry ID value of the entry in the form. This is best as a hidden field like so:')); $documentation_parts[] = self::processDocumentationCode(Widget::Input('id' . ($multiple ? '[0]' : NULL), '23', 'hidden')); $documentation_parts[] = new XMLElement('p', __('To redirect to a different location upon a successful save, include the redirect location in the form. This is best as a hidden field like so, where the value is the URL to redirect to:')); $documentation_parts[] = self::processDocumentationCode(Widget::Input('redirect', URL . '/success/', 'hidden')); if (in_array('send-email', $filters)) { $documentation_parts[] = new XMLElement('h3', __('Send Notification Email')); $documentation_parts[] = new XMLElement('p', __('Upon the event successfully saving the entry, this option takes input from the form and send an email to the desired recipient.') . ' <strong>' . __('It currently does not work with ‘Allow Multiple’') . '</strong>. ' . __('The following are the recognised fields:')); $documentation_parts[] = self::processDocumentationCode('send-email[sender-email] // ' . __('Optional') . PHP_EOL . 'send-email[sender-name] // ' . __('Optional') . PHP_EOL . 'send-email[reply-to-email] // ' . __('Optional') . PHP_EOL . 'send-email[reply-to-name] // ' . __('Optional') . PHP_EOL . 'send-email[subject]' . PHP_EOL . 'send-email[body]' . PHP_EOL . 'send-email[recipient] // ' . __('list of comma-separated author usernames.')); $documentation_parts[] = new XMLElement('p', __('All of these fields can be set dynamically using the exact field name of another field in the form as shown below in the example form:')); $documentation_parts[] = self::processDocumentationCode('<form action="" method="post"> <fieldset> <label>' . __('Name') . ' <input type="text" name="fields[author]" value="" /></label> <label>' . __('Email') . ' <input type="text" name="fields[email]" value="" /></label> <label>' . __('Message') . ' <textarea name="fields[message]" rows="5" cols="21"></textarea></label> <input name="send-email[sender-email]" value="fields[email]" type="hidden" /> <input name="send-email[sender-name]" value="fields[author]" type="hidden" /> <input name="send-email[reply-to-email]" value="fields[email]" type="hidden" /> <input name="send-email[reply-to-name]" value="fields[author]" type="hidden" /> <input name="send-email[subject]" value="You are being contacted" type="hidden" /> <input name="send-email[body]" value="fields[message]" type="hidden" /> <input name="send-email[recipient]" value="fred" type="hidden" /> <input id="submit" type="submit" name="action[save-contact-form]" value="Send" /> </fieldset> </form>'); } /** * Allows adding documentation for new filters. A reference to the $documentation * array is provided, along with selected filters * @delegate AppendEventFilterDocumentation * @param string $context * '/blueprints/events/(edit|new|info)/' * @param array $selected * An array of all the selected filters for this Event * @param array $documentation * An array of all the documentation XMLElements, passed by reference */ Symphony::ExtensionManager()->notifyMembers('AppendEventFilterDocumentation', '/blueprints/events/' . $this->_context[0] . '/', array('selected' => $filters, 'documentation' => &$documentation_parts)); $documentation = join(PHP_EOL, array_map(create_function('$x', 'return rtrim($x->generate(true, 4));'), $documentation_parts)); $documentation = str_replace('\'', '\\\'', $documentation); $eventShell = str_replace('<!-- CLASS EXTENDS -->', $extends, $eventShell); $eventShell = str_replace('<!-- DOCUMENTATION -->', General::tabsToSpaces($documentation, 2), $eventShell); } $eventShell = str_replace('<!-- ROOT ELEMENT -->', $rootelement, $eventShell); $eventShell = str_replace('<!-- CLASS NAME -->', $classname, $eventShell); $eventShell = str_replace('<!-- SOURCE -->', $source, $eventShell); // Remove left over placeholders $eventShell = preg_replace(array('/<!--[\\w ]++-->/'), '', $eventShell); if ($this->_context[0] == 'new') { /** * Prior to creating an Event, the file path where it will be written to * is provided and well as the contents of that file. * * @delegate EventsPreCreate * @since Symphony 2.2 * @param string $context * '/blueprints/events/' * @param string $file * The path to the Event file * @param string $contents * The contents for this Event as a string passed by reference * @param array $filters * An array of the filters attached to this event */ Symphony::ExtensionManager()->notifyMembers('EventPreCreate', '/blueprints/events/', array('file' => $file, 'contents' => &$eventShell, 'filters' => $filters)); } else { /** * Prior to editing an Event, the file path where it will be written to * is provided and well as the contents of that file. * * @delegate EventPreEdit * @since Symphony 2.2 * @param string $context * '/blueprints/events/' * @param string $file * The path to the Event file * @param string $contents * The contents for this Event as a string passed by reference * @param array $filters * An array of the filters attached to this event */ Symphony::ExtensionManager()->notifyMembers('EventPreEdit', '/blueprints/events/', array('file' => $file, 'contents' => &$eventShell, 'filters' => $filters)); } // Write the file if (!is_writable(dirname($file)) || !($write = General::writeFile($file, $eventShell, Symphony::Configuration()->get('write_mode', 'file')))) { $this->pageAlert(__('Failed to write Event to disk.') . ' ' . __('Please check permissions on %s.', array('<code>/workspace/events</code>')), Alert::ERROR); } else { if ($queueForDeletion) { General::deleteFile($queueForDeletion); $pages = PageManager::fetch(false, array('events', 'id'), array("\n\t\t\t\t\t\t\t`events` REGEXP '[[:<:]]" . $existing_handle . "[[:>:]]'\n\t\t\t\t\t\t")); if (is_array($pages) && !empty($pages)) { foreach ($pages as $page) { $page['events'] = preg_replace('/\\b' . $existing_handle . '\\b/i', $classname, $page['events']); PageManager::edit($page['id'], $page); } } } if ($this->_context[0] == 'new') { /** * After creating the Event, the path to the Event file is provided * * @delegate EventPostCreate * @since Symphony 2.2 * @param string $context * '/blueprints/events/' * @param string $file * The path to the Event file */ Symphony::ExtensionManager()->notifyMembers('EventPostCreate', '/blueprints/events/', array('file' => $file)); } else { /** * After editing the Event, the path to the Event file is provided * * @delegate EventPostEdit * @since Symphony 2.2 * @param string $context * '/blueprints/events/' * @param string $file * The path to the Event file * @param string $previous_file * The path of the previous Event file in the case where an Event may * have been renamed. To get the handle from this value, see * `EventManager::__getHandleFromFilename` */ Symphony::ExtensionManager()->notifyMembers('EventPostEdit', '/blueprints/events/', array('file' => $file, 'previous_file' => $queueForDeletion ? $queueForDeletion : null)); } redirect(SYMPHONY_URL . '/blueprints/events/edit/' . $classname . '/' . ($this->_context[0] == 'new' ? 'created' : 'saved') . '/'); } } }
/** * Returns Pages that match the given `$types`. If no `$types` is provided * the function returns the result of `PageManager::fetch`. * * @param array $types * An array of some of the available Page Types. * @param boolean $negate (optional) * If true, the logic gets inversed to return Pages that don't match the given `$types`. * @return array|null * An associative array of Page information with the key being the column * name from `tbl_pages` and the value being the data. If multiple Pages * are found, an array of Pages will be returned. If no Pages are found * null is returned. */ public static function fetchPageByTypes(array $types = array(), $andOperation = false, $negate = false) { if (empty($types)) { return PageManager::fetch(); } $types = array_map(array('MySQL', 'cleanValue'), $types); // Build SQL parts depending on query parameters. There are four possibilities. // 1. Without negation and with OR filter if (!$andOperation && !$negate) { $join = "LEFT JOIN `tbl_pages_types` AS `pt` ON (p.id = pt.page_id)"; $where = sprintf("\n\t\t\t\t\t\tAND `pt`.type IN ('%s')\n\t\t\t\t\t", implode("', '", $types)); } elseif ($andOperation && !$negate) { $join = ""; $where = ""; foreach ($types as $index => $type) { $join .= " LEFT JOIN `tbl_pages_types` AS `pt_{$index}` ON (p.id = pt_{$index}.page_id)"; $where .= " AND pt_{$index}.type = '" . $type . "'"; } } elseif (!$andOperation && $negate) { $join = sprintf("\n\t\t\t\t\t\tLEFT JOIN `tbl_pages_types` AS `pt` ON (p.id = pt.page_id AND pt.type IN ('%s'))\n\t\t\t\t\t", implode("', '", $types)); $where = "AND `pt`.type IS NULL"; } elseif ($andOperation && $negate) { $join = ""; $where = "AND ("; foreach ($types as $index => $type) { $join .= sprintf("\n\t\t\t\t\t\t\tLEFT JOIN `tbl_pages_types` AS `pt_%s` ON (p.id = pt_%s.page_id AND pt_%s.type IN ('%s'))\n\t\t\t\t\t\t", $index, $index, $index, $type); $where .= ($index === 0 ? "" : " OR ") . "pt_{$index}.type IS NULL"; } $where .= ")"; } $pages = Symphony::Database()->fetch(sprintf("\n\t\t\t\t\tSELECT\n\t\t\t\t\t\t`p`.*\n\t\t\t\t\tFROM\n\t\t\t\t\t\t`tbl_pages` AS `p`\n\t\t\t\t\t%s\n\t\t\t\t\tWHERE 1\n\t\t\t\t\t\t%s\n\t\t\t\t", $join, $where)); return count($pages) == 1 ? array_pop($pages) : $pages; }
/** * This function will return the number of child pages for a given * `$page_id`. This is a recursive function and will return the absolute * count. * * @param integer $page_id * The ID of the Page. * @return integer * The number of child pages for the given `$page_id` */ public static function getChildPagesCount($page_id = null) { if (is_null($page_id)) { return null; } $children = PageManager::fetch(false, array('id'), array(sprintf('parent = %d', $page_id))); $count = count($children); if ($count > 0) { foreach ($children as $c) { $count += self::getChildPagesCount($c['id']); } } return $count; }
public function __formAction() { $fields = $_POST['fields']; $this->_errors = array(); $providers = Symphony::ExtensionManager()->getProvidersOf('data-sources'); $providerClass = null; if (trim($fields['name']) == '') { $this->_errors['name'] = __('This is a required field'); } if ($fields['source'] == 'static_xml') { if (trim($fields['static_xml']) == '') { $this->_errors['static_xml'] = __('This is a required field'); } else { $xml_errors = NULL; include_once TOOLKIT . '/class.xsltprocess.php'; General::validateXML($fields['static_xml'], $xml_errors, false, new XsltProcess()); if (!empty($xml_errors)) { $this->_errors['static_xml'] = __('XML is invalid'); } } } elseif ($fields['source'] == 'dynamic_xml') { if (trim($fields['dynamic_xml']['url']) == '') { $this->_errors['dynamic_xml']['url'] = __('This is a required field'); } // Use the TIMEOUT that was specified by the user for a real world indication $timeout = isset($fields['dynamic_xml']['timeout']) ? (int) $fields['dynamic_xml']['timeout'] : 6; // If there is a parameter in the URL, we can't validate the existence of the URL // as we don't have the environment details of where this datasource is going // to be executed. if (!preg_match('@{([^}]+)}@i', $fields['dynamic_xml']['url'])) { $valid_url = self::__isValidURL($fields['dynamic_xml']['url'], $timeout, $error); if ($valid_url) { $data = $valid_url['data']; } else { $this->_errors['dynamic_xml']['url'] = $error; } } if (trim($fields['dynamic_xml']['xpath']) == '') { $this->_errors['dynamic_xml']['xpath'] = __('This is a required field'); } if (!is_numeric($fields['dynamic_xml']['cache'])) { $this->_errors['dynamic_xml']['cache'] = __('Must be a valid number'); } elseif ($fields['dynamic_xml']['cache'] < 1) { $this->_errors['dynamic_xml']['cache'] = __('Must be greater than zero'); } } elseif (is_numeric($fields['source'])) { if (strlen(trim($fields['max_records'])) == 0 || is_numeric($fields['max_records']) && $fields['max_records'] < 1) { if (isset($fields['paginate_results'])) { $this->_errors['max_records'] = __('A result limit must be set'); } } else { if (!self::__isValidPageString($fields['max_records'])) { $this->_errors['max_records'] = __('Must be a valid number or parameter'); } } if (strlen(trim($fields['page_number'])) == 0 || is_numeric($fields['page_number']) && $fields['page_number'] < 1) { if (isset($fields['paginate_results'])) { $this->_errors['page_number'] = __('A page number must be set'); } } else { if (!self::__isValidPageString($fields['page_number'])) { $this->_errors['page_number'] = __('Must be a valid number or parameter'); } } } elseif (!empty($providers)) { foreach ($providers as $providerClass => $provider) { if ($fields['source'] == call_user_func(array($providerClass, 'getSource'))) { call_user_func(array($providerClass, 'validate'), &$fields, &$this->_errors); break; } unset($providerClass); } } $classname = Lang::createHandle($fields['name'], 255, '_', false, true, array('@^[^a-z\\d]+@i' => '', '/[^\\w-\\.]/i' => '')); $rootelement = str_replace('_', '-', $classname); // Check to make sure the classname is not empty after handlisation. if (empty($classname) && !isset($this->_errors['name'])) { $this->_errors['name'] = __('Please ensure name contains at least one Latin-based character.', array($classname)); } $file = DATASOURCES . '/data.' . $classname . '.php'; $isDuplicate = false; $queueForDeletion = NULL; if ($this->_context[0] == 'new' && is_file($file)) { $isDuplicate = true; } elseif ($this->_context[0] == 'edit') { $existing_handle = $this->_context[1]; if ($classname != $existing_handle && is_file($file)) { $isDuplicate = true; } elseif ($classname != $existing_handle) { $queueForDeletion = DATASOURCES . '/data.' . $existing_handle . '.php'; } } // Duplicate if ($isDuplicate) { $this->_errors['name'] = __('A Data source with the name %s already exists', array('<code>' . $classname . '</code>')); } if (empty($this->_errors)) { $filters = array(); $elements = NULL; $placeholder = '<!-- GRAB -->'; $source = $fields['source']; $params = array('rootelement' => $rootelement); $about = array('name' => $fields['name'], 'version' => 'Symphony ' . Symphony::Configuration()->get('version', 'symphony'), 'release date' => DateTimeObj::getGMT('c'), 'author name' => Administration::instance()->Author->getFullName(), 'author website' => URL, 'author email' => Administration::instance()->Author->get('email')); // If there is a provider, get their template if ($providerClass) { $dsShell = file_get_contents(call_user_func(array($providerClass, 'getTemplate'))); } else { $dsShell = file_get_contents($this->getTemplate('blueprints.datasource')); } // Author metadata self::injectAboutInformation($dsShell, $about); // Do dependencies, the template file must have <!-- CLASS NAME --> // and <!-- DS DEPENDENCY LIST --> tokens $dsShell = str_replace('<!-- CLASS NAME -->', $classname, $dsShell); // If there is a provider, let them do the prepartion work if ($providerClass) { $dsShell = call_user_func(array($providerClass, 'prepare'), $fields, $params, $dsShell); } else { switch ($source) { case 'authors': $extends = 'AuthorDatasource'; if (isset($fields['filter']['author'])) { $filters = $fields['filter']['author']; } $elements = $fields['xml_elements']; $params['order'] = $fields['order']; $params['redirectonempty'] = isset($fields['redirect_on_empty']) ? 'yes' : 'no'; $params['requiredparam'] = trim($fields['required_url_param']); $params['paramoutput'] = $fields['param']; $params['sort'] = $fields['sort']; break; case 'navigation': $extends = 'NavigationDatasource'; if (isset($fields['filter']['navigation'])) { $filters = $fields['filter']['navigation']; } $params['order'] = $fields['order']; $params['redirectonempty'] = isset($fields['redirect_on_empty']) ? 'yes' : 'no'; $params['requiredparam'] = trim($fields['required_url_param']); break; case 'dynamic_xml': $extends = 'DynamicXMLDatasource'; // Automatically detect namespaces if (isset($data)) { preg_match_all('/xmlns:([a-z][a-z-0-9\\-]*)="([^\\"]+)"/i', $data, $matches); if (!is_array($fields['dynamic_xml']['namespace'])) { $fields['dynamic_xml']['namespace'] = array(); } if (isset($matches[2][0])) { $detected_namespaces = array(); foreach ($fields['dynamic_xml']['namespace'] as $name => $uri) { $detected_namespaces[] = $name; $detected_namespaces[] = $uri; } foreach ($matches[2] as $index => $uri) { $name = $matches[1][$index]; if (in_array($name, $detected_namespaces) or in_array($uri, $detected_namespaces)) { continue; } $detected_namespaces[] = $name; $detected_namespaces[] = $uri; $fields['dynamic_xml']['namespace'][] = array('name' => $name, 'uri' => $uri); } } } $filters = array(); if (is_array($fields['dynamic_xml']['namespace'])) { foreach ($fields['dynamic_xml']['namespace'] as $index => $data) { $filters[$data['name']] = $data['uri']; } } $params['url'] = $fields['dynamic_xml']['url']; $params['xpath'] = $fields['dynamic_xml']['xpath']; $params['cache'] = $fields['dynamic_xml']['cache']; $params['format'] = $fields['dynamic_xml']['format']; $params['timeout'] = isset($fields['dynamic_xml']['timeout']) ? (int) $fields['dynamic_xml']['timeout'] : '6'; break; case 'static_xml': $extends = 'StaticXMLDatasource'; $fields['static_xml'] = trim($fields['static_xml']); if (preg_match('/^<\\?xml/i', $fields['static_xml']) == true) { // Need to remove any XML declaration $fields['static_xml'] = preg_replace('/^<\\?xml[^>]+>/i', NULL, $fields['static_xml']); } $params['static'] = sprintf('%s', addslashes(trim($fields['static_xml']))); break; default: $extends = 'SectionDatasource'; $elements = $fields['xml_elements']; if (is_array($fields['filter']) && !empty($fields['filter'])) { $filters = array(); foreach ($fields['filter'] as $f) { foreach ($f as $key => $val) { $filters[$key] = $val; } } } $params['order'] = $fields['order']; $params['group'] = $fields['group']; $params['paginateresults'] = isset($fields['paginate_results']) ? 'yes' : 'no'; $params['limit'] = $fields['max_records']; $params['startpage'] = $fields['page_number']; $params['redirectonempty'] = isset($fields['redirect_on_empty']) ? 'yes' : 'no'; $params['requiredparam'] = trim($fields['required_url_param']); $params['paramoutput'] = $fields['param']; $params['sort'] = $fields['sort']; $params['htmlencode'] = $fields['html_encode']; $params['associatedentrycounts'] = $fields['associated_entry_counts']; if ($params['associatedentrycounts'] == NULL) { $params['associatedentrycounts'] = 'no'; } break; } $this->__injectVarList($dsShell, $params); $this->__injectIncludedElements($dsShell, $elements); self::injectFilters($dsShell, $filters); if (preg_match_all('@(\\$ds-[0-9a-z_\\.\\-]+)@i', $dsShell, $matches)) { $dependencies = General::array_remove_duplicates($matches[1]); $dsShell = str_replace('<!-- DS DEPENDENCY LIST -->', "'" . implode("', '", $dependencies) . "'", $dsShell); } $dsShell = str_replace('<!-- CLASS EXTENDS -->', $extends, $dsShell); $dsShell = str_replace('<!-- SOURCE -->', $source, $dsShell); } if ($this->_context[0] == 'new') { /** * Prior to creating the Datasource, the file path where it will be written to * is provided and well as the contents of that file. * * @delegate DatasourcePreCreate * @since Symphony 2.2 * @param string $context * '/blueprints/datasources/' * @param string $file * The path to the Datasource file * @param string $contents * The contents for this Datasource as a string passed by reference * @param array $params * An array of all the `$dsParam*` values * @param array $elements * An array of all the elements included in this datasource * @param array $filters * An associative array of all the filters for this datasource with the key * being the `field_id` and the value the filter. * @param array $dependencies * An array of dependencies that this datasource has */ Symphony::ExtensionManager()->notifyMembers('DatasourcePreCreate', '/blueprints/datasources/', array('file' => $file, 'contents' => &$dsShell, 'params' => $params, 'elements' => $elements, 'filters' => $filters, 'dependencies' => $dependencies)); } else { /** * Prior to editing a Datasource, the file path where it will be written to * is provided and well as the contents of that file. * * @delegate DatasourcePreEdit * @since Symphony 2.2 * @param string $context * '/blueprints/datasources/' * @param string $file * The path to the Datasource file * @param string $contents * The contents for this Datasource as a string passed by reference * @param array $dependencies * An array of dependencies that this datasource has * @param array $params * An array of all the `$dsParam*` values * @param array $elements * An array of all the elements included in this datasource * @param array $filters * An associative array of all the filters for this datasource with the key * being the `field_id` and the value the filter. */ Symphony::ExtensionManager()->notifyMembers('DatasourcePreEdit', '/blueprints/datasources/', array('file' => $file, 'contents' => &$dsShell, 'dependencies' => $dependencies, 'params' => $params, 'elements' => $elements, 'filters' => $filters)); } // Remove left over placeholders $dsShell = preg_replace(array('/<!--[\\w ]++-->/', '/(\\r\\n){2,}/', '/(\\t+[\\r\\n]){2,}/'), '', $dsShell); // Write the file if (!is_writable(dirname($file)) || !($write = General::writeFile($file, $dsShell, Symphony::Configuration()->get('write_mode', 'file')))) { $this->pageAlert(__('Failed to write Data source to disk.') . ' ' . __('Please check permissions on %s.', array('<code>/workspace/data-sources</code>')), Alert::ERROR); } else { if ($queueForDeletion) { General::deleteFile($queueForDeletion); // Update pages that use this DS $pages = PageManager::fetch(false, array('data_sources', 'id'), array("\n\t\t\t\t\t\t\t`data_sources` REGEXP '[[:<:]]" . $existing_handle . "[[:>:]]'\n\t\t\t\t\t\t")); if (is_array($pages) && !empty($pages)) { foreach ($pages as $page) { $page['data_sources'] = preg_replace('/\\b' . $existing_handle . '\\b/i', $classname, $page['data_sources']); PageManager::edit($page['id'], $page); } } } if ($this->_context[0] == 'new') { /** * After creating the Datasource, the path to the Datasource file is provided * * @delegate DatasourcePostCreate * @since Symphony 2.2 * @param string $context * '/blueprints/datasources/' * @param string $file * The path to the Datasource file */ Symphony::ExtensionManager()->notifyMembers('DatasourcePostCreate', '/blueprints/datasources/', array('file' => $file)); } else { /** * After editing the Datasource, the path to the Datasource file is provided * * @delegate DatasourcePostEdit * @since Symphony 2.2 * @param string $context * '/blueprints/datasources/' * @param string $file * The path to the Datasource file */ Symphony::ExtensionManager()->notifyMembers('DatasourcePostEdit', '/blueprints/datasources/', array('file' => $file)); } redirect(SYMPHONY_URL . '/blueprints/datasources/edit/' . $classname . '/' . ($this->_context[0] == 'new' ? 'created' : 'saved') . '/'); } } }
public function __viewEdit() { $isNew = true; $time = Widget::Time(); // Verify role exists if ($this->_context[0] == 'edit') { $isNew = false; if (!($role_id = $this->_context[1])) { redirect(extension_Members::baseURL() . 'roles/'); } if (!($existing = RoleManager::fetch($role_id))) { throw new SymphonyErrorPage(__('The role you requested to edit does not exist.'), __('Role not found')); } } // Add in custom assets Administration::instance()->Page->addStylesheetToHead(URL . '/extensions/members/assets/members.roles.css', 'screen', 101); Administration::instance()->Page->addScriptToHead(URL . '/extensions/members/assets/members.roles.js', 104); // Append any Page Alerts from the form's if (isset($this->_context[2])) { switch ($this->_context[2]) { case 'saved': $this->pageAlert(__('Role updated at %s.', array($time->generate())) . ' <a href="' . extension_members::baseURL() . 'roles/new/" accesskey="c">' . __('Create another?') . '</a> <a href="' . extension_members::baseURL() . 'roles/" accesskey="a">' . __('View all Roles') . '</a>', Alert::SUCCESS); break; case 'created': $this->pageAlert(__('Role created at %s.', array($time->generate())) . ' <a href="' . extension_members::baseURL() . 'roles/new/" accesskey="c">' . __('Create another?') . '</a> <a href="' . extension_members::baseURL() . 'roles/" accesskey="a">' . __('View all Roles') . '</a>', Alert::SUCCESS); break; } } // Has the form got any errors? $formHasErrors = is_array($this->_errors) && !empty($this->_errors); if ($formHasErrors) { $this->pageAlert(__('An error occurred while processing this form. <a href="#error">See below for details.</a>'), Alert::ERROR); } $this->setPageType('form'); if ($isNew) { $this->setTitle(__('Symphony – Member Roles')); $this->appendSubheading(__('Untitled')); $fields = array('name' => null, 'permissions' => null, 'page_access' => null); } else { $this->setTitle(__('Symphony – Member Roles – ') . $existing->get('name')); $this->appendSubheading($existing->get('name')); if (isset($_POST['fields'])) { $fields = $_POST['fields']; } else { $fields = array('name' => $existing->get('name'), 'permissions' => $existing->get('event_permissions'), 'page_access' => $existing->get('forbidden_pages')); } } $this->insertBreadcrumbs(array(Widget::Anchor(__('Member Roles'), extension_members::baseURL() . 'roles/'))); $fieldset = new XMLElement('fieldset'); $fieldset->setAttribute('class', 'settings type-file'); $fieldset->appendChild(new XMLElement('legend', __('Essentials'))); $label = Widget::Label(__('Name')); $label->appendChild(Widget::Input('fields[name]', General::sanitize($fields['name']))); if (isset($this->_errors['name'])) { $fieldset->appendChild(Widget::Error($label, $this->_errors['name'])); } else { $fieldset->appendChild($label); } $this->Form->appendChild($fieldset); $events = EventManager::listAll(); $fieldset = new XMLElement('fieldset'); $fieldset->setAttribute('class', 'settings type-file'); $fieldset->appendChild(new XMLElement('legend', __('Event Level Permissions'))); $aTableBody = array(); if (is_array($events) && !empty($events)) { foreach ($events as $event_handle => $event) { $permissions = $fields['permissions'][$event_handle]; $td_name = Widget::TableData($event['name'], 'name'); $td_permission_create = Widget::TableData(sprintf('<label title="%s">%s <span>%s</span></label>', __('User can create new entries'), Widget::Input("fields[permissions][{$event_handle}][create]", (string) EventPermissions::CREATE, 'checkbox', $permissions['create'] == EventPermissions::CREATE ? array('checked' => 'checked') : NULL)->generate(), 'Create'), 'create'); $td_permission_none = Widget::TableData(sprintf('<label title="%s">%s <span>%s</span></label>', __('User cannot edit existing entries'), Widget::Input("fields[permissions][{$event_handle}][edit]", (string) EventPermissions::NO_PERMISSIONS, 'radio', $permissions['edit'] == EventPermissions::NO_PERMISSIONS ? array('checked' => 'checked') : NULL)->generate(), 'None')); $td_permission_own = Widget::TableData(sprintf('<label title="%s">%s <span>%s</span></label>', __('User can edit their own entries only'), Widget::Input("fields[permissions][{$event_handle}][edit]", (string) EventPermissions::OWN_ENTRIES, 'radio', $permissions['edit'] == EventPermissions::OWN_ENTRIES ? array('checked' => 'checked') : NULL)->generate(), 'Own')); $td_permission_all = Widget::TableData(sprintf('<label title="%s">%s <span>%s</span></label>', __('User can edit all entries'), Widget::Input("fields[permissions][{$event_handle}][edit]", (string) EventPermissions::ALL_ENTRIES, 'radio', $permissions['edit'] == EventPermissions::ALL_ENTRIES ? array('checked' => 'checked') : NULL)->generate(), 'All')); // Create an Event instance $ev = EventManager::create($event_handle, array()); $aTableBody[] = Widget::TableRow(array($td_name, $td_permission_create, $td_permission_none, $td_permission_own, $td_permission_all), method_exists($ev, 'ignoreRolePermissions') && $ev->ignoreRolePermissions() == true ? 'inactive' : ''); unset($ev); } } $thead = Widget::TableHead(array(array(__('Event'), 'col', array('class' => 'name')), array(__('Create New'), 'col', array('class' => 'new', 'title' => __('Toggle all'))), array(__('No Edit'), 'col', array('class' => 'edit', 'title' => __('Toggle all'))), array(__('Edit Own'), 'col', array('class' => 'edit', 'title' => __('Toggle all'))), array(__('Edit All'), 'col', array('class' => 'edit', 'title' => __('Toggle all'))))); $table = Widget::Table($thead, NULL, Widget::TableBody($aTableBody), 'role-permissions'); $fieldset->appendChild($table); $this->Form->appendChild($fieldset); // Add Page Permissions [simple Deny/Allow] $fieldset = new XMLElement('fieldset'); $fieldset->setAttribute('class', 'settings type-file'); $fieldset->appendChild(new XMLElement('legend', __('Page Level Permissions'))); $label = Widget::Label(__('Deny Access')); if (!is_array($fields['page_access'])) { $fields['page_access'] = array(); } $options = array(); $pages = PageManager::fetch(false, array('id')); if (!empty($pages)) { foreach ($pages as $page) { $options[] = array($page['id'], in_array($page['id'], $fields['page_access']), '/' . PageManager::resolvePagePath($page['id'])); } } $label->appendChild(Widget::Select('fields[page_access][]', $options, array('multiple' => 'multiple'))); $fieldset->appendChild($label); $this->Form->appendChild($fieldset); $div = new XMLElement('div'); $div->setAttribute('class', 'actions'); $div->appendChild(Widget::Input('action[save]', __('Save Changes'), 'submit', array('accesskey' => 's'))); if (!$isNew && $existing->get('id') != Role::PUBLIC_ROLE) { $button = new XMLElement('button', __('Delete')); $button->setAttributeArray(array('name' => 'action[delete]', 'class' => 'button confirm delete', 'title' => __('Delete this Role'), 'type' => 'submit', 'accesskey' => 'd')); $div->appendChild($button); } $this->Form->appendChild($div); }
/** * This function is called from the resources index when a user uses the * With Selected, or Apply, menu. The type of resource is given by * `$resource_type`. At this time the only two valid values, * `RESOURCE_TYPE_EVENT` or `RESOURCE_TYPE_DATASOURCE`. * * The function handles 'delete', 'attach', 'detach', 'attach all', * 'detach all' actions. * * @param integer $resource_type * Either `RESOURCE_TYPE_EVENT` or `RESOURCE_TYPE_DATASOURCE` */ public function __actionIndex($resource_type) { $manager = ResourceManager::getManagerFromType($resource_type); if (isset($_POST['action']) && is_array($_POST['action'])) { $checked = $_POST['items'] ? @array_keys($_POST['items']) : NULL; if (is_array($checked) && !empty($checked)) { if ($_POST['with-selected'] == 'delete') { $canProceed = true; foreach ($checked as $handle) { $path = call_user_func(array($manager, '__getDriverPath'), $handle); if (!General::deleteFile($path)) { $folder = str_replace(DOCROOT, '', $path); $folder = str_replace('/' . basename($path), '', $folder); $this->pageAlert(__('Failed to delete %s.', array('<code>' . basename($path) . '</code>')) . ' ' . __('Please check permissions on %s', array('<code>' . $folder . '</code>')), Alert::ERROR); $canProceed = false; } } if ($canProceed) { redirect(Administration::instance()->getCurrentPageURL()); } } else { if (preg_match('/^(at|de)?tach-(to|from)-page-/', $_POST['with-selected'])) { if (substr($_POST['with-selected'], 0, 6) == 'detach') { $page = str_replace('detach-from-page-', '', $_POST['with-selected']); foreach ($checked as $handle) { ResourceManager::detach($resource_type, $handle, $page); } } else { $page = str_replace('attach-to-page-', '', $_POST['with-selected']); foreach ($checked as $handle) { ResourceManager::attach($resource_type, $handle, $page); } } if ($canProceed) { redirect(Administration::instance()->getCurrentPageURL()); } } else { if (preg_match('/^(at|de)?tach-all-pages$/', $_POST['with-selected'])) { $pages = PageManager::fetch(false, array('id')); if (substr($_POST['with-selected'], 0, 6) == 'detach') { foreach ($checked as $handle) { foreach ($pages as $page) { ResourceManager::detach($resource_type, $handle, $page['id']); } } } else { foreach ($checked as $handle) { foreach ($pages as $page) { ResourceManager::attach($resource_type, $handle, $page['id']); } } } redirect(Administration::instance()->getCurrentPageURL()); } } } } } }
public function appendFormattedElement(XMLElement &$wrapper, $data, $encode = false, $mode = null, $entry_id = null) { if (!is_array($data) || empty($data)) { return; } $role_id = $this->getActivationRole($entry_id, $data['role_id']); $role = RoleManager::fetch($role_id); if (!$role instanceof Role) { return; } $element = new XMLElement($this->get('element_name'), null, array('id' => $role->get('id'), 'assumed-id' => $data["role_id"], 'mode' => $mode == "permissions" ? $mode : 'normal')); $element->appendChild(new XMLElement('name', General::sanitize($role->get('name')), array('handle' => $role->get('handle')))); if ($mode == "permissions") { // The more information that's provided here, the easier it will be for // a developer to write XSLT that is dynamic and can work when the Roles // are updated in the backend. For instance you could check if a page was // denied access before creating a link to it. This check would then work // for all roles, instead of writing logic for Role A, Role B. Consider it // feature detection, rather than user agent detection. $forbidden_pages = $role->get('forbidden_pages'); if (is_array($forbidden_pages) & !empty($forbidden_pages)) { $page_data = PageManager::fetch(false, array('*'), array(sprintf('id IN (%s)', implode(',', $forbidden_pages)))); if (is_array($page_data) && !empty($page_data)) { $pages = new XMLElement('forbidden-pages'); foreach ($page_data as $key => $page) { $attributes = array('id' => $page['id'], 'handle' => $page['handle']); if (!is_null($page['path'])) { $attributes['parent-path'] = General::sanitize($page['path']); } $pages->appendChild(new XMLElement('page', $page['title'], $attributes)); } $element->appendChild($pages); } } $event_permissions = $role->get('event_permissions'); if (is_array($event_permissions) & !empty($event_permissions)) { $events = new XMLElement('events'); foreach ($event_permissions as $event => $event_data) { $item = new XMLElement('event', null, array('handle' => $event)); foreach ($event_data as $action => $level) { $item->appendChild(new XMLElement('action', EventPermissions::$permissionMap[$level], array('type' => $action, 'handle' => Lang::createHandle(EventPermissions::$permissionMap[$level])))); } $events->appendChild($item); } $element->appendChild($events); } } $wrapper->appendChild($element); }
/** * This function is called from the resources index when a user uses the * With Selected, or Apply, menu. The type of resource is given by * `$resource_type`. At this time the only two valid values, * `RESOURCE_TYPE_EVENT` or `RESOURCE_TYPE_DATASOURCE`. * * The function handles 'delete', 'attach', 'detach', 'attach all', * 'detach all' actions. * * @param integer $resource_type * Either `RESOURCE_TYPE_EVENT` or `RESOURCE_TYPE_DATASOURCE` * @throws Exception */ public function __actionIndex($resource_type) { $manager = ResourceManager::getManagerFromType($resource_type); $checked = is_array($_POST['items']) ? array_keys($_POST['items']) : null; $context = Administration::instance()->getPageCallback(); if (isset($_POST['action']) && is_array($_POST['action'])) { /** * Extensions can listen for any custom actions that were added * through `AddCustomPreferenceFieldsets` or `AddCustomActions` * delegates. * * @delegate CustomActions * @since Symphony 2.3.2 * @param string $context * '/blueprints/datasources/' or '/blueprints/events/' * @param array $checked * An array of the selected rows. The value is usually the ID of the * the associated object. */ Symphony::ExtensionManager()->notifyMembers('CustomActions', $context['pageroot'], array('checked' => $checked)); if (is_array($checked) && !empty($checked)) { if ($_POST['with-selected'] == 'delete') { $canProceed = true; foreach ($checked as $handle) { $path = call_user_func(array($manager, '__getDriverPath'), $handle); // Don't allow Extension resources to be deleted. RE: #2027 if (stripos($path, EXTENSIONS) === 0) { continue; } elseif (!General::deleteFile($path)) { $folder = str_replace(DOCROOT, '', $path); $folder = str_replace('/' . basename($path), '', $folder); $this->pageAlert(__('Failed to delete %s.', array('<code>' . basename($path) . '</code>')) . ' ' . __('Please check permissions on %s', array('<code>' . $folder . '</code>')), Alert::ERROR); $canProceed = false; } else { $pages = ResourceManager::getAttachedPages($resource_type, $handle); foreach ($pages as $page) { ResourceManager::detach($resource_type, $handle, $page['id']); } } } if ($canProceed) { redirect(Administration::instance()->getCurrentPageURL()); } } elseif (preg_match('/^(at|de)?tach-(to|from)-page-/', $_POST['with-selected'])) { if (substr($_POST['with-selected'], 0, 6) == 'detach') { $page = str_replace('detach-from-page-', '', $_POST['with-selected']); foreach ($checked as $handle) { ResourceManager::detach($resource_type, $handle, $page); } } else { $page = str_replace('attach-to-page-', '', $_POST['with-selected']); foreach ($checked as $handle) { ResourceManager::attach($resource_type, $handle, $page); } } if ($canProceed) { redirect(Administration::instance()->getCurrentPageURL()); } } elseif (preg_match('/^(at|de)?tach-all-pages$/', $_POST['with-selected'])) { $pages = PageManager::fetch(false, array('id')); if (substr($_POST['with-selected'], 0, 6) == 'detach') { foreach ($checked as $handle) { foreach ($pages as $page) { ResourceManager::detach($resource_type, $handle, $page['id']); } } } else { foreach ($checked as $handle) { foreach ($pages as $page) { ResourceManager::attach($resource_type, $handle, $page['id']); } } } redirect(Administration::instance()->getCurrentPageURL()); } } } }
public function render_panel($context) { $config = $context['config']; switch ($context['type']) { case 'datasource_to_table': $ds = DatasourceManager::create($config['datasource'], NULL, false); if (!$ds) { $context['panel']->appendChild(new XMLElement('div', __('The Data Source with the name <code>%s</code> could not be found.', array($config['datasource'])))); return; } $param_pool = array(); $xml = $ds->grab($param_pool); if (!$xml) { return; } $xml = $xml->generate(); require_once TOOLKIT . '/class.xsltprocess.php'; $proc = new XsltProcess(); $data = $proc->process($xml, file_get_contents(EXTENSIONS . '/dashboard/lib/datasource-to-table.xsl')); $context['panel']->appendChild(new XMLElement('div', $data)); break; case 'rss_reader': require_once TOOLKIT . '/class.gateway.php'; require_once CORE . '/class.cacheable.php'; $cache_id = md5('rss_reader_cache' . $config['url']); $cache = new Cacheable(Administration::instance()->Database()); $data = $cache->check($cache_id); if (!$data) { $ch = new Gateway(); $ch->init(); $ch->setopt('URL', $config['url']); $ch->setopt('TIMEOUT', 6); $new_data = $ch->exec(); $writeToCache = true; if ((int) $config['cache'] > 0) { $cache->write($cache_id, $new_data, $config['cache']); } $xml = $new_data; if (empty($xml) && $data) { $xml = $data['data']; } } else { $xml = $data['data']; } if (!$xml) { $xml = '<error>' . __('Error: could not retrieve panel XML feed.') . '</error>'; } require_once TOOLKIT . '/class.xsltprocess.php'; $proc = new XsltProcess(); $data = $proc->process($xml, file_get_contents(EXTENSIONS . '/dashboard/lib/rss-reader.xsl'), array('show' => $config['show'])); $context['panel']->appendChild(new XMLElement('div', $data)); break; case 'html_block': require_once TOOLKIT . '/class.gateway.php'; require_once CORE . '/class.cacheable.php'; $cache_id = md5('html_block_' . $config['url']); $cache = new Cacheable(Administration::instance()->Database()); $data = $cache->check($cache_id); if (!$data) { $ch = new Gateway(); $ch->init(); $ch->setopt('URL', $config['url']); $ch->setopt('TIMEOUT', 6); $new_data = $ch->exec(); $writeToCache = true; if ((int) $config['cache'] > 0) { $cache->write($cache_id, $new_data, $config['cache']); } $html = $new_data; if (empty($html) && $data) { $html = $data['data']; } } else { $html = $data['data']; } if (!$html) { $html = '<p class="invalid">' . __('Error: could not retrieve panel HTML.') . '</p>'; } $context['panel']->appendChild(new XMLElement('div', $html)); break; case 'symphony_overview': $container = new XMLElement('div'); $dl = new XMLElement('dl'); $dl->appendChild(new XMLElement('dt', __('Website Name'))); $dl->appendChild(new XMLElement('dd', Symphony::Configuration()->get('sitename', 'general'))); $current_version = Symphony::Configuration()->get('version', 'symphony'); require_once TOOLKIT . '/class.gateway.php'; $ch = new Gateway(); $ch->init(); $ch->setopt('URL', 'https://api.github.com/repos/symphonycms/symphony-2/tags'); $ch->setopt('TIMEOUT', $timeout); $repo_tags = $ch->exec(); // tags request found if (is_array($repo_tags)) { $repo_tags = json_decode($repo_tags); $tags = array(); foreach ($repo_tags as $tag) { // remove tags that contain strings if (preg_match('/[a-zA]/i', $tag->name)) { continue; } $tags[] = $tag->name; } natsort($tags); rsort($tags); $latest_version = reset($tags); } else { $latest_version = $current_version; } $needs_update = version_compare($latest_version, $current_version, '>'); $dl->appendChild(new XMLElement('dt', __('Version'))); $dl->appendChild(new XMLElement('dd', $current_version . ($needs_update ? ' (<a href="http://getsymphony.com/download/releases/version/' . $latest_version . '/">' . __('Latest is %s', array($latest_version)) . "</a>)" : ''))); $container->appendChild(new XMLElement('h4', __('Configuration'))); $container->appendChild($dl); $entries = 0; foreach (SectionManager::fetch() as $section) { $entries += EntryManager::fetchCount($section->get('id')); } $dl = new XMLElement('dl'); $dl->appendChild(new XMLElement('dt', __('Sections'))); $dl->appendChild(new XMLElement('dd', (string) count(SectionManager::fetch()))); $dl->appendChild(new XMLElement('dt', __('Entries'))); $dl->appendChild(new XMLElement('dd', (string) $entries)); $dl->appendChild(new XMLElement('dt', __('Data Sources'))); $dl->appendChild(new XMLElement('dd', (string) count(DatasourceManager::listAll()))); $dl->appendChild(new XMLElement('dt', __('Events'))); $dl->appendChild(new XMLElement('dd', (string) count(EventManager::listAll()))); $dl->appendChild(new XMLElement('dt', __('Pages'))); $dl->appendChild(new XMLElement('dd', (string) count(PageManager::fetch()))); $container->appendChild(new XMLElement('h4', __('Statistics'))); $container->appendChild($dl); $context['panel']->appendChild($container); break; case 'markdown_text': $formatter = TextformatterManager::create($config['formatter']); $html = $formatter->run($config['text']); $context['panel']->appendChild(new XMLElement('div', $html)); break; } }
public function __viewIndexDSPages($context) { $pages = PageManager::fetch(false, array(), array(), 'sortorder ASC'); $options = array(); foreach ($pages as $page) { $selected = $this->driver->isDSPageSelected($page['id']); $options[] = array($page['id'], $selected, '/' . PageManager::resolvePagePath($page['id'])); } $section = Widget::Label(__('Excluded Pages')); $section->setAttribute('class', 'column'); $section->appendChild(Widget::Select('settings[ds-pages][]', $options, array('multiple' => 'multiple'))); $context->appendChild($section); }
function view() { // fetch all pages $pages = PageManager::fetch(); // build container DIV $sitemap = new XMLElement('div', null, array('class' => 'sitemap')); // add headings $sitemap->appendChild(new XMLElement('h1', 'Sitemap <span>' . Symphony::Configuration()->get('sitename', 'general') . '</span>')); $sitemap->appendChild(new XMLElement('h2', 'Site Map, ' . date('d F Y', time()))); // build container ULs $primary = new XMLElement('ul', null, array('id' => 'primaryNav')); $utilities = new XMLElement('ul', null, array('id' => 'utilityNav')); // get values from config: remove spaces, remove any trailing commas and split into an array $this->type_index = explode(',', trim(preg_replace('/ /', '', Symphony::Configuration()->get('index_type', 'sitemap')), ',')); $this->type_primary = explode(',', trim(preg_replace('/ /', '', Symphony::Configuration()->get('primary_type', 'sitemap')), ',')); $this->type_utility = explode(',', trim(preg_replace('/ /', '', Symphony::Configuration()->get('utilities_type', 'sitemap')), ',')); $this->type_exclude = explode(',', trim(preg_replace('/ /', '', Symphony::Configuration()->get('exclude_type', 'sitemap')), ',')); // supplement list of pages with additional meta data foreach ($pages as $page) { $page['url'] = '/' . implode('/', Administration::instance()->resolvePagePath($page['id'])); $page['edit-url'] = Administration::instance()->getCurrentPageURL() . 'edit/' . $page['id'] . '/'; if (count(array_intersect($page['type'], $this->type_exclude)) > 0) { continue; } $page['is_home'] = count(array_intersect($page['type'], $this->type_index)) ? true : false; $page['is_primary'] = count(array_intersect($page['type'], $this->type_primary)) > 0 ? true : false; $page['is_utility'] = count(array_intersect($page['type'], $this->type_utility)) > 0 ? true : false; $this->_pages[] = $page; } // append the Home page first foreach ($this->_pages as $page) { if ($page['is_home'] == true) { $this->appendPage($primary, $page, 1, true, false); } } // append top level pages $primary_pages = 0; foreach ($this->_pages as $page) { if ($page['is_primary'] == true) { $primary_pages++; $this->appendPage($primary, $page); } } // sitemap provides styles for up to 10 top level pages if ($primary_pages > 0 && $primary_pages < 11) { $primary->setAttribute('class', 'col' . $primary_pages); } // append utilities (global) pages foreach ($this->_pages as $page) { if ($page['is_utility'] == true) { $this->appendPage($utilities, $page, 1, false, false); } } if ($utilities->getNumberOfChildren() > 0) { $sitemap->appendChild($utilities); } $sitemap->appendChild($primary); // build a vanilla HTML document $html = new XMLElement('html'); $html->setDTD('<!DOCTYPE html>'); $head = new XMLElement('head'); $head->appendChild(new XMLElement('meta', null, array('charset' => 'utf-8'))); $head->appendChild(new XMLElement('title', 'Site Map — ' . Symphony::Configuration()->get('sitename', 'general'))); $head->appendChild(new XMLElement('link', null, array('rel' => 'stylesheet', 'type' => 'text/css', 'media' => 'print, screen', 'href' => URL . '/extensions/sitemap/assets/sitemap.map.css'))); $head->appendChild(new XMLElement('link', null, array('rel' => 'stylesheet', 'type' => 'text/css', 'media' => 'print, screen', 'href' => URL . '/extensions/sitemap/assets/slickmap/slickmap.css'))); $html->appendChild($head); $body = new XMLElement('body'); $body->appendChild($sitemap); $html->appendChild($body); header('content-type: text/html'); echo $html->generate(true); die; }