1
0
mirror of https://github.com/processwire/processwire.git synced 2025-08-08 15:57:01 +02:00

Updates to support multiple template selections for Page fields per @apeisa and @niklam PR #22, plus bump version to 3.0.44

This commit is contained in:
Ryan Cramer
2016-12-09 14:16:04 -05:00
parent 880810c6bb
commit f0212dcc9c
4 changed files with 128 additions and 42 deletions

View File

@@ -45,7 +45,7 @@ class ProcessWire extends Wire {
* Reversion revision number
*
*/
const versionRevision = 43;
const versionRevision = 44;
/**
* Version suffix string (when applicable)

View File

@@ -133,10 +133,14 @@ class FieldtypePage extends FieldtypeMulti implements Module, ConfigurableModule
$template = null;
$template_id = $field->get('template_id');
$template_ids = $field->get('template_ids');
$derefAsPage = $field->get('derefAsPage');
$allowUnpub = $field->get('allowUnpub');
if($template_id) $template = $this->wire('templates')->get($template_id);
if(empty($template_ids) || count($template_ids) <= 1) {
// we only use $template optimization if only one template selected
if($template_id) $template = $this->wire('templates')->get($template_id);
}
// handle $value if it's blank, Page, or PageArray
if($derefAsPage > 0) {
@@ -385,7 +389,8 @@ class FieldtypePage extends FieldtypeMulti implements Module, ConfigurableModule
$result = false;
$parent_id = $field->get('parent_id');
$template_id = $field->get('template_id');
$template_id = $field->get('template_ids');
if(empty($template_id)) $template_id = $field->get('template_id');
if(Selectors::stringHasOperator($value)) {
// selector string
@@ -434,7 +439,7 @@ class FieldtypePage extends FieldtypeMulti implements Module, ConfigurableModule
if(!$result->id) $result = $this->wire('pages')->get("parent_id=$parentIDs, name=" .
$this->wire('sanitizer')->selectorValue($this->wire('sanitizer')->pageNameUTF8($value)));
} else if($template_id) {
} else if(!empty($template_id)) {
// set by title
$templateIDs = is_array($template_id) ? implode('|', $template_id) : $template_id;
$result = $this->wire('pages')->get("templates_id=$templateIDs, title=" . $this->wire('sanitizer')->selectorValue($value));
@@ -787,7 +792,8 @@ class FieldtypePage extends FieldtypeMulti implements Module, ConfigurableModule
$value = $this->wire('sanitizer')->selectorValue($value);
$findPagesSelector = $field->get('findPagesSelector');
$parent_id = $field->get('parent_id');
$template_id = $field->get('template_id');
$template_id = $field->get('template_ids');
if(empty($template_id)) $template_id = $field->get('template_id');
if(in_array($subfield, $this->nativeNames)) {
// fine then, we can handle that here when needed (like !=)
@@ -902,7 +908,8 @@ class FieldtypePage extends FieldtypeMulti implements Module, ConfigurableModule
$subfields = array();
$fieldgroups = array();
$template_id = $field->get('template_id');
$template_id = $field->get('template_ids');
if(empty($template_id)) $template_id = $field->get('template_id');
$parent_id = $field->get('parent_id');
if($template_id) {
@@ -1028,18 +1035,19 @@ class FieldtypePage extends FieldtypeMulti implements Module, ConfigurableModule
// convert parent ID to parent path
$data['parent_id'] = $this->wire('pages')->get((int) $data['parent_id'])->path;
}
if(!empty($data['template_id'])) {
if(is_array($data['template_id'])) {
foreach(array('template_id', 'template_ids') as $key) {
if(empty($data[$key])) continue;
if(is_array($data[$key])) {
// convert array of template ids to template names
foreach($data['template_id'] as $key => $id) {
foreach($data[$key] as $k => $id) {
if(ctype_digit("$id")) continue;
$template = $this->wire('templates')->get((int) $id);
if($template) $data['template_id'][$key] = $template->name;
if($template) $data[$key][$k] = $template->name;
}
} else if(ctype_digit("$data[template_id]")) {
} else if(ctype_digit((string) $data[$key])) {
// convert template id to template name
$template = $this->wire('templates')->get((int) $data['template_id']);
if($template) $data['template_id'] = $template->name;
$template = $this->wire('templates')->get((int) $data[$key]);
if($template) $data[$key] = $template->name;
}
}
return $data;
@@ -1071,23 +1079,24 @@ class FieldtypePage extends FieldtypeMulti implements Module, ConfigurableModule
$data['parent_id'] = $id;
}
// template
if(!empty($data['template_id'])) {
foreach(array('template_id', 'template_ids') as $property) {
if(empty($data[$property])) continue;
// template_id can be an id or array of IDs, but we will be importing a template name or array of them
$errors = array();
$isArray = is_array($data['template_id']);
if(!$isArray) $data['template_id'] = array($data['template_id']);
foreach($data['template_id'] as $key => $name) {
if(ctype_digit("$name")) continue;
$isArray = is_array($data[$property]);
if(!$isArray) $data[$property] = array($data[$property]);
foreach($data[$property] as $key => $name) {
if(ctype_digit("$name")) continue;
// we have a template name rather than id
$template = $this->wire('templates')->get($this->wire('sanitizer')->name($name));
if($template) {
$data['template_id'][$key] = $template->id;
$data[$property][$key] = $template->id;
} else {
$errors[] = $this->_('Unable to find template') . " - $name.";
}
}
if(!$isArray) $data['template_id'] = reset($data['template_id']);
if(count($errors)) $data['errors']['template_id'] = implode(" \n", $errors);
if(!$isArray) $data[$property] = reset($data[$property]);
if(count($errors)) $data['errors'][$property] = implode(" \n", $errors);
}
return $data;
}

View File

@@ -11,6 +11,7 @@
* Can be accessed from $this or from $field:
*
* @property int $template_id
* @property array $template_ids
* @property int $parent_id
* @property string $inputfield
* @property string $labelFieldName Field name to use for label (note: this will be "." if $labelFieldFormat is in use).
@@ -70,6 +71,7 @@ class InputfieldPage extends Inputfield implements ConfigurableModule {
protected static $defaultConfig = array(
'parent_id' => 0,
'template_id' => 0,
'template_ids' => array(),
'inputfield' => '',
'labelFieldName' => '',
'labelFieldFormat' => '',
@@ -142,7 +144,7 @@ class InputfieldPage extends Inputfield implements ConfigurableModule {
*
* @param array|string $class
* @param string $property
* @return $this
* @return InputfieldPage|Inputfield
*
*/
public function addClass($class, $property = 'class') {
@@ -159,7 +161,7 @@ class InputfieldPage extends Inputfield implements ConfigurableModule {
*
* @param array|string $key
* @param array|int|string $value
* @return $this
* @return InputfieldPage|Inputfield
*
*/
public function setAttribute($key, $value) {
@@ -211,7 +213,7 @@ class InputfieldPage extends Inputfield implements ConfigurableModule {
*
*/
public static function isValidPage(Page $page, $field, Page $editPage = null) {
if(!$field instanceof Field) $field = $page->wire('fields')->get($field);
if(!$field instanceof Field) throw new WireException('isValidPage requires a valid Field or field name');
@@ -228,6 +230,8 @@ class InputfieldPage extends Inputfield implements ConfigurableModule {
$findPagesSelector = $field->get('findPagesSelector');
$parent_id = $field->get('parent_id');
$template_id = $field->get('template_id');
$template_ids = $field->get('template_ids');
if(!is_array($template_ids)) $template_ids = array();
if($findPagesSelector) {
$selector = $findPagesSelector;
@@ -268,10 +272,22 @@ class InputfieldPage extends Inputfield implements ConfigurableModule {
$valid = $reflector->implementsInterface('InputfieldPageListSelection');
}
}
if($template_id && $page->template->id != $template_id) {
$hasRequiredTemplate = true;
if(!empty($template_ids)) {
if($template_id && !in_array($template_id, $template_ids)) {
array_unshift($template_ids, $template_id);
}
$hasRequiredTemplate = in_array($page->template->id, $template_ids);
} else if($template_id) {
$hasRequiredTemplate = $page->template->id == $template_id;
}
if(!$hasRequiredTemplate) {
$valid = false;
if($editPage) $editPage->set('_isValidPage', "Page $page does not have required template $template_id");
$requiredTemplate = empty($template_ids) ? $template_id : implode(',', $template_ids);
if($editPage) {
$editPage->set('_isValidPage', "Page $page does not have required template(s): $requiredTemplate");
}
}
return $valid;
@@ -295,6 +311,15 @@ class InputfieldPage extends Inputfield implements ConfigurableModule {
// ensures it accepts any config value (like those for delegate inputfields)
return true;
}
public function getSetting($key) {
$value = parent::getSetting($key);
if(empty($value) && $key == 'template_id') {
$templateIDs = parent::getSetting('template_ids');
if(!empty($templateIDs)) $value = reset($templateIDs);
}
return $value;
}
/**
* Return PageArray of selectable pages for this input
@@ -308,6 +333,7 @@ class InputfieldPage extends Inputfield implements ConfigurableModule {
$lockedModes = array(Inputfield::collapsedNoLocked, Inputfield::collapsedYesLocked);
$statusUnder = $this->allowUnpub ? Page::statusTrash : Page::statusUnpublished;
$children = null;
$templateIDs = $this->getTemplateIDs(true);
if($this->configMode) {
$children = $this->wire('pages')->newPageArray();
@@ -335,15 +361,15 @@ class InputfieldPage extends Inputfield implements ConfigurableModule {
} else if($this->parent_id) {
$parent = $this->wire('pages')->get($this->parent_id);
if($parent) {
if($this->template_id) {
$children = $parent->children("templates_id={$this->template_id}, check_access=0, status<$statusUnder");
if($templateIDs) {
$children = $parent->children("templates_id=$templateIDs, check_access=0, status<$statusUnder");
} else {
$children = $parent->children("check_access=0, status<$statusUnder");
}
}
} else if($this->template_id) {
$children = $this->pages->find("templates_id={$this->template_id}, check_access=0, status<$statusUnder");
} else if($templateIDs) {
$children = $this->pages->find("templates_id=$templateIDs, check_access=0, status<$statusUnder");
} else {
$children = $this->wire('pages')->newPageArray();
@@ -354,7 +380,26 @@ class InputfieldPage extends Inputfield implements ConfigurableModule {
}
return $children;
}
}
/**
* Return array or string of configured template IDs
*
* @param bool $getString Specify true to return a 1|2|3 style string rather than an array
* @return array|string
*
*/
public function getTemplateIDs($getString = false) {
$templateIDs = $this->getSetting('template_ids');
$templateID = $this->getSetting('template_id');
if(empty($templateIDs)) {
if(empty($templateID)) return $getString ? '' : array();
$templateIDs = array($templateID);
} else {
if(!in_array($templateID, $templateIDs)) array_unshift($templateIDs, $templateID);
}
return $getString ? implode('|', $templateIDs) : $templateIDs;
}
/**
* Populate any variables in findPagesSelector
@@ -369,6 +414,7 @@ class InputfieldPage extends Inputfield implements ConfigurableModule {
// if an $inputfield is passed in, then we want to retrieve dependent values directly
// from the form, rather than from the $page
/** @var InputfieldWrapper $form */
if($inputfield) {
// locate the $form
$n = 0;
@@ -480,6 +526,7 @@ class InputfieldPage extends Inputfield implements ConfigurableModule {
$parent_id = $this->getSetting('parent_id');
$template_id = $this->getSetting('template_id');
$template_ids = $this->getTemplateIDs();
$findPagesCode = $this->getSetting('findPagesCode');
$findPagesSelector = $this->getSetting('findPagesSelector');
$labelFieldName = $this->getSetting('labelFieldName');
@@ -494,6 +541,7 @@ class InputfieldPage extends Inputfield implements ConfigurableModule {
}
if($template_id) $inputfield->template_id = $template_id;
if(!empty($template_ids)) $inputfield->template_ids = $template_ids;
if($findPagesSelector) {
$inputfield->findPagesSelector = self::getFindPagesSelector($page, $findPagesSelector);
@@ -801,7 +849,7 @@ class InputfieldPage extends Inputfield implements ConfigurableModule {
foreach($titles as $title) {
// check if there is an existing page using this title
$selector = "include=all, templates_id={$this->template_id}, title=" . $this->wire('sanitizer')->selectorValue($title);
$selector = "include=all, templates_id=$template_id, title=" . $this->wire('sanitizer')->selectorValue($title);
$existingPage = $parent->child($selector);
if($existingPage->id) {
// use existing page
@@ -865,6 +913,7 @@ class InputfieldPage extends Inputfield implements ConfigurableModule {
} else if($value instanceof PageArray) {
// derefAsPageArray
/** @var PageArray $value */
if(!count($value)) return true;
} else {
@@ -901,17 +950,37 @@ class InputfieldPage extends Inputfield implements ConfigurableModule {
$field->attr('value', (int) $this->parent_id);
$field->description = $this->_('Select the parent of the pages that are selectable.');
$field->required = false;
$fieldset->append($field);
$fieldset->append($field);
/** @var InputfieldSelect $field */
$field = $this->modules->get('InputfieldSelect');
$field->setAttribute('name', 'template_id');
$field->setAttribute('name', 'template_id');
$field->label = $this->_('Template of selectable page(s)');
$field->attr('value', (int) $this->template_id);
$field->description = $this->_('Select the template of the pages that are selectable. May be used instead of, or in addition to, the parent above. NOTE: Not compatible with PageListSelect input field types.'); // Description for Template of selectable pages
foreach($this->templates as $template) $field->addOption($template->id, $template->name);
foreach($this->templates as $template) {
$field->addOption($template->id, $template->name);
}
$field->attr('value', $this->getSetting('template_id'));
$field->collapsed = Inputfield::collapsedBlank;
$fieldset->append($field);
$fieldset->append($field);
$templateIDs = $this->getTemplateIDs();
/** @var InputfieldAsmSelect $field */
$field = $this->modules->get('InputfieldAsmSelect');
$field->attr('name', 'template_ids');
$field->label = $this->_('Need more templates? Select them here');
$field->description = $this->_('Optionally select multiple templates to use for page selections.');
$field->description .= ' ' . $this->_('This may not be supported by all input types.');
foreach($this->templates as $template) {
$field->addOption($template->id, $template->name);
}
$field->attr('value', $templateIDs);
$field->collapsed = Inputfield::collapsedBlank;
$field->showIf = 'template_id!=0';
if(count($templateIDs) == 1 && reset($templateIDs) == $this->getSetting('template_id')) {
$field->collapsed = Inputfield::collapsedYes;
}
$fieldset->append($field);
/** @var InputfieldText $field */
$field = $this->modules->get('InputfieldText');

View File

@@ -10,6 +10,7 @@
*
* @property int $parent_id Limit results to this parent, or if combined with findPagesSelector, the search is performed as $pages->get($parent_id)->find() rather than $pages->find().
* @property int $template_id Limit results to pages using this template.
* @property array $template_ids Limit results to pages using this templates (alternate to the single template_id).
* @property string $labelFieldName Field to display in the results. (default=title)
* @property string $labelFieldFormat Format string to display in the results, overrides labelFieldName when used (default=blank).
* @property string $searchFields Field(s) to search for text. Separate multiple by a space. (default=title)
@@ -48,7 +49,8 @@ class InputfieldPageAutocomplete extends Inputfield implements InputfieldHasArra
$this->set('parent_id', 0);
// limit results to pages using this template
$this->set('template_id', 0);
$this->set('template_id', 0);
$this->set('template_ids', array());
// field to display in the results
$this->set('labelFieldName', 'title');
@@ -259,7 +261,11 @@ _OUT;
else $value = array();
foreach($value as $k => $v) {
$value[$k] = (int) $v;
if(empty($v)) {
unset($value[$k]);
} else {
$value[$k] = (int) $v;
}
}
$this->attr('value', $value);
@@ -287,7 +293,9 @@ _OUT;
}
}
if($this->template_id) {
if(count($this->template_ids)) {
$selector .= ",templates_id=" . implode('|', $this->template_ids);
} else if($this->template_id) {
$selector .= ",templates_id={$this->template_id}";
}