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') . '/'); } } }
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') . '/'); } } }