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

Add support for Fieldtypes to specify that a Field should use a custom class that extends the Field class, rather than always using the "Field" class.

This commit is contained in:
Ryan Cramer
2019-11-12 11:06:02 -05:00
parent 4e4b3afdcb
commit bbddcf1ca0
7 changed files with 112 additions and 17 deletions

View File

@@ -616,7 +616,7 @@ class Field extends WireData implements Saveable, Exportable {
} else if(is_string($type)) { } else if(is_string($type)) {
$typeStr = $type; $typeStr = $type;
$fieldtypes = $this->wire('fieldtypes'); $fieldtypes = $this->wire('fieldtypes'); /** @var Fieldtypes $fieldtypes */
if(!$type = $fieldtypes->get($type)) { if(!$type = $fieldtypes->get($type)) {
$this->error("Fieldtype '$typeStr' does not exist"); $this->error("Fieldtype '$typeStr' does not exist");
return $this; return $this;

View File

@@ -155,6 +155,45 @@ class Fields extends WireSaveableItems {
return $this->wire(new Field()); return $this->wire(new Field());
} }
/**
* Make an item and populate with given data
*
* @param array $a Associative array of data to populate
* @return Saveable|Wire
* @throws WireException
* @since 3.0.147
*
*/
public function makeItem(array $a = array()) {
if(empty($a['type'])) return parent::makeItem($a);
/** @var Fieldtypes $fieldtypes */
$fieldtypes = $this->wire('fieldtypes');
if(!$fieldtypes) return parent::makeItem($a);
/** @var Fieldtype $fieldtype */
$fieldtype = $fieldtypes->get($a['type']);
if(!$fieldtype) return parent::makeItem($a);
$class = $fieldtype->getFieldClass($a);
if(empty($class) || $class === 'Field') return parent::makeItem($a);
if(strpos($class, "\\") === false) $class = wireClassName($class, true);
if(!class_exists($class)) return parent::makeItem($a);
$field = new $class();
$this->wire($field);
foreach($a as $key => $value) {
$field->$key = $value;
}
$field->resetTrackChanges(true);
return $field;
}
/** /**
* Per WireSaveableItems interface, return all available Field instances * Per WireSaveableItems interface, return all available Field instances
* *

View File

@@ -605,7 +605,7 @@ abstract class Fieldtype extends WireData implements Module {
* *
* #pw-internal * #pw-internal
* *
* @param array Field $field * @param Field $field
* @return array * @return array
* *
*/ */
@@ -813,6 +813,21 @@ abstract class Fieldtype extends WireData implements Module {
return $schema; return $schema;
} }
/**
* Get class name to use Field objects of this type (must be class that extends Field class)
*
* Return blank if default class (Field) should be used.
*
* @param array $a Field data from DB (if needed)
* @return string Return class name or blank to use default Field class
* @since 3.0.147
*
*/
public function getFieldClass(array $a = array()) {
if($a) {} // ignore
return '';
}
/** /**
* Returns verbose array of database schema information * Returns verbose array of database schema information
* *

View File

@@ -49,10 +49,11 @@ class Fieldtypes extends WireArray {
if($this->preloaded) return; if($this->preloaded) return;
$debug = $this->isAPI && $this->wire('config')->debug; $debug = $this->isAPI && $this->wire('config')->debug;
if($debug) Debug::timer('Fieldtypes.preload'); if($debug) Debug::timer('Fieldtypes.preload');
foreach($this->data as $key => $module) { $modules = $this->wire('modules'); /** @var Modules $modules */
foreach($this->data as $moduleName => $module) {
if($module instanceof ModulePlaceholder) { if($module instanceof ModulePlaceholder) {
$fieldtype = $this->wire('modules')->get($module->className()); $fieldtype = $modules->getModule($moduleName);
$this->data[$key] = $fieldtype; $this->data[$moduleName] = $fieldtype;
} }
} }
if($debug) Debug::saveTimer('Fieldtypes.preload'); if($debug) Debug::saveTimer('Fieldtypes.preload');
@@ -130,11 +131,12 @@ class Fieldtypes extends WireArray {
if(strpos($key, 'Fieldtype') !== 0) $key = "Fieldtype" . ucfirst($key); if(strpos($key, 'Fieldtype') !== 0) $key = "Fieldtype" . ucfirst($key);
if(!$fieldtype = parent::get($key)) { if(!$fieldtype = parent::get($key)) {
$fieldtype = $this->wire('modules')->get($key); $fieldtype = $this->wire('modules')->getModule($key);
if($fieldtype) $this->set($key, $fieldtype);
} }
if($fieldtype instanceof ModulePlaceholder) { if($fieldtype instanceof ModulePlaceholder) {
$fieldtype = $this->wire('modules')->get($fieldtype->className()); $fieldtype = $this->wire('modules')->getModule($fieldtype->className());
if($fieldtype) $this->set($key, $fieldtype); if($fieldtype) $this->set($key, $fieldtype);
} }

View File

@@ -42,6 +42,25 @@ abstract class WireSaveableItems extends Wire implements \IteratorAggregate {
*/ */
abstract public function makeBlankItem(); abstract public function makeBlankItem();
/**
* Make an item and populate with given data
*
* @param array $a Associative array of data to populate
* @return Saveable|Wire
* @throws WireException
* @since 3.0.147
*
*/
public function makeItem(array $a = array()) {
$item = $this->makeBlankItem();
$this->wire($item);
foreach($a as $key => $value) {
$item->$key = $value;
}
$item->resetTrackChanges(true);
return $item;
}
/** /**
* Return the name of the table that this DAO stores item records in * Return the name of the table that this DAO stores item records in
* *
@@ -163,6 +182,7 @@ abstract class WireSaveableItems extends Wire implements \IteratorAggregate {
*/ */
protected function ___load(WireArray $items, $selectors = null) { protected function ___load(WireArray $items, $selectors = null) {
/** @var WireDatabasePDO $database */
$database = $this->wire('database'); $database = $this->wire('database');
$sql = $this->getLoadQuery($selectors)->getQuery(); $sql = $this->getLoadQuery($selectors)->getQuery();
@@ -170,21 +190,20 @@ abstract class WireSaveableItems extends Wire implements \IteratorAggregate {
$query->execute(); $query->execute();
while($row = $query->fetch(\PDO::FETCH_ASSOC)) { while($row = $query->fetch(\PDO::FETCH_ASSOC)) {
$item = $this->makeBlankItem(); if(isset($row['data'])) {
$this->wire($item); if($row['data']) {
foreach($row as $field => $value) { $row['data'] = $this->decodeData($row['data']);
if($field == 'data') { } else {
if($value) $value = $this->decodeData($value); unset($row['data']);
else continue;
} }
$item->$field = $value;
} }
$item->setTrackChanges(true); $item = $this->makeItem($row);
$items->add($item); if($item) $items->add($item);
} }
$query->closeCursor();
$query->closeCursor();
$items->setTrackChanges(true); $items->setTrackChanges(true);
return $items; return $items;
} }

View File

@@ -200,6 +200,21 @@ class FieldtypeRepeater extends Fieldtype implements ConfigurableModule {
} }
*/ */
/**
* Get class name to use Field objects of this type (must be class that extends Field class)
*
* Return blank if default class (Field) should be used.
*
* @param array $a Field data from DB (if needed)
* @return string Return class name or blank to use default Field class
* @since 3.0.147
*
*/
public function getFieldClass(array $a = array()) {
require_once(dirname(__FILE__) . '/RepeaterField.php');
return 'RepeaterField';
}
/** /**
* Get the class used for repeater Page objects * Get the class used for repeater Page objects
* *

View File

@@ -0,0 +1,5 @@
<?php namespace ProcessWire;
class RepeaterField extends Field {
// example of custom class for Field object (not yet put to use in this case)
}