1
0
mirror of https://github.com/processwire/processwire.git synced 2025-08-07 07:16:51 +02:00

Add PageFieldValueInterface as an implementation option for objects supporting page field values. Basically a helper for certain object-based values like Pagefiles/Pageimages, and likely others.

This commit is contained in:
Ryan Cramer
2016-12-01 10:56:04 -05:00
parent 30f96593bb
commit ef42513831
7 changed files with 158 additions and 35 deletions

View File

@@ -15,6 +15,7 @@ namespace PHPSTORM_META {
\wire('') => [
'' == '@',
'config' instanceof \ProcessWire\Config,
'cache' instanceof \ProcessWire\WireCache,
'wire' instanceof \ProcessWire\ProcessWire,
'log' instanceof \ProcessWire\WireLog,
'notices' instanceof \ProcessWire\Notices,
@@ -46,6 +47,7 @@ namespace PHPSTORM_META {
// this one does not appear to work, leaving in case someone knows how to make it work
'' == '@',
'config' instanceof \ProcessWire\Config,
'cache' instanceof \ProcessWire\WireCache,
'wire' instanceof \ProcessWire\ProcessWire,
'log' instanceof \ProcessWire\WireLog,
'notices' instanceof \ProcessWire\Notices,

View File

@@ -455,6 +455,56 @@ interface FieldtypeLanguageInterface {
*/
}
/**
* Interface for objects that carry a Field value for a Page
*
* Optional, but enables Page to do some of the work rather than the Fieldtype
*
*/
interface PageFieldValueInterface {
/**
* Get or set formatted state
*
* @param bool|null $set Specify bool to set formatted state or omit to retrieve formatted state
* @return bool
*
*/
public function formatted($set = null);
/**
* Set the Page
*
* @param Page $page
*
*/
public function setPage(Page $page);
/**
* Set the Field
*
* @param Field $field
*
*/
public function setField(Field $field);
/**
* Get the page or null if not set
*
* @return Page|null
*
*/
public function getPage();
/**
* Get the field or null if not set
*
* @return Field|null
*
*/
public function getField();
}
/**
* Interface for tracking runtime events
*

View File

@@ -630,8 +630,7 @@ class Page extends WireData implements \Countable, WireMatchable {
$value2 = clone $value;
$this->set($name, $value2); // commit cloned value
// if value is Pagefiles, then tell it the new page
if($value2 instanceof Pagefiles) $value2->setPage($this);
if($value2 instanceof PageFieldValueInterface) $value2->setPage($this);
}
$this->instanceID .= ".clone";
if($track) $this->setTrackChanges(true);
@@ -656,7 +655,7 @@ class Page extends WireData implements \Countable, WireMatchable {
*
* @param string $key Name of property to set
* @param mixed $value Value to set
* @return Page Reference to this Page
* @return Page|WireData Reference to this Page
* @see __set
* @throws WireException
*
@@ -783,9 +782,9 @@ class Page extends WireData implements \Countable, WireMatchable {
*
* #pw-internal
*
* @param string $key
* @param mixed $value
* @return $this
* @param string $key Name of field/property to set
* @param mixed $value Value to set
* @return Page|WireData Returns reference to this page
*
*/
public function setForced($key, $value) {
@@ -804,7 +803,7 @@ class Page extends WireData implements \Countable, WireMatchable {
* @param string $key
* @param mixed $value
* @param bool $load Should the existing value be loaded for change comparisons? (applicable only to non-autoload fields)
* @return $this
* @return Page|WireData Returns reference to this Page
* @throws WireException
*
*/
@@ -855,15 +854,24 @@ class Page extends WireData implements \Countable, WireMatchable {
// retrieve old value first in case it's not autojoined so that change comparisons and save's work
if($load && $this->isLoaded) $this->get($key);
} else if($this->outputFormatting && $field->type->formatValue($this, $field, $value) != $value) {
// The field has been loaded or dereferenced from the API, and this field changes when formatters are applied to it.
// There is a good chance they are trying to set a formatted value, and we don't allow this situation because the
// possibility of data corruption is high. We set the Page::statusCorrupted status so that Pages::save() can abort.
$this->set('status', $this->status | self::statusCorrupted);
$corruptedFields = $this->get('_statusCorruptedFields');
if(!is_array($corruptedFields)) $corruptedFields = array();
$corruptedFields[$field->name] = $field->name;
$this->set('_statusCorruptedFields', $corruptedFields);
} else {
// check if the field is corrupted
$isCorrupted = false;
if(is_object($value) && $value instanceof PageFieldValueInterface) {
if($value->formatted()) $isCorrupted = true;
} else if($this->outputFormatting && $field->type->formatValue($this, $field, $value) != $value) {
$isCorrupted = true;
}
if($isCorrupted) {
// The field has been loaded or dereferenced from the API, and this field changes when formatters are applied to it.
// There is a good chance they are trying to set a formatted value, and we don't allow this situation because the
// possibility of data corruption is high. We set the Page::statusCorrupted status so that Pages::save() can abort.
$this->set('status', $this->status | self::statusCorrupted);
$corruptedFields = $this->get('_statusCorruptedFields');
if(!is_array($corruptedFields)) $corruptedFields = array();
$corruptedFields[$field->name] = $field->name;
$this->set('_statusCorruptedFields', $corruptedFields);
}
}
// isLoaded so sanitizeValue can determine if it can perform a typecast rather than a full sanitization (when helpful)
@@ -1223,13 +1231,13 @@ class Page extends WireData implements \Countable, WireMatchable {
// note: we do not store this blank value in the Page, so that
// the real value can potentially be loaded later without output formatting
$value = $field->type->getBlankValue($this, $field);
return $field->type->formatValue($this, $field, $value);
return $this->formatFieldValue($field, $value);
}
}
if(!is_null($value) && empty($selector)) {
// if the non-filtered value is already loaded, return it
return $this->outputFormatting ? $field->type->formatValue($this, $field, $value) : $value;
return $this->formatFieldValue($field, $value);
}
$track = $this->trackChanges();
@@ -1261,8 +1269,40 @@ class Page extends WireData implements \Countable, WireMatchable {
if(is_object($value) && $value instanceof Wire) $value->resetTrackChanges(true);
if($track) $this->setTrackChanges(true);
return $this->formatFieldValue($field, $value);
}
/**
* Return a value consistent with the pages output formatting state
*
* This is primarily for use as a helper to the getFieldValue() method.
*
* @param Field $field
* @param mixed $value
* @return mixed
*
*/
protected function formatFieldValue(Field $field, $value) {
$hasInterface = is_object($value) && $value instanceof PageFieldValueInterface;
return $this->outputFormatting ? $field->type->formatValue($this, $field, $value) : $value;
if($hasInterface) {
$value->setPage($this);
$value->setField($field);
}
if($this->outputFormatting) {
// output formatting is enabled so return a formatted value
$value = $field->type->formatValue($this, $field, $value);
if($hasInterface) $value->formatted(true);
} else if($hasInterface && $value->formatted()) {
// unformatted requested, and value is already formatted so load a fresh copy
$this->__unset($field->name);
$value = $this->getFieldValue($field->name);
}
return $value;
}
/**
@@ -2570,6 +2610,7 @@ class Page extends WireData implements \Countable, WireMatchable {
*
* @return string Returns page URL, for example: `/my-site/about/contact/`
* @see Page::path(), Page::httpUrl(), Page::editUrl(), Page::localUrl()
* @todo add $options support
*
*/
public function url() {
@@ -3099,7 +3140,7 @@ class Page extends WireData implements \Countable, WireMatchable {
* - `true` (boolean): To return an array of status names (indexed by status number).
* - `integer|string|array`: Status number(s) or status name(s) to set the current page status (same as $page->status = $value)
* @param int|null $status If you specified `true` for first argument, optionally specify status value you want to use (if not the current).
* @return int|array|$this If setting status, `$this` is returned. If getting status: current status or array of status names is returned.
* @return int|array|Page If setting status, `$this` is returned. If getting status: current status or array of status names is returned.
* @see Page::addStauts(), Page::removeStatus(), Page::hasStatus()
*
*/

View File

@@ -21,7 +21,7 @@
* @property-read string $name Returns the filename without the path, same as the "basename" property.
* @property-read string $hash Get a unique hash (for the page) representing this Pagefile.
* @property-read string $tagsArray Get file tags as an array. #pw-group-tags @since 3.0.17
* @property-read int $sort Sort order in database. #pw-group-other
* @property int $sort Sort order in database. #pw-group-other
* @property string $basename Returns the filename without the path.
* @property string $description Value of the files description field (string), if enabled. Note you can also set this property directly.
* @property string $tags Value of the files tags field (string), if enabled. #pw-group-tags
@@ -159,7 +159,7 @@ class Pagefile extends WireData {
*
* @param string $key
* @param mixed $value
* @return $this
* @return Pagefile|WireData
*
*/
public function set($key, $value) {

View File

@@ -50,7 +50,7 @@
*
*/
class Pagefiles extends WireArray {
class Pagefiles extends WireArray implements PageFieldValueInterface {
/**
* The Page object associated with these Pagefiles
@@ -83,6 +83,14 @@ class Pagefiles extends WireArray {
*
*/
protected $hookIDs = array();
/**
* Whether or not this is a formatted value
*
* @var bool
*
*/
protected $formatted = false;
/**
* Construct a Pagefiles object
@@ -161,7 +169,7 @@ class Pagefiles extends WireArray {
*
* #pw-internal
*
* @return WireArray
* @return Pagefiles|WireArray
*
*/
public function makeNew() {
@@ -310,10 +318,13 @@ class Pagefiles extends WireArray {
public function add($item) {
if(is_string($item)) {
/** @var Pagefile $item */
$item = $this->wire(new Pagefile($this, $item));
}
return parent::add($item);
/** @var Pagefiles $result */
$result = parent::add($item);
return $result;
}
/**
@@ -522,10 +533,11 @@ class Pagefiles extends WireArray {
* @return $this
*
*/
public function trackChange($what, $old = null, $new = null) {
if($this->field && $this->page) $this->page->trackChange($this->field->name);
return parent::trackChange($what, $old, $new);
/** @var Pagefiles $result */
$result = parent::trackChange($what, $old, $new);
return $result;
}
/**
@@ -677,13 +689,14 @@ class Pagefiles extends WireArray {
* @return $this
*
*/
public function resetTrackChanges($trackChanges = true) {
$this->unlinkQueue = array();
if($this->page && $this->page->id && $this->field) {
$this->page->untrackChange($this->field->name);
}
return parent::resetTrackChanges($trackChanges);
/** @var Pagefiles $result */
$result = parent::resetTrackChanges($trackChanges);
return $result;
}
/**
@@ -696,6 +709,17 @@ class Pagefiles extends WireArray {
//$this->page = null;
}
/**
* Get or set formatted state
*
* @param bool|null $set
* @return bool
*
*/
public function formatted($set = null) {
if(is_bool($set)) $this->formatted = $set;
return $this->formatted;
}
}

View File

@@ -26,7 +26,7 @@
* ================
* @method PageArray find() find($selectorString, array $options = array()) Find and return all pages matching the given selector string. Returns a PageArray. #pw-group-retrieval
* @method bool save() save(Page $page) Save any changes made to the given $page. Same as : $page->save() Returns true on success. #pw-group-manipulation
* @method bool saveField() saveField(Page $page, $field) Save just the named field from $page. Same as: $page->save('field') #pw-group-manipulation
* @method bool saveField() saveField(Page $page, $field, array $options = array()) Save just the named field from $page. Same as: $page->save('field') #pw-group-manipulation
* @method bool trash() trash(Page $page, $save = true) Move a page to the trash. If you have already set the parent to somewhere in the trash, then this method won't attempt to set it again. #pw-group-manipulation
* @method bool restore(Page $page, $save = true) Restore a trashed page to its original location. #pw-group-manipulation
* @method int emptyTrash() Empty the trash and return number of pages deleted. #pw-group-manipulation
@@ -843,10 +843,11 @@ class Pages extends Wire {
* #pw-internal
*
* @param Page $page
* @return void
*
*/
public function cache(Page $page) {
return $this->cacher->cache($page);
$this->cacher->cache($page);
}
/**
@@ -1141,7 +1142,7 @@ class Pages extends Wire {
*
*/
public function executeQuery(\PDOStatement $query, $throw = true, $maxTries = 3) {
$this->wire('database')->execute($query, $throw, $maxTries);
return $this->wire('database')->execute($query, $throw, $maxTries);
}
/**
@@ -1152,7 +1153,7 @@ class Pages extends Wire {
* When given an array, it calls $pages->getById($key);
*
* @param string|int|array $key
* @return Page|PageArray
* @return Page|Pages|PageArray
*
*/
public function __invoke($key) {
@@ -1262,7 +1263,9 @@ class Pages extends Wire {
$str = "Saved page";
if(count($changes)) $str .= " (Changes: " . implode(', ', $changes) . ")";
$this->log($str, $page);
$this->wire('cache')->maintenance($page);
/** @var WireCache $cache */
$cache = $this->wire('cache');
$cache->maintenance($page);
if($page->className() != 'Page') {
$manager = $page->getPagesManager();
if($manager instanceof PagesType) $manager->saved($page, $changes, $values);
@@ -1395,7 +1398,9 @@ class Pages extends Wire {
*/
public function ___deleted(Page $page) {
$this->log("Deleted page", $page);
$this->wire('cache')->maintenance($page);
/** @var WireCache $cache */
$cache = $this->wire('cache');
$cache->maintenance($page);
if($page->className() != 'Page') {
$manager = $page->getPagesManager();
if($manager instanceof PagesType) $manager->deleted($page);

View File

@@ -66,6 +66,7 @@ class PagesLoaderCache extends Wire {
* Cache the given page.
*
* @param Page $page
* @return void
*
*/
public function cache(Page $page) {