Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

965 lines (774 sloc) 32.944 kB
<?php
/**
* @package subsectionmanager
*/
/**
* This field provides inline subsection management.
*/
if(!defined('__IN_SYMPHONY__')) die('<h2>Symphony Error</h2><p>You cannot directly access this file</p>');
require_once(EXTENSIONS . '/subsectionmanager/lib/class.subsectionmanager.php');
Class fieldSubsectionmanager extends Field {
static $sortOrder = null;
/**
* @see http://symphony-cms.com/learn/api/2.3/toolkit/field/#__construct
*/
function __construct() {
parent::__construct();
$this->_name = __('Subsection Manager');
$this->_required = true;
}
/*-------------------------------------------------------------------------
Definition:
-------------------------------------------------------------------------*/
/**
* @see http://symphony-cms.com/learn/api/2.3/toolkit/field/#canFilter
*/
function canFilter(){
return true;
}
/**
* @see http://symphony-cms.com/learn/api/2.3/toolkit/field/#isSortable
*/
public function isSortable(){
return false;
}
/**
* @see http://symphony-cms.com/learn/api/2.3/toolkit/field/#allowDatasourceOutputGrouping
*/
public function allowDatasourceOutputGrouping(){
return ($this->get('allow_multiple') == 0 ? true : false);
}
/**
* @see http://symphony-cms.com/learn/api/2.3/toolkit/field/#allowDatasourceParamOutput
*/
function allowDatasourceParamOutput(){
return true;
}
/**
* Test whether this field requires grouping. If this function returns true
* SQL statements generated in the `EntryManager` will include the `DISTINCT` keyword
* to only return a single row for an entry regardless of how many 'matches' it
* might have. This default implementation returns false.
*/
public function requiresSQLGrouping(){
return ($this->get('allow_multiple') == 1 ? true : false);
}
/*-------------------------------------------------------------------------
Setup:
-------------------------------------------------------------------------*/
/**
* @see http://symphony-cms.com/learn/api/2.3/toolkit/field/#createTable
*/
function createTable(){
return Symphony::Database()->query(
"CREATE TABLE IF NOT EXISTS `tbl_entries_data_" . $this->get('id') . "` (
`id` int(11) unsigned NOT null auto_increment,
`entry_id` int(11) unsigned NOT null,
`relation_id` int(11) unsigned DEFAULT null,
PRIMARY KEY (`id`),
KEY `entry_id` (`entry_id`),
KEY `relation_id` (`relation_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;"
);
}
/*-------------------------------------------------------------------------
Utilities:
-------------------------------------------------------------------------*/
/**
* @see http://symphony-cms.com/learn/api/2.3/toolkit/field/#fetchAssociatedEntrySearchValue
*
* `$data` would contain the related entries, but is usually `null` when called from the frontend
* (when the field is not included in the DS, and only then "associated entry count" makes sense)
*/
public function fetchAssociatedEntrySearchValue($data, $field_id = null, $parent_entry_id = null){
if(!is_null($parent_entry_id)) {
return $parent_entry_id;
}
}
/**
* @see http://symphony-cms.com/learn/api/2.3/toolkit/field/#fetchAssociatedEntryCount
*/
public function fetchAssociatedEntryCount($value){
if(isset($value)) {
return Symphony::Database()->fetchVar('count', 0, "SELECT count(*) AS `count` FROM `tbl_entries_data_".$this->get('id')."` WHERE `entry_id` = '".intval($value)."'");
}
else {
return 0;
}
}
/*-------------------------------------------------------------------------
Settings:
-------------------------------------------------------------------------*/
/**
* @see http://symphony-cms.com/learn/api/2.3/toolkit/field/#displaySettingsPanel
*/
function displaySettingsPanel(&$wrapper, $errors=null) {
// Basics
parent::displaySettingsPanel($wrapper, $errors);
/*-----------------------------------------------------------------------*/
$div = new XMLElement('div', null, array('class' => 'two columns'));
// Get current section id
$section_id = Symphony::Engine()->Page->_context[1];
// Related section
$label = new XMLElement('label', __('Subsection'), array('class' => 'column'));
$sections = SectionManager::fetch(null, 'ASC', 'name');
$options = array(
array('', false, __('None Selected')),
);
if(is_array($sections) && !empty($sections)) {
foreach($sections as $section) {
$options[] = array($section->get('id'), ($section->get('id') == $this->get('subsection_id')), $section->get('name'));
}
}
$label->appendChild(Widget::Select('fields[' . $this->get('sortorder') . '][subsection_id]', $options, array('class' => 'subsectionmanager')));
if(isset($errors['subsection_id'])) {
$div->appendChild(Widget::Error($label, $errors['subsection_id']));
}
else {
$div->appendChild($label);
}
// Recursion levels
$label = new XMLElement('label', null, array('class' => 'column'));
$recursion_levels = $this->get('recursion_levels');
$select = Widget::Select('fields[' . $this->get('sortorder') . '][recursion_levels]', array(
array('0', ($recursion_levels == 0), __('Exclude from XML output')),
array('1', ($recursion_levels == 1), __('Include 1 child level in XML output')),
array('2', ($recursion_levels == 2), __('Include 2 child levels in XML output')),
array('3', ($recursion_levels == 3), __('Include 3 child levels in XML output')),
));
$label->setValue(__('Nested subsections %s', array($select->generate())));
$div->appendChild($label);
$wrapper->appendChild($div);
/*-----------------------------------------------------------------------*/
// Filter input
$label = new XMLElement('label', __('Filter items by tags or categories') . '<i>' . __('Comma separated, alt+click for negation') . '</i>', array('class' => 'filter', 'style' => 'display: none;'));
$label->appendChild(Widget::Input('fields[' . $this->get('sortorder') . '][filter_tags]', $this->get('filter_tags')));
$wrapper->appendChild($label);
// Filter suggestions
if(is_array($sections) && !empty($sections)) {
// Get values
$values = array();
foreach($sections as $section) {
// Don't include the current section
if($section->get('id') != $section_id) {
$fields = $section->fetchFields();
// Continue if fields exist
if(is_array($fields)) {
foreach($fields as $field) {
// Fetch only taglist or select boxes
if($field->get('type') == 'taglist' || $field->get('type') == 'select' ) {
// Fetch dynamic filter values
$dynamic = Symphony::Database()->fetchCol(
'value',
"SELECT DISTINCT `value` FROM `tbl_entries_data_" . $field->get('id') . "` LIMIT 100"
);
// Fetch static filter values
$static = explode(', ', $field->get('static_options'));
// Merge dynamic and static values
$filters = array_unique(array_merge($dynamic, $static));
$relation = 'section' . $section->get('id');
foreach($filters as $value) {
if(!empty($value)) {
$values[$value][] = $relation;
}
}
}
}
}
}
}
// Generate list
if(!empty($values)) {
$filter = new XMLElement('ul', null, array('class' => 'tags negation subsectionmanager'));
foreach($values as $handle => $fields) {
$filter->appendChild(new XMLElement('li', $handle, array('rel' => implode(' ', $fields))));
}
$wrapper->appendChild($filter);
}
}
/*-----------------------------------------------------------------------*/
// Behaviour
$fieldset = new XMLElement('fieldset');
$div = new XMLElement('div', null, array('class' => 'three columns'));
// Create
$label = new XMLElement('label', '<input name="fields[' . $this->get('sortorder') . '][create]" value="1" type="checkbox"' . ($this->get('create') == 0 ? '' : ' checked="checked"') . '/> ' . __('Allow creation of new items'), array('class' => 'column'));
$div->appendChild($label);
// Remove
$label = new XMLElement('label', '<input name="fields[' . $this->get('sortorder') . '][remove]" value="1" type="checkbox"' . ($this->get('remove') == 0 ? '' : ' checked="checked"') . '/> ' . __('Allow removal of existing items'), array('class' => 'column'));
$div->appendChild($label);
// Multiple
$label = new XMLElement('label', '<input name="fields[' . $this->get('sortorder') . '][allow_multiple]" value="1" type="checkbox"' . ($this->get('allow_multiple') == 0 ? '' : ' checked="checked"') . '/> ' . __('Allow multiple items'), array('class' => 'column'));
$div->appendChild($label);
// Edit
$label = new XMLElement('label', '<input name="fields[' . $this->get('sortorder') . '][edit]" value="1" type="checkbox"' . ($this->get('edit') == 0 ? '' : ' checked="checked"') . '/> ' . __('Enable editing'), array('class' => 'column'));
$div->appendChild($label);
// Sort
$label = new XMLElement('label', '<input name="fields[' . $this->get('sortorder') . '][sort]" value="1" type="checkbox"' . ($this->get('sort') == 0 ? '' : ' checked="checked"') . '/> ' . __('Enable sorting'), array('class' => 'column'));
$div->appendChild($label);
// Drop
$label = new XMLElement('label', '<input name="fields[' . $this->get('sortorder') . '][drop]" value="1" type="checkbox"' . ($this->get('drop') == 0 ? '' : ' checked="checked"') . '/> ' . __('Enable dropping'), array('class' => 'column'));
$div->appendChild($label);
// Search
$label = new XMLElement('label', '<input name="fields[' . $this->get('sortorder') . '][show_search]" value="1" type="checkbox"' . ($this->get('show_search') == 0 ? '' : ' checked="checked"') . '/> ' . __('Show search'), array('class' => 'column'));
$div->appendChild($label);
// Search
$label = new XMLElement('label', '<input name="fields[' . $this->get('sortorder') . '][show_preview]" value="1" type="checkbox"' . ($this->get('show_preview') == 0 ? '' : ' checked="checked"') . '/> ' . __('Show image and file previews'), array('class' => 'column'));
$div->appendChild($label);
// Append behaviour settings
$fieldset->appendChild($div);
$wrapper->appendChild($fieldset);
/*-----------------------------------------------------------------------*/
// Display
$fieldset = new XMLElement('fieldset');
$div = new XMLElement('div', null, array('class' => 'two columns'));
// Caption input
$div->appendChild($this->__groupContentGenerator('caption', __('Caption'), $sections, $errors));
// Custom drop text
$div->appendChild($this->__groupContentGenerator('droptext', __('Drop text'), $sections, $errors));
$fieldset->appendChild($div);
$wrapper->appendChild($fieldset);
/*-----------------------------------------------------------------------*/
// General
$fieldset = new XMLElement('fieldset');
$div = new XMLElement('div', null, array('class' => 'two columns'));
$this->appendShowColumnCheckbox($div);
$this->appendRequiredCheckbox($div);
$fieldset->appendChild($div);
$wrapper->appendChild($fieldset);
// Compatibility with 1.x
$wrapper->appendChild(Widget::Input('fields[' . $this->get('sortorder') . '][included_fields]', $this->get('included_fields'), 'hidden'));
}
/**
* Create caption and droptext settings
*/
private function __groupContentGenerator($name, $title, $sections, $errors) {
$container = new XMLElement('div', null, array('class' => 'column'));
$label = new XMLElement('label', $title);
$label->appendChild(Widget::Input('fields[' . $this->get('sortorder') . '][' . $name . ']', htmlspecialchars($this->get($name))));
// Append Caption
if(isset($errors[$name])) {
$container->appendChild(Widget::wrapFormElementWithError($label, $errors[$name]));
}
else {
$container->appendChild($label);
}
// Caption suggestions
if(is_array($sections) && !empty($sections) && !isset($errors[$name])) {
// Get values
$values = array();
foreach($sections as $section) {
// Don't include the current section
if($section->get('id') != $section_id) {
$fields = $section->fetchFields();
// Continue if fields exist
if(is_array($fields)) {
foreach($fields as $field) {
$values[$field->get('element_name')][] = 'section' . $section->get('id');
}
}
}
}
// Generate list
if(is_array($values)) {
$filter = new XMLElement('ul', null, array('class' => 'tags inline'));
foreach($values as $handle => $fields) {
$filter->appendChild(new XMLElement('li', '{$' . $handle . '}', array('rel' => implode(' ', $fields))));
}
$container->appendChild($filter);
}
}
return $container;
}
/**
* @see http://symphony-cms.com/learn/api/2.3/toolkit/field/#checkFields
*/
function checkFields(&$errors, $checkForDuplicates=true) {
if(!is_array($errors)) $errors = array();
// Check if a related section has been selected
if($this->get('subsection_id') == '') {
$errors['subsection_id'] = __('This is a required field.');
}
// Check if caption content is well formed
if($this->get('caption')) {
try {
simplexml_load_string('<li>' . $this->get('caption') . '</li>');
}
catch(Exception $e) {
$errors['caption'] = __('%s has to be well-formed. Please check opening and closing tags.', array(__('Caption')));
}
}
// Check if droptext content is well formed
if($this->get('droptext')) {
try {
simplexml_load_string('<li>' . $this->get('droptext') . '</li>');
}
catch(Exception $e) {
$errors['droptext'] = __('%s has to be well-formed. Please check opening and closing tags.', array(__('Drop text')));
}
}
parent::checkFields($errors, $checkForDuplicates);
}
/**
* @see http://symphony-cms.com/learn/api/2.3/toolkit/field/#commit
*/
function commit() {
// Prepare commit
if(!parent::commit()) return false;
$id = $this->get('id');
if($id === false) return false;
// Set up fields
$fields = array();
$fields['field_id'] = $id;
$fields['subsection_id'] = $this->get('subsection_id');
$fields['create'] = ($this->get('create') ? 1 : 0);
$fields['remove'] = ($this->get('remove') ? 1 : 0);
$fields['allow_multiple'] = ($this->get('allow_multiple') ? 1 : 0);
$fields['edit'] = ($this->get('edit') ? 1 : 0);
$fields['sort'] = ($this->get('sort') ? 1 : 0);
$fields['drop'] = ($this->get('drop') ? 1 : 0);
$fields['show_search'] = ($this->get('show_search') ? 1 : 0);
$fields['show_preview'] = ($this->get('show_preview') ? 1 : 0);
// Clean up filter values
if($this->get('filter_tags') != '') {
$tags = explode(",", $this->get('filter_tags'));
foreach($tags as &$tag) {
$tag = trim($this->cleanValue($tag));
$list[] = $tag;
}
$fields['filter_tags'] = implode(', ', $list);
}
// Item caption
$fields['caption'] = $this->get('caption');
if($this->get('caption') == '') {
// Fetch fields in subsection
$subsection_fields = Symphony::Database()->fetch(
"SELECT element_name, type
FROM tbl_fields
WHERE parent_section = '" . $this->get('subsection_id') . "'
ORDER BY sortorder ASC
LIMIT 10"
);
// Generate default caption
$text = $file = '';
foreach($subsection_fields as $subfield) {
if($text != '' && $file != '') break;
if(strpos($subfield['type'], 'upload') === false) {
if($text == '') $text = '{$' . $subfield['element_name'] . '}';
}
else {
if($file == '') $file = '{$' . $subfield['element_name'] . '}';
}
}
// Caption markup
if($text != '' && $file != '') {
$fields['caption'] = $text . '<br /> <em>' . $file . '</em>';
}
else {
$fields['caption'] = $text . $file;
}
}
// Drop text
$fields['droptext'] = $this->get('droptext');
// XML Output
$fields['recursion_levels'] = intval($this->get('recursion_levels'));
if(empty($fields['recursion_levels'])) $fields['recursion_levels'] = 0; // Make sure it is 0, not null
// Delete old field settings
Symphony::Database()->query(
"DELETE FROM `tbl_fields_".$this->handle()."` WHERE `field_id` = '$id' LIMIT 1"
);
// Save new field setting
$settings = Symphony::Database()->insert($fields, 'tbl_fields_' . $this->handle());
// Remove old secion association
SectionManager::removeSectionAssociation($id);
// Save new section association
$association = $this->createSectionAssociation(null, $this->get('subsection_id'), $id, $id, false);
if($settings && $association) {
return true;
}
else {
return false;
}
}
/**
* @see http://symphony-cms.com/learn/api/2.3/toolkit/field/#createSectionAssociation
*/
public function createSectionAssociation($parent_section_id = null, $child_section_id = null, $child_field_id = null, $parent_field_id = null, $show_association = false){
if(is_null($parent_section_id) && is_null($child_section_id) && (is_null($parent_field_id) || !$parent_field_id)) return false;
if(is_null($parent_section_id )) {
$parent_section_id = Symphony::Database()->fetchVar('parent_section', 0,
"SELECT `parent_section` FROM `tbl_fields` WHERE `id` = '$parent_field_id' LIMIT 1"
);
}
$fields = array(
'parent_section_id' => $parent_section_id,
'parent_section_field_id' => $parent_field_id,
'child_section_id' => $child_section_id,
'child_section_field_id' => $child_field_id,
'hide_association' => ($show_association ? 'no' : 'yes')
);
return Symphony::Database()->insert($fields, 'tbl_sections_association');
}
/*-------------------------------------------------------------------------
Publish:
-------------------------------------------------------------------------*/
/**
* If you need to fetch the pure data this field returns, please use getDefaultPublishContent()
*
* @see http://symphony-cms.com/learn/api/2.3/toolkit/field/#displayPublishPanel
*/
function displayPublishPanel(&$wrapper, $data=null, $flagWithError=null, $fieldnamePrefix=null, $fieldnamePostfix=null, $entry_id=null) {
if(!is_array($data['relation_id'])) $data['relation_id'] = array($data['relation_id']);
// Houston, we have problem: we've been called out of context!
$callback = Administration::instance()->getPageCallback();
if($callback['context']['page'] != 'edit' && $callback['context']['page'] != 'new') {
$this->getDefaultPublishContent($wrapper, $data);
return;
}
// Append styles
Symphony::Engine()->Page->addStylesheetToHead(URL . '/extensions/subsectionmanager/assets/subsectionmanager.publish.css', 'screen', 102, false);
// Append scripts
Symphony::Engine()->Page->addScriptToHead(URL . '/extensions/subsectionmanager/assets/subsectionmanager.publish.js', 104, false);
Symphony::Engine()->Page->addScriptToHead(URL . '/extensions/subsectionmanager/lib/resize/jquery.ba-resize.js', 105, false);
// Setup field name
$fieldname = 'fields' . $fieldnamePrefix . '['. $this->get('element_name') . ']' . $fieldnamePostfix;
// Label
$label = Widget::Label($this->get('label'));
if($this->get('required') == 'no') {
$optional = new XMLElement('i', __('Optional'));
$label->appendChild($optional);
}
$wrapper->appendChild($label);
// Get Subsection
$subsection = new SubsectionManager();
$content = $subsection->generate($this->get('id'), $this->get('subsection_id'), $data, $this->get('recursion_levels'), SubsectionManager::GETHTML);
// Create interface
$settings = array('dark', 'frame');
if($this->get('create') == 1) {
$settings[] = 'constructable';
}
if($this->get('remove') == 1) {
$settings[] = 'destructable';
}
if($this->get('allow_multiple') == 1) {
$settings[] = 'multiple';
}
if($this->get('edit') == 1) {
$settings[] = 'editable';
}
if($this->get('sort') == 1) {
$settings[] = 'sortable';
}
if($this->get('drop') == 1) {
$settings[] = 'droppable';
}
if($this->get('show_search') == 1) {
$settings[] = 'searchable';
}
$duplicator = new XMLElement('div', null, array('class' => implode(' ', $settings)));
$selected = new XMLElement('ol', $content['html']);
$duplicator->appendChild($selected);
// Append item template
$item = new XMLElement('li',
'<header>
<strong>' . __('New item') . '</strong>
<span>' . __('Please fill out the form below') . '</span>
</header>
<div class="content">
<iframe></iframe>
</div>',
array(
'class' => 'template',
'data-type' => 'subsection'
)
);
$selected->appendChild($item);
// Append subsection information
$subsection = SectionManager::fetch($this->get('subsection_id'));
$wrapper->setAttribute('data-field-id', $this->get('id'));
$wrapper->setAttribute('data-field-name', $fieldname);
$wrapper->setAttribute('data-subsection-id', $this->get('subsection_id'));
$wrapper->setAttribute('data-subsection-new', SYMPHONY_URL . '/publish/' . $subsection->get('handle'));
// Error handling
if($flagWithError != null) {
$wrapper->appendChild(Widget::Error($duplicator, $flagWithError));
}
else {
$wrapper->appendChild($duplicator);
}
}
/**
* Get default publish content
*/
function getDefaultPublishContent(&$wrapper, $data = null) {
// Get items
$subsection = new SubsectionManager();
$content = $subsection->generate($this->get('id'), $this->get('subsection_id'), $data, $this->get('recursion_levels'), SubsectionManager::GETOPTIONS | SubsectionManager::GETALLITEMS);
// Append items
$select = Widget::Select('', $content['options'], ($this->get('allow_multiple') == 0 ? array() : array('multiple' => 'multiple')));
$wrapper->appendChild($select);
}
/**
* @see http://symphony-cms.com/learn/api/2.3/toolkit/field/#checkPostFieldData
*/
public function checkPostFieldData($data, &$message, $entry_id = null) {
if(!is_array($data)) $data = array($data);
$data = array_filter($data);
$status = parent::checkPostFieldData($data, $message, $entry_id);
if($status != self::__OK__) return $status;
if(empty($data) || !is_array($data)) return self::__OK__;
if($this->get('allow_multiple') == 0 && count($data) > 1) {
$message = __("'%s' allows single item only.", array($this->get('label')));
return self::__INVALID_FIELDS__;
}
return self::__OK__;
}
/**
* @see http://symphony-cms.com/learn/api/2.3/toolkit/field/#processRawFieldData
*/
public function processRawFieldData($data, &$status, &$message=null, $simulate=false, $entry_id=null) {
$status = self::__OK__;
if(!is_array($data)) $data = array($data);
if(empty($data)) return null;
return array('relation_id' => $data);
}
/*-------------------------------------------------------------------------
Output:
-------------------------------------------------------------------------*/
/**
* Subsection entries are pre-processed in the extension driver and stored in
* extension_subsectionmanager::$storage with other helpful data. If you are building
* custom data sources, please use extension_subsectionmanager::storeSubsectionFields()
* to store subsection fields and extension_subsectionmanager::preloadSubsectionEntries()
* to preload subsection entries.
*
* @see http://symphony-cms.com/learn/api/2.3/toolkit/field/#appendFormattedElement
*/
public function appendFormattedElement(&$wrapper, $data, $encode = false, $mode = null) {
static $done = array();
// Unify data
if(empty($data) || empty($data['relation_id'])) {
$data['relation_id'] = array();
}
else if(!is_array($data['relation_id'])) {
$data['relation_id'] = array($data['relation_id']);
}
// Create subsection element
$subsection = new XMLElement($this->get('element_name'));
$subsection->setAttribute('field-id', $this->get('id'));
$subsection->setAttribute('subsection-id', $this->get('subsection_id'));
// Generate output
foreach($data['relation_id'] as $index => $entry_id) {
// Populate entry element
$entry = extension_subsectionmanager::$storage['entries'][$entry_id];
// Fetch missing entries
if(empty($entry)) {
$entry = EntryManager::fetch($entry_id, $this->get('subsection_id'));
// Store entry
$entry = $entry[0];
extension_subsectionmanager::$storage['entries'][$entry_id] = $entry;
}
if(empty($entry)) {
// TODO: Looks like related entry was deleted and data was not removed.
// Should SubsectionManager gather deleted IDs and remove them from DB at exit?
// Or register delegate to always delete them when entry is deleted?
continue;
}
// Create item
$item = new XMLElement('item', null, array('id' => $entry_id, 'creation-date' => $entry->get('creation_date')));
$subsection->appendChild($item);
// Process entry for Data Source
if(!empty(extension_subsectionmanager::$storage['fields'][$mode][$this->get('id')])) {
foreach(extension_subsectionmanager::$storage['fields'][$mode][$this->get('id')] as $field_id => $modes) {
$field = FieldManager::fetch($field_id);
// Omit fields that were removed in meantime
if(empty($field)) continue;
$entry_data = $entry->getData($field_id);
// No modes
if(empty($modes)) {
$field->appendFormattedElement($item, $entry_data, $encode, $mode, $entry_id);
}
// With modes
else {
foreach($modes as $m) {
$field->appendFormattedElement($item, $entry_data, $encode, $m, $entry_id);
}
}
}
}
// Process entry for anyone else
else {
$engine = Symphony::Engine();
if($engine instanceof Administration) {
// Check for recursion first
$id = $this->get('parent_section');
if($done[$id] >= $this->get('recursion_levels') + 1) return array();
$done[$id] += 1;
// Now output data
$callback = Administration::instance()->getPageCallback();
if(!empty($callback['context']['page'])) {
$data = $entry->getData();
// Add fields:
foreach($data as $field_id => $values) {
if(empty($field_id)) continue;
$field = FieldManager::fetch($field_id);
if(empty($field)) continue;
$field->appendFormattedElement($item, $values, $encode, null, $entry_id);
}
}
$done[$id] -= 1;
}
}
}
// Append subsection
$subsection->setAttribute('items', count($data['relation_id']));
$wrapper->appendChild($subsection);
}
/**
* @see http://symphony-cms.com/learn/api/2.3/toolkit/field/#prepareTableValue
*/
function prepareTableValue($data, XMLElement $link=null) {
if(empty($data['relation_id'])) return null;
// Single select
if($this->get('allow_multiple') == 0 || count($data['relation_id']) === 1) {
$subsection = new SubsectionManager();
$content = $subsection->generate($this->get('id'), $this->get('subsection_id'), $data, $this->get('recursion_levels'), SubsectionManager::GETPREVIEW);
// Link?
if($link) {
$href = $link->getAttribute('href');
$item = '<a href="' . $href . '">' . $content['preview'] . '</a>';
}
else {
$item = $content['preview'];
}
return '<div class="subsectionmanager">' . $item . '</div>';
}
// Multiple select
else {
$count = count($data['relation_id']);
return parent::prepareTableValue(array('value' => ($count > 1) ? $count . ' ' . __('items') : $count . ' ' . __('item')), $link);
}
}
/**
* Used by the XML Importer when importing
*
* @param mixed $value
* @param integer $entry_id
* @return array
*/
public function prepareImportValue($value, $entry_id = null) {
if($this->get('allow_multiple_selection') == 'no') {
$value = array(implode('', $value));
}
return $value;
}
/**
* @see http://symphony-cms.com/learn/api/2.3/toolkit/field/#getParameterPoolValue
*/
public function getParameterPoolValue($data) {
return $data['relation_id'];
}
/**
* @see http://symphony-cms.com/learn/api/2.3/toolkit/field/#fetchIncludableElements
*/
public function fetchIncludableElements($break = false) {
static $done = array();
$id = $this->get('parent_section');
if($done[$id] >= $this->get('recursion_levels') + 1) return array();
$done[$id] += 1;
$includable = array();
// Fetch subsection fields
$section = SectionManager::fetch($this->get('subsection_id'));
$fields = $section->fetchFields();
foreach($fields as $field) {
$field_id = $field->get('id');
$elements = $field->fetchIncludableElements(true);
if (is_array($elements)) {
foreach($elements as $element) {
$includable[] = $this->get('element_name') . ': ' . $element;
}
}
}
$done[$id] -= 1;
return $includable;
}
/*-------------------------------------------------------------------------
Filtering:
-------------------------------------------------------------------------*/
/**
* @see http://symphony-cms.com/learn/api/2.3/toolkit/field/#displayDatasourceFilterPanel
*/
function displayDatasourceFilterPanel(&$wrapper, $data=null, $errors=null, $fieldnamePrefix=null, $fieldnamePostfix=null) {
parent::displayDatasourceFilterPanel($wrapper, $data, $errors, $fieldnamePrefix, $fieldnamePostfix);
$text = new XMLElement('p', __('Use comma separated list of entry ids that has to be associated with filtered entries, e.g., "23, 45, 691" or "not: 23, 45, 691".'), array('class' => 'help') );
$wrapper->appendChild($text);
}
/**
* @see http://symphony-cms.com/learn/api/2.3/toolkit/field/#buildDSRetrievalSQL
*/
public function buildDSRetrievalSQL($data, &$joins, &$where, $andOperation=false) {
// Current field id
$field_id = $this->get('id');
// Filters connected with AND
if($andOperation) {
$op = '=';
if(preg_match('/^not:\s*/i', $data[0], $m)) {
$data[0] = str_replace($m[0], '', $data[0]);
$op = '!=';
}
foreach($data as $value) {
$this->_key++;
$joins .= " LEFT JOIN `tbl_entries_data_{$field_id}` AS `t{$field_id}_{$this->_key}` ON (`e`.`id` = `t{$field_id}_{$this->_key}`.entry_id) ";
$where .= " AND `t{$field_id}_{$this->_key}`.relation_id {$op} '". intval($value) ."' ";
}
}
// Filters connected with OR
else {
$op = 'IN';
if(preg_match('/^not:\s*/i', $data[0], $m)) {
$data[0] = str_replace($m[0], '', $data[0]);
$op = 'NOT IN';
}
$this->_key++;
$joins .= " LEFT JOIN `tbl_entries_data_$field_id` AS `t{$field_id}_{$this->_key}` ON (`e`.`id` = `t{$field_id}_{$this->_key}`.entry_id) ";
$where .= " AND `t{$field_id}_{$this->_key}`.relation_id {$op} ('" . @implode("', '", array_map('intval', $data)) . "') ";
}
return true;
}
/*-------------------------------------------------------------------------
Grouping:
-------------------------------------------------------------------------*/
public function groupRecords($records){
if(!is_array($records) || empty($records)) return;
$groups = array($this->get('element_name') => array());
$field_id = $this->get('id');
foreach($records as $r){
$data = $r->getData($field_id);
$entry_id = $data['relation_id'];
if(!isset($groups[$this->get('element_name')][$entry_id])){
$groups[$this->get('element_name')][$entry_id] = array('attr' => array('id' => $entry_id),
'records' => array(), 'groups' => array());
}
$groups[$this->get('element_name')][$entry_id]['records'][] = $r;
}
return $groups;
}
/*-------------------------------------------------------------------------
Events:
-------------------------------------------------------------------------*/
/**
* @see http://symphony-cms.com/learn/api/2.3/toolkit/field/#getExampleFormMarkup
*/
public function getExampleFormMarkup() {
return Widget::Select('fields['.$this->get('element_name').']', array(array('...')));
}
/*-------------------------------------------------------------------------
Compatibility:
-------------------------------------------------------------------------*/
/**
* Keep compatibility with Symphony pre 2.2.1 for a little longer.
* @see http://symphony-cms.com/learn/api/2.2.1/toolkit/field/#buildDSRetrivalSQL
*/
public function buildDSRetrivalSQL($data, &$joins, &$where, $andOperation=false) {
return $this->buildDSRetrievalSQL($data, $joins, $where, $andOperation);
}
}
Jump to Line
Something went wrong with that request. Please try again.