Rev 22 | Blame | Compare with Previous | Last modification | View Log | Download
<?php namespace ProcessWire;/*** ProcessWire Text Fieldtype** Basic Field that stores text, typically a single line.** For documentation about the fields used in this class, please see:* /wire/core/Fieldtype.php** ProcessWire 3.x, Copyright 2023 by Ryan Cramer* https://processwire.com***/class FieldtypeText extends Fieldtype {public static function getModuleInfo() {return array('title' => 'Text','version' => 102,'summary' => 'Field that stores a single line of text','permanent' => true,);}/*** Are text formatters allowed for this Fieldtype?** Descending classes can override with the allowTextFormatters(false) method.**/private $allowTextFormatters = true;/*** Provides a way for descending classes to disable text formatters where they aren't applicable** @param bool|null $allow True to allow them, false to disallow or NULL not to do anything* @return bool Current state of $allowTextFormatters**/protected function allowTextFormatters($allow = null) {if(!is_null($allow)) $this->allowTextFormatters = $allow ? true : false;return $this->allowTextFormatters;}/*** Return all Fieldtypes derived from FieldtypeText, which we will consider compatible** @param Field $field* @return Fieldtypes**/public function ___getCompatibleFieldtypes(Field $field) {$fieldtypes = $this->wire(new Fieldtypes());foreach($this->wire()->fieldtypes as $fieldtype) {if($fieldtype instanceof FieldtypeText) {$fieldtypes->add($fieldtype);} else {$className = $fieldtype->className();if($className == 'FieldtypeSelector') $fieldtypes->add($fieldtype);}}return $fieldtypes;}/*** Sanitize value for storage** @param Page $page* @param Field $field* @param string $value* @return string**/public function sanitizeValue(Page $page, Field $field, $value) {return $value;}/*** Format value for output** @param Page $page* @param Field $field* @param string $value* @return string**/public function ___formatValue(Page $page, Field $field, $value) {$value = (string) $value;$textformatters = $field->get('textformatters');if($this->allowTextFormatters() && is_array($textformatters)) {$modules = $this->wire()->modules;foreach($textformatters as $name) {/** @var Textformatter $textformatter */$textformatter = $modules->get($name);if($textformatter) $textformatter->formatValue($page, $field, $value);}}return $value;}/*** Return whether the given value is considered empty or not** This an be anything that might be present in a selector value and thus is* typically a string. However, it may be used outside of that purpose so you* shouldn't count on it being a string.** @param Field $field* @param mixed $value* @return bool**/public function isEmptyValue(Field $field, $value) {return !strlen("$value");}/*** Return the associated Inputfield** @param Page $page* @param Field $field* @return Inputfield**/public function getInputfield(Page $page, Field $field) {$modules = $this->wire()->modules;$inputfieldClass = $field->get('inputfieldClass');/** @var Inputfield $inputfield */$inputfield = $inputfieldClass ? $modules->getModule($inputfieldClass) : null;if(!$inputfield) $inputfield = $modules->get('InputfieldText');return $inputfield;}/*** Update a query to match the text with a fulltext index** @param PageFinderDatabaseQuerySelect $query* @param string $table* @param string $subfield* @param string $operator* @param int|string $value* @return DatabaseQuerySelect**/public function getMatchQuery($query, $table, $subfield, $operator, $value) {$ft = new DatabaseQuerySelectFulltext($query);$ft->match($table, $subfield, $operator, $value);return $query;}/*** Return the database schema in specified format** @param Field $field* @return array**/public function getDatabaseSchema(Field $field) {$schema = parent::getDatabaseSchema($field);$len = $this->wire()->database->getMaxIndexLength();$schema['data'] = 'text NOT NULL';$schema['keys']['data_exact'] = "KEY `data_exact` (`data`($len))";$schema['keys']['data'] = 'FULLTEXT KEY `data` (`data`)';return $schema;}/*** Hook called when field is about to be saved** @param Field $field* @since 3.0.212**/public function ___saveFieldReady(Field $field) {parent::___saveFieldReady($field);if(!$field->id && $this->allowTextFormatters() && $this->wire()->page->process == 'ProcessField') {// default Textformatter for newly created fields in ProcessField$value = $field->get('textformatters');if(!is_array($value) || !count($value)) {$field->set('textformatters', array('TextformatterEntities'));}}}/*** Return the fields required to configure an instance of FieldtypeText** @param Field $field* @return InputfieldWrapper**/public function ___getConfigInputfields(Field $field) {$inputfields = parent::___getConfigInputfields($field);if(!$this->allowTextFormatters()) return $inputfields;$modules = $this->wire()->modules;$textformatters = $modules->findByPrefix('Textformatter');if(!count($textformatters)) return $inputfields;/** @var InputfieldFieldset $fieldset */$fieldset = $modules->get('InputfieldFieldset');$fieldset->attr('name', '_text_fieldset');$fieldset->label = $this->_('Text settings');$fieldset->icon = 'text-width';$inputfields->add($fieldset);/** @var InputfieldAsmSelect $f */$f = $modules->get('InputfieldAsmSelect');$f->attr('name', 'textformatters');$f->label = $this->_('Text formatters');foreach($textformatters as $moduleName) {$info = $modules->getModuleInfo($moduleName);$f->addOption($moduleName, "$info[title]");}$value = $field->get('textformatters');if(!is_array($value)) $value = array();$f->val($value);$f->description =$this->_('If you want to apply any automatic formatting to the field when it is prepared for output, select one or more text formatters here.') . ' ' .$this->_('If you select more than one, drag them into the order they should be applied.') . ' ' .sprintf($this->_('Find more in the [text formatter modules directory](%s).'), 'https://processwire.com/modules/category/textformatter/');$f->notes =$this->_('For plain text fields that will not contain HTML or markup, we recommend selecting the **HTML Entity Encoder** option above.');$fieldset->add($f);if(!in_array('TextformatterEntities', $value) && $this->allowTextformatters() && !$this->wire()->input->is('post')) {// warn user when HTML is allowed and we aren’t sure they intend to allow it$allowHTML = false;if(wireInstanceOf($field->type, 'FieldtypeTextarea')) {$inputType = $field->get('inputfieldClass');$htmlInputTypes = array('InputfieldTinyMCE', 'InputfieldCKEditor');$contentType = $field->get('contentType');$allowHTML = in_array($inputType, $htmlInputTypes) || $contentType >= FieldtypeTextarea::contentTypeHTML;}if(!$allowHTML) {$htmlValue = '<p>HTML</p>';foreach($value as $textformatter) {/** @var Textformatter $textformatter */$textformatter = $modules->get($textformatter);if($textformatter) $textformatter->format($htmlValue);}if(strpos($htmlValue, '<') !== false) $this->warning($this->_('This field currently allows Markup/HTML in formatted output.') . ' ' .$this->_('If you do not intend to allow Markup/HTML, please select the “HTML Entity Encoder” for “Text formatters”.'));}}if($field->type->className() === 'FieldtypeText') {/** @var InputfieldSelect $f */$defaultLabel = $this->_('Default');$f = $modules->get('InputfieldRadios');$f->attr('name', 'inputfieldClass');$f->label = $this->_('Input module');$f->description = $this->_('Save after changing this as it may affect what settings are available on the “Input” tab.');$f->addOption('', $this->_('Text') . " [span.detail] - $defaultLabel [/span]");foreach($modules->findByPrefix('Inputfield', 2) as $moduleName => $moduleInfo) {if($moduleName === 'InputfieldText') continue;if(stripos($moduleName, 'textarea') !== false) continue;if(!wireInstanceOf($moduleName, 'InputfieldHasTextValue')) continue;$f->addOption($moduleName, "$moduleInfo[title] [span.detail] - $moduleInfo[summary] [/span]");}$f->val((string) $field->get('inputfieldClass'));$f->collapsed = Inputfield::collapsedBlank;$fieldset->add($f);}return $inputfields;}/*** Convert an array of exported data to a format that will be understood internally** @param Field $field* @param array $data* @return array Data as given and modified as needed. Also included is $data[errors], an associative array* indexed by property name containing errors that occurred during import of config data.**/public function ___importConfigData(Field $field, array $data) {if(isset($data['textformatters']) && is_array($data['textformatters'])) {$errors = array();foreach($data['textformatters'] as $className) {if(!$this->wire()->modules->isInstalled($className)) {$errors[] = "Requires module '$className' to be installed";}}if(count($errors)) $data['errors']['textformatters'] = implode(" \n", $errors);}return $data;}/*** Import value** @param Page $page* @param Field $field* @param array|int|object|string $value* @param array $options* @return array|string**/public function ___importValue(Page $page, Field $field, $value, array $options = array()) {if(is_array($value) && isset($value['default']) && !$this->wire()->languages) {// multi-language value to non-multi-language site, use only default language$value = $value['default'];}$value = parent::___importValue($page, $field, $value, $options);return $value;}}