mirror of
https://github.com/processwire/processwire.git
synced 2025-08-13 18:24:57 +02:00
Add the following new hooks to $templates, $fields and $fieldgroups: renameReady($item, $oldName, $newName); renamed($item, $oldName, $newName); Added the following new hooks to $fieldgroups: fieldAdded($fieldgroup, $field); fieldRemoved($fieldgroup, $field); Make template selectable for Page fields in InputfieldSelector, plus other minor updates.
This commit is contained in:
@@ -7,12 +7,16 @@
|
||||
* #pw-body For full details on all methods available in a Fieldgroup, be sure to also see the `WireArray` class.
|
||||
* #pw-var $fieldgroups
|
||||
*
|
||||
* ProcessWire 3.x, Copyright 2016 by Ryan Cramer
|
||||
* ProcessWire 3.x, Copyright 2022 by Ryan Cramer
|
||||
* https://processwire.com
|
||||
*
|
||||
* @method int saveContext(Fieldgroup $fieldgroup)
|
||||
* @method array getExportData(Fieldgroup $fieldgroup)
|
||||
* @method array setImportData(Fieldgroup $fieldgroup, array $data)
|
||||
*
|
||||
* @method void fieldRemoved(Fieldgroup $fieldgroup, Field $field)
|
||||
* @method void fieldAdded(Fieldgroup $fieldgroup, Field $field)
|
||||
* @method void sorted(Fieldgroup $fieldgroup, array $oldOrder, array $newOrder)
|
||||
*
|
||||
*
|
||||
*/
|
||||
@@ -25,8 +29,12 @@ class Fieldgroups extends WireSaveableItemsLookup {
|
||||
* @var FieldgroupsArray
|
||||
*
|
||||
*/
|
||||
protected $fieldgroupsArray;
|
||||
|
||||
protected $fieldgroupsArray;
|
||||
|
||||
/**
|
||||
* Init
|
||||
*
|
||||
*/
|
||||
public function init() {
|
||||
$this->fieldgroupsArray = $this->wire(new FieldgroupsArray());
|
||||
$this->load($this->fieldgroupsArray);
|
||||
@@ -142,54 +150,80 @@ class Fieldgroups extends WireSaveableItemsLookup {
|
||||
*/
|
||||
public function ___save(Saveable $item) {
|
||||
|
||||
$database = $this->wire('database');
|
||||
$database = $this->wire()->database;
|
||||
|
||||
/** @var Fieldgroup $fieldgroup */
|
||||
$fieldgroup = $item;
|
||||
$datas = array();
|
||||
$fieldsAdded = array();
|
||||
$fieldsRemoved = array();
|
||||
|
||||
/** @var Fieldgroup $item */
|
||||
if($fieldgroup->id && $fieldgroup->removedFields) {
|
||||
|
||||
if($item->id && $item->removedFields) {
|
||||
|
||||
foreach($this->wire('templates') as $template) {
|
||||
if($template->fieldgroup->id !== $item->id) continue;
|
||||
foreach($item->removedFields as $field) {
|
||||
foreach($this->wire()->templates as $template) {
|
||||
if($template->fieldgroup->id !== $fieldgroup->id) continue;
|
||||
foreach($fieldgroup->removedFields as $field) {
|
||||
// make sure the field is valid to delete from this template
|
||||
$error = $this->isFieldNotRemoveable($field, $item, $template);
|
||||
$error = $this->isFieldNotRemoveable($field, $fieldgroup, $template);
|
||||
if($error !== false) throw new WireException("$error Save of fieldgroup changes aborted.");
|
||||
if($field->type) $field->type->deleteTemplateField($template, $field);
|
||||
$item->finishRemove($field);
|
||||
$fieldgroup->finishRemove($field);
|
||||
$fieldsRemoved[] = $field;
|
||||
}
|
||||
}
|
||||
|
||||
$item->resetRemovedFields();
|
||||
$fieldgroup->resetRemovedFields();
|
||||
}
|
||||
|
||||
$contextData = array();
|
||||
if($item->id) {
|
||||
// save context data
|
||||
$query = $database->prepare("SELECT fields_id, data FROM fieldgroups_fields WHERE fieldgroups_id=:item_id");
|
||||
$query->bindValue(":item_id", (int) $item->id, \PDO::PARAM_INT);
|
||||
if($fieldgroup->id) {
|
||||
// load context data to populate back after fieldgroup save
|
||||
$sql = 'SELECT fields_id, data FROM fieldgroups_fields WHERE fieldgroups_id=:fieldgroups_id';
|
||||
$query = $database->prepare($sql);
|
||||
$query->bindValue(':fieldgroups_id', (int) $fieldgroup->id, \PDO::PARAM_INT);
|
||||
$query->execute();
|
||||
/** @noinspection PhpAssignmentInConditionInspection */
|
||||
while($row = $query->fetch(\PDO::FETCH_ASSOC)) {
|
||||
$contextData[$row['fields_id']] = $row['data'];
|
||||
$fields_id = (int) $row['fields_id'];
|
||||
$datas[$fields_id] = $row['data'];
|
||||
}
|
||||
$query->closeCursor();
|
||||
}
|
||||
|
||||
$result = parent::___save($fieldgroup);
|
||||
|
||||
// identify any fields added
|
||||
foreach($fieldgroup as $field) {
|
||||
if(!array_key_exists($field->id, $datas)) {
|
||||
$fieldsAdded[] = $field;
|
||||
}
|
||||
}
|
||||
|
||||
$result = parent::___save($item);
|
||||
|
||||
if(count($contextData)) {
|
||||
if(count($datas)) {
|
||||
// restore context data
|
||||
foreach($contextData as $fields_id => $data) {
|
||||
$fieldgroups_id = (int) $item->id;
|
||||
$fields_id = (int) $fields_id;
|
||||
$query = $database->prepare("UPDATE fieldgroups_fields SET data=:data WHERE fieldgroups_id=:fieldgroups_id AND fields_id=:fields_id"); // QA
|
||||
$query->bindValue(":data", $data, \PDO::PARAM_STR);
|
||||
$fieldgroups_id = (int) $fieldgroup->id;
|
||||
foreach($datas as $fields_id => $data) {
|
||||
$sql = "UPDATE fieldgroups_fields SET data=:data WHERE fieldgroups_id=:fieldgroups_id AND fields_id=:fields_id";
|
||||
$query = $database->prepare($sql);
|
||||
if($data === null) {
|
||||
$query->bindValue(":data", null, \PDO::PARAM_NULL);
|
||||
} else {
|
||||
$query->bindValue(":data", $data, \PDO::PARAM_STR);
|
||||
}
|
||||
$query->bindValue(":fieldgroups_id", $fieldgroups_id, \PDO::PARAM_INT);
|
||||
$query->bindValue(":fields_id", $fields_id, \PDO::PARAM_INT);
|
||||
$query->execute();
|
||||
}
|
||||
}
|
||||
|
||||
// trigger any fields added
|
||||
foreach($fieldsAdded as $field) {
|
||||
$this->fieldAdded($fieldgroup, $field);
|
||||
}
|
||||
// trigger any fieldsl removed
|
||||
foreach($fieldsRemoved as $field) {
|
||||
$this->fieldRemoved($fieldgroup, $field);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
@@ -270,7 +304,7 @@ class Fieldgroups extends WireSaveableItemsLookup {
|
||||
foreach($contexts as $fieldID => $context) {
|
||||
$field = $fieldgroup->getFieldContext((int) $fieldID);
|
||||
if(!$field) continue;
|
||||
if($this->wire('fields')->saveFieldgroupContext($field, $fieldgroup)) $numSaved++;
|
||||
if($this->wire()->fields->saveFieldgroupContext($field, $fieldgroup)) $numSaved++;
|
||||
}
|
||||
return $numSaved;
|
||||
}
|
||||
@@ -486,5 +520,28 @@ class Fieldgroups extends WireSaveableItemsLookup {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook called when field has been added to fieldgroup
|
||||
*
|
||||
* #pw-hooker
|
||||
*
|
||||
* @param Fieldgroup $fieldgroup
|
||||
* @param Field $field
|
||||
* @since 3.0.193
|
||||
*
|
||||
*/
|
||||
public function ___fieldAdded(Fieldgroup $fieldgroup, Field $field) { }
|
||||
|
||||
/**
|
||||
* Hook called when field has been removed from fieldgroup
|
||||
*
|
||||
* #pw-hooker
|
||||
*
|
||||
* @param Fieldgroup $fieldgroup
|
||||
* @param Field $field
|
||||
* @since 3.0.193
|
||||
*
|
||||
*/
|
||||
public function ___fieldRemoved(Fieldgroup $fieldgroup, Field $field) { }
|
||||
}
|
||||
|
||||
|
@@ -6,7 +6,7 @@
|
||||
* Wire Data Access Object, provides reusable capability for loading, saving, creating, deleting,
|
||||
* and finding items of descending class-defined types.
|
||||
*
|
||||
* ProcessWire 3.x, Copyright 2016 by Ryan Cramer
|
||||
* ProcessWire 3.x, Copyright 2022 by Ryan Cramer
|
||||
* https://processwire.com
|
||||
*
|
||||
* @method WireArray load(WireArray $items, $selectors = null)
|
||||
@@ -20,6 +20,8 @@
|
||||
* @method void added(Saveable $item) #pw-hooker
|
||||
* @method void deleted(Saveable $item) #pw-hooker
|
||||
* @method void cloned(Saveable $item, Saveable $copy) #pw-hooker
|
||||
* @method void renameReady(Saveable $item, $oldName, $newName)
|
||||
* @method void renamed(Saveable $item, $oldName, $newName)
|
||||
*
|
||||
*
|
||||
*/
|
||||
@@ -256,6 +258,17 @@ abstract class WireSaveableItems extends Wire implements \IteratorAggregate {
|
||||
$this->saveReady($item);
|
||||
$data = $item->getTableData();
|
||||
$binds = array();
|
||||
$namePrevious = false;
|
||||
|
||||
if($id && $item->isChanged('name')) {
|
||||
$query = $database->prepare("SELECT name FROM `$table` WHERE id=:id");
|
||||
$query->bindValue(':id', $id, \PDO::PARAM_INT);
|
||||
$query->execute();
|
||||
$oldName = $query->fetchColumn();
|
||||
$query->closeCursor();
|
||||
if($oldName != $item->name) $namePrevious = $oldName;
|
||||
if($namePrevious) $this->renameReady($item, $namePrevious, $item->name);
|
||||
}
|
||||
|
||||
foreach($data as $key => $value) {
|
||||
if(!$this->saveItemKey($key)) continue;
|
||||
@@ -292,6 +305,7 @@ abstract class WireSaveableItems extends Wire implements \IteratorAggregate {
|
||||
}
|
||||
|
||||
if($result) {
|
||||
if($namePrevious) $this->renamed($item, $namePrevious, $item->name);
|
||||
$this->saved($item);
|
||||
$this->resetTrackChanges();
|
||||
} else {
|
||||
@@ -475,6 +489,16 @@ abstract class WireSaveableItems extends Wire implements \IteratorAggregate {
|
||||
*/
|
||||
public function ___cloneReady(Saveable $item, Saveable $copy) { }
|
||||
|
||||
/**
|
||||
* Hook that runs right before item is to be renamed.
|
||||
*
|
||||
* @param Saveable $item
|
||||
* @param string $oldName
|
||||
* @param string $newName
|
||||
*
|
||||
*/
|
||||
public function ___renameReady(Saveable $item, $oldName, $newName) { }
|
||||
|
||||
/**
|
||||
* Hook that runs right after an item has been saved.
|
||||
*
|
||||
@@ -517,8 +541,6 @@ abstract class WireSaveableItems extends Wire implements \IteratorAggregate {
|
||||
/**
|
||||
* Hook that runs right after an item has been cloned.
|
||||
*
|
||||
* Unlike after(delete), it has already been confirmed that the item was indeed deleted.
|
||||
*
|
||||
* @param Saveable $item
|
||||
* @param Saveable $copy
|
||||
*
|
||||
@@ -526,6 +548,18 @@ abstract class WireSaveableItems extends Wire implements \IteratorAggregate {
|
||||
public function ___cloned(Saveable $item, Saveable $copy) {
|
||||
$this->log("Cloned '$item->name' to '$copy->name'", $item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook that runs right after an item has been renamed.
|
||||
*
|
||||
* @param Saveable $item
|
||||
* @param string $oldName
|
||||
* @param string $newName
|
||||
*
|
||||
*/
|
||||
public function ___renamed(Saveable $item, $oldName, $newName) {
|
||||
$this->log("Renamed $oldName to $newName", $item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables use of $apivar('name') or wire()->apivar('name')
|
||||
|
@@ -5,7 +5,7 @@
|
||||
*
|
||||
* Provides same functionality as WireSaveableItems except that this class includes joining/modification of a related lookup table
|
||||
*
|
||||
* ProcessWire 3.x, Copyright 2016 by Ryan Cramer
|
||||
* ProcessWire 3.x, Copyright 2022 by Ryan Cramer
|
||||
* https://processwire.com
|
||||
*
|
||||
*/
|
||||
@@ -40,12 +40,13 @@ abstract class WireSaveableItemsLookup extends WireSaveableItems {
|
||||
*/
|
||||
protected function getLoadQuery($selectors = null) {
|
||||
$query = parent::getLoadQuery($selectors);
|
||||
$database = $this->wire('database');
|
||||
$database = $this->wire()->database;
|
||||
$table = $database->escapeTable($this->getTable());
|
||||
$lookupTable = $database->escapeTable($this->getLookupTable());
|
||||
$lookupField = $database->escapeCol($this->getLookupField());
|
||||
$query->select("$lookupTable.$lookupField"); // QA
|
||||
$query->leftjoin("$lookupTable ON $lookupTable.{$table}_id=$table.id ")->orderby("sort"); // QA
|
||||
$query->leftjoin("$lookupTable ON $lookupTable.{$table}_id=$table.id ")->orderby("sort");
|
||||
// $query->leftjoin("$lookupTable ON $lookupTable.{$table}_id=$table.id ")->orderby("$table.id, $lookupTable.sort");
|
||||
return $query;
|
||||
}
|
||||
|
||||
@@ -60,9 +61,9 @@ abstract class WireSaveableItemsLookup extends WireSaveableItems {
|
||||
*
|
||||
*/
|
||||
protected function ___load(WireArray $items, $selectors = null) {
|
||||
|
||||
|
||||
$database = $this->wire()->database;
|
||||
$query = $this->getLoadQuery($selectors);
|
||||
$database = $this->wire('database');
|
||||
$sql = $query->getQuery();
|
||||
$stmt = $database->prepare($sql);
|
||||
$stmt->execute();
|
||||
@@ -70,6 +71,7 @@ abstract class WireSaveableItemsLookup extends WireSaveableItems {
|
||||
|
||||
while($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
|
||||
|
||||
/** @var HasLookupItems $item */
|
||||
$item = $this->makeBlankItem();
|
||||
$lookupValue = $row[$lookupField];
|
||||
unset($row[$lookupField]);
|
||||
@@ -93,6 +95,7 @@ abstract class WireSaveableItemsLookup extends WireSaveableItems {
|
||||
|
||||
$stmt->closeCursor();
|
||||
$items->setTrackChanges(true);
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
@@ -125,7 +128,7 @@ abstract class WireSaveableItemsLookup extends WireSaveableItems {
|
||||
throw new WireException("$class::save() requires an item that implements HasLookupItems interface");
|
||||
}
|
||||
|
||||
$database = $this->wire('database');
|
||||
$database = $this->wire()->database;
|
||||
$lookupTable = $database->escapeTable($this->getLookupTable());
|
||||
$lookupField = $database->escapeCol($this->getLookupField());
|
||||
$table = $database->escapeTable($this->getTable());
|
||||
@@ -141,15 +144,18 @@ abstract class WireSaveableItemsLookup extends WireSaveableItems {
|
||||
$item_id = (int) $item->id; // reload, in case it was 0 before
|
||||
|
||||
$sort = 0;
|
||||
if($item_id) foreach($item->getLookupItems() as $key => $value) {
|
||||
$value_id = (int) $value->id;
|
||||
$query = $database->prepare("INSERT INTO $lookupTable SET {$table}_id=:item_id, $lookupField=:value_id, sort=:sort");
|
||||
$query->bindValue(":item_id", $item_id);
|
||||
$query->bindValue(":value_id", $value_id);
|
||||
$query->bindValue(":sort", $sort);
|
||||
$query->execute();
|
||||
if($item_id) {
|
||||
$sql = "INSERT INTO $lookupTable SET {$table}_id=:item_id, $lookupField=:value_id, sort=:sort";
|
||||
$query = $database->prepare($sql);
|
||||
foreach($item->getLookupItems() as $key => $value) {
|
||||
$value_id = (int) $value->id;
|
||||
$query->bindValue(":item_id", $item_id, \PDO::PARAM_INT);
|
||||
$query->bindValue(":value_id", $value_id, \PDO::PARAM_INT);
|
||||
$query->bindValue(":sort", $sort, \PDO::PARAM_INT);
|
||||
$query->execute();
|
||||
$sort++;
|
||||
}
|
||||
$this->resetTrackChanges();
|
||||
$sort++;
|
||||
}
|
||||
|
||||
return $result;
|
||||
@@ -163,7 +169,7 @@ abstract class WireSaveableItemsLookup extends WireSaveableItems {
|
||||
*
|
||||
*/
|
||||
public function ___delete(Saveable $item) {
|
||||
$database = $this->wire('database');
|
||||
$database = $this->wire()->database;
|
||||
$lookupTable = $database->escapeTable($this->getLookupTable());
|
||||
$table = $database->escapeTable($this->getTable());
|
||||
$item_id = (int) $item->id;
|
||||
|
@@ -1055,7 +1055,7 @@ class FieldtypePage extends FieldtypeMulti implements Module, ConfigurableModule
|
||||
$value = date('Y-m-d H:i:s', $value);
|
||||
|
||||
} else if(in_array($subfield, array('template', 'templates_id'))) {
|
||||
$template = $this->templates->get($subfield);
|
||||
$template = $this->templates->get($value);
|
||||
$value = $template ? $template->id : 0;
|
||||
$subfield = 'templates_id';
|
||||
|
||||
@@ -1235,6 +1235,9 @@ class FieldtypePage extends FieldtypeMulti implements Module, ConfigurableModule
|
||||
*
|
||||
*/
|
||||
public function ___getSelectorInfo(Field $field, array $data = array()) {
|
||||
|
||||
$pages = $this->wire()->pages;
|
||||
$templates = $this->wire()->templates;
|
||||
|
||||
$info = parent::___getSelectorInfo($field, $data);
|
||||
if(!isset($data['level'])) $data['level'] = 0;
|
||||
@@ -1245,29 +1248,34 @@ class FieldtypePage extends FieldtypeMulti implements Module, ConfigurableModule
|
||||
$fieldgroups = array();
|
||||
$template_ids = self::getTemplateIDs($field);
|
||||
$parent_id = $field->get('parent_id');
|
||||
$templateOptions = array();
|
||||
|
||||
if($template_ids) {
|
||||
// determine fieldgroup(s) from template setting
|
||||
// template_id can be int or array of ints
|
||||
foreach($template_ids as $tid) {
|
||||
$template = $this->wire('templates')->get((int) $tid);
|
||||
if($template) $fieldgroups[] = $template->fieldgroup;
|
||||
$template = $templates->get((int) $tid);
|
||||
if(!$template) continue;
|
||||
$fieldgroups[] = $template->fieldgroup;
|
||||
$templateOptions[$template->id] = $template->getLabel();
|
||||
}
|
||||
|
||||
} else if($parent_id) {
|
||||
// determine fieldgroup(s) from family settings
|
||||
$parent = $this->wire('pages')->get((int) $parent_id);
|
||||
$parent = $pages->get((int) $parent_id);
|
||||
if($parent->id) {
|
||||
foreach($parent->template->childTemplates as $template_id) {
|
||||
$template = $this->wire('templates')->get((int) $template_id);
|
||||
$template = $templates->get((int) $template_id);
|
||||
if(!$template) continue;
|
||||
$fieldgroups[$template->fieldgroup->id] = $template->fieldgroup;
|
||||
$templateOptions[$template->id] = $template->getLabel();
|
||||
}
|
||||
|
||||
foreach($this->wire('templates') as $template) {
|
||||
foreach($templates as $template) {
|
||||
if(!in_array($parent->template->id, $template->parentTemplates)) continue;
|
||||
if(!$this->wire('pages')->count("parent=$parent_id, template=$template->id, include=all")) continue;
|
||||
$fieldgroups[$template->fieldgroup->id] = $template->fieldgroup;
|
||||
if(!$pages->count("parent=$parent_id, template=$template->id, include=all")) continue;
|
||||
$fieldgroups[$template->fieldgroup->id] = $template->fieldgroup;
|
||||
$templateOptions[$template->id] = $template->getLabel();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1276,6 +1284,12 @@ class FieldtypePage extends FieldtypeMulti implements Module, ConfigurableModule
|
||||
// if no fieldgorups found, then we have no choice but to use all fields
|
||||
//$fieldgroups[] = $this->wire('fields');
|
||||
}
|
||||
|
||||
if(!count($templateOptions)) {
|
||||
foreach($templates as $template) {
|
||||
$templateOptions[$template->id] = $template->getLabel();
|
||||
}
|
||||
}
|
||||
|
||||
foreach($fieldgroups as $fieldgroup) {
|
||||
foreach($fieldgroup as $f) {
|
||||
@@ -1290,7 +1304,14 @@ class FieldtypePage extends FieldtypeMulti implements Module, ConfigurableModule
|
||||
'name' => 'count',
|
||||
'label' => $this->_('Count'), // Label for 'count' property of a PageArray
|
||||
'input' => 'number',
|
||||
);
|
||||
);
|
||||
|
||||
$subfields['templates_id'] = array(
|
||||
'name' => 'templates_id',
|
||||
'label' => $this->_('Template'), // Label for 'template' property of a Page
|
||||
'input' => 'select',
|
||||
'options' => $templateOptions,
|
||||
);
|
||||
|
||||
$info['subfields'] = $subfields;
|
||||
|
||||
|
@@ -270,7 +270,7 @@ function pwModalWindow(href, options, size) {
|
||||
$iframe.refresh();
|
||||
};
|
||||
$iframe.setTitle = function(title) {
|
||||
$iframe.dialog('option', 'title', title);
|
||||
$iframe.dialog('option', 'title', jQuery('<textarea />').text(title).html());
|
||||
};
|
||||
|
||||
return $iframe;
|
||||
|
2
wire/modules/Jquery/JqueryUI/modal.min.js
vendored
2
wire/modules/Jquery/JqueryUI/modal.min.js
vendored
File diff suppressed because one or more lines are too long
@@ -2958,7 +2958,7 @@ class ProcessTemplate extends Process implements ConfigurableModule {
|
||||
$template->noParents = 1;
|
||||
$template->parentTemplates = array();
|
||||
} else {
|
||||
$template->noParents = 0;
|
||||
if($template->noParents != 0) $template->noParents = 0;
|
||||
}
|
||||
|
||||
$sortfield = $sanitizer->name($input->post('sortfield'));
|
||||
|
Reference in New Issue
Block a user