Overview

Namespaces

  • None
  • PHP

Classes

  • Breadcrumb
  • Breadcrumbs
  • CacheFile
  • Comment
  • CommentArray
  • CommentFilter
  • CommentForm
  • CommentList
  • Config
  • Database
  • DatabaseQuery
  • DatabaseQuerySelect
  • DatabaseQuerySelectFulltext
  • DatabaseStopwords
  • Debug
  • Field
  • Fieldgroup
  • Fieldgroups
  • FieldgroupsArray
  • Fields
  • FieldsArray
  • Fieldtype
  • FieldtypeMulti
  • Fieldtypes
  • FileLog
  • FilenameArray
  • Fuel
  • HookEvent
  • ImageSizer
  • Inputfield
  • InputfieldsArray
  • InputfieldWrapper
  • Language
  • LanguageParser
  • Languages
  • LanguagesPageFieldValue
  • LanguageSupportInstall
  • LanguageTranslator
  • Markdown_Parser
  • MarkdownExtra_Parser
  • ModuleJS
  • ModulePlaceholder
  • Modules
  • Notice
  • NoticeError
  • NoticeMessage
  • Notices
  • NullPage
  • Page
  • PageArray
  • Pagefile
  • Pagefiles
  • PagefilesManager
  • PageFinder
  • Pageimage
  • Pageimages
  • PagerNav
  • PagerNavItem
  • Pages
  • PagesAccess
  • PagesSortfields
  • PagesType
  • Paths
  • Permission
  • Permissions
  • Process
  • ProcessController
  • ProcessWire
  • Role
  • Roles
  • Sanitizer
  • Selector
  • SelectorBitwiseAnd
  • SelectorContains
  • SelectorContainsLike
  • SelectorContainsWords
  • SelectorEnds
  • SelectorEqual
  • SelectorGreaterThan
  • SelectorGreaterThanEqual
  • SelectorLessThan
  • SelectorLessThanEqual
  • SelectorNotEqual
  • Selectors
  • SelectorStarts
  • Session
  • SessionCSRF
  • SmartyPants_Parser
  • SmartyPantsTypographer_Parser
  • SystemUpdate1
  • Template
  • TemplateFile
  • Templates
  • TemplatesArray
  • Textformatter
  • Textile
  • User
  • Users
  • Wire
  • WireArray
  • WireData
  • WireInput
  • WireInputData
  • WireSaveableItems
  • WireSaveableItemsLookup
  • WireUpload

Interfaces

  • CommentFormInterface
  • CommentListInterface
  • ConfigurableModule
  • FieldtypeLanguageInterface
  • FieldtypePageTitleCompatible
  • HasLookupItems
  • HasRoles
  • InputfieldHasArrayValue
  • Module
  • Saveable
  • TrackChanges

Exceptions

  • ProcessController404Exception
  • ProcessControllerPermissionException
  • Wire404Exception
  • WireDatabaseException
  • WireException
  • WirePermissionException

Functions

  • __
  • _n
  • _x
  • fuel
  • identify_modifier_markdown
  • Markdown
  • mdwp_add_p
  • mdwp_hide_tags
  • mdwp_show_tags
  • mdwp_strip_p
  • ProcessWireClassLoader
  • ProcessWireHostSiteConfig
  • ProcessWireShutdown
  • removeNewlines
  • SmartDashes
  • SmartEllipsis
  • SmartQuotes
  • smarty_modifier_markdown
  • smarty_modifier_smartypants
  • SmartyPants
  • tabIndent
  • unregisterGLOBALS
  • wire
  • wireDecodeJSON
  • wireEncodeJSON
  • wireMkdir
  • Overview
  • Namespace
  • Class
  • Tree
  • Download
  1: <?php
  2: 
  3: /**
  4:  * ProcessWire Field
  5:  *
  6:  * The Field class corresponds to a record in the fields database table 
  7:  * and is managed by the 'Fields' class.
  8:  * 
  9:  * ProcessWire 2.x 
 10:  * Copyright (C) 2010 by Ryan Cramer 
 11:  * Licensed under GNU/GPL v2, see LICENSE.TXT
 12:  * 
 13:  * http://www.processwire.com
 14:  * http://www.ryancramer.com
 15:  *
 16:  */
 17: class Field extends WireData implements Saveable {
 18: 
 19:     /**  
 20:      * Field should be automatically joined to the page at page load time
 21:      *
 22:      */
 23:     const flagAutojoin = 1;     
 24: 
 25:     /** 
 26:      * Field used by all fieldgroups - all fieldgroups required to contain this field
 27:      *
 28:      */
 29:     const flagGlobal = 4;       
 30: 
 31:     /**
 32:      * Field is a system field and may not be deleted, have it's name changed, or be converted to non-system
 33:      *
 34:      */
 35:     const flagSystem = 8; 
 36: 
 37:     /**
 38:      * Field is permanent in any fieldgroups/templates where it exists - it may not be removed from them 
 39:      *
 40:      */
 41:     const flagPermanent = 16; 
 42: 
 43:     /**
 44:      * Field has been placed in a runtime state where it is contextual to a specific fieldgroup and is no longer saveable
 45:      *
 46:      */
 47:     const flagFieldgroupContext = 2048; 
 48: 
 49:     /**
 50:      * Set this flag to override system/permanent flags if necessary - once set, system/permanent flags can be removed, but not in the same set().
 51:      *
 52:      */
 53:     const flagSystemOverride = 32768; 
 54: 
 55:     /**
 56:      * Permanent/native settings to an individual Field
 57:      *
 58:      * id: Numeric ID corresponding with id in the fields table.
 59:      * type: Fieldtype object or NULL if no Fieldtype assigned. 
 60:      * label: String text label corresponding to the <label> field during input. 
 61:      * flags: 
 62:      * - autojoin: True if the field is automatically joined with the page, or False if it's value is loaded separately. 
 63:      * - global: Is this field required by all Fieldgroups?
 64:      *
 65:      */
 66:     protected $settings = array(
 67:         'id' => 0, 
 68:         'type' => null, 
 69:         'flags' => 0, 
 70:         'name' => '', 
 71:         'label' => '', 
 72:         ); 
 73: 
 74:     /**
 75:      * If the field name changed, this is the name of the previous table so that it can be renamed at save time 
 76:      *
 77:      */
 78:     protected $prevTable; 
 79: 
 80:     /**
 81:      * If the field type changed, this is the previous fieldtype so that it can be changed at save time
 82:      *
 83:      */
 84:     protected $prevFieldtype; 
 85: 
 86:     /**
 87:      * True if lowercase tables should be enforce, false if not (null = unset). Cached from $config
 88:      *
 89:      */
 90:     static protected $lowercaseTables = null;
 91: 
 92:     /**
 93:      * Set a native setting or a dynamic data property for this Field
 94:      *
 95:      */
 96:     public function set($key, $value) {
 97: 
 98:         if($key == 'name') return $this->setName($value); 
 99:             else if($key == 'type' && $value) return $this->setFieldtype($value); 
100:             else if($key == 'prevTable') {
101:                 $this->prevTable = $value; 
102:                 return $this; 
103:             } else if($key == 'prevFieldtype') {
104:                 $this->prevFieldtype = $value;
105:                 return $this; 
106:             } else if($key == 'flags') {
107:                 $this->setFlags($value); 
108:                 return $this; 
109:             } else if($key == 'id') {
110:                 $value = (int) $value; 
111:             }
112: 
113:         if(isset($this->settings[$key])) $this->settings[$key] = $value; 
114:             else return parent::set($key, $value); 
115: 
116:         return $this; 
117:     }
118: 
119:     /**
120:      * Set the flags field, ensuring a system flag remains set
121:      *
122:      */
123:     protected function setFlags($value) {
124:         // ensure that the system flag stays set
125:         $value = (int) $value; 
126:         $override = $this->settings['flags'] & Field::flagSystemOverride;
127:         if(!$override) { 
128:             if($this->settings['flags'] & Field::flagSystem) $value = $value | Field::flagSystem;
129:             if($this->settings['flags'] & Field::flagPermanent) $value = $value | Field::flagPermanent; 
130:         }
131:         $this->settings['flags'] = $value;
132:     }
133: 
134:     /**
135:      * Get a Field setting or dynamic data property
136:      *
137:      */
138:     public function get($key) {
139:         if($key == 'table') return $this->getTable();
140:             else if($key == 'prevTable') return $this->prevTable; 
141:             else if($key == 'prevFieldtype') return $this->prevFieldtype; 
142:             else if(isset($this->settings[$key])) return $this->settings[$key]; 
143:         return parent::get($key); 
144:     }
145: 
146:     /**
147:      * Return a key=>value array of the data associated with the database table per Saveable interface
148:      *
149:      * @return array
150:      *
151:      */
152:     public function getTableData() {
153:         $a = $this->settings; 
154:         $a['data'] = $this->data; 
155:         return $a;
156:     }
157: 
158:     /**
159:      * Set the field's name
160:      *
161:      * @param string $name
162:      * @return Field $this
163:      *
164:      */
165:     public function setName($name) {
166:         $name = $this->fuel('sanitizer')->fieldName($name); 
167: 
168:         if(Fields::isNativeName($name)) 
169:             throw new WireException("Field may not be named '$name' because it is a reserved word"); 
170: 
171:         if($this->fuel('fields') && ($f = $this->fuel('fields')->get($name)) && $f->id != $this->id)
172:             throw new WireException("Field may not be named '$name' because it is already used by another field"); 
173: 
174:         if(strpos($name, '__') !== false) 
175:             throw new WireException("Field name '$name' may not have double underscores because this usage is reserved by the core"); 
176: 
177:         if($this->settings['name'] != $name) {
178:             if($this->settings['name'] && ($this->settings['flags'] & Field::flagSystem)) {
179:                 throw new WireException("You may not change the name of field '{$this->settings['name']}' because it is a system field."); 
180:             }
181:             $this->trackChange('name'); 
182:             if($this->settings['name']) $this->prevTable = $this->getTable(); // so that Fields can perform a table rename
183:         }
184: 
185:         $this->settings['name'] = $name; 
186:         return $this; 
187:     }
188: 
189:     /**
190:      * Set what type of field this is. 
191:      *
192:      * Type should be either a Fieldtype object or the string name of a Fieldtype object. 
193:      *
194:      * @param string|Fieldtype $type
195:      * @return Field $this
196:      *
197:      */
198:     public function setFieldtype($type) {
199: 
200:         if(is_object($type) && $type instanceof Fieldtype) {
201:             // good for you
202: 
203:         } else if(is_string($type)) {
204:             $typeStr = $type; 
205:             $fieldtypes = $this->fuel('fieldtypes'); 
206:             if(!$type = $fieldtypes->get($type)) {
207:                 $this->error("Fieldtype '$typeStr' does not exist");
208:                 return $this;
209:             }
210:         } else {
211:             throw new WireException("Invalid field type in call to Field::setFieldType"); 
212:         }
213: 
214:         if(!$this->type || ($this->type->name != $type->name)) {
215:             $this->trackChange("type:{$type->name}"); 
216:             if($this->type) $this->prevFieldtype = $this->type; 
217:         }
218:         $this->settings['type'] = $type; 
219: 
220:         return $this; 
221:     }
222: 
223:     /**
224:      * Save this field's settings and data in the database. 
225:      *
226:      * To hook ___save, use Fields::save instead
227:      *
228:      */
229:     public function save() {
230:         $fields = $this->getFuel('fields'); 
231:         return $fields->save($this); 
232:     }
233: 
234: 
235:     /**
236:      * Return the number of fieldsets this field is used in
237:      *
238:      * Primarily used to check if the Field is deleteable. 
239:      *
240:      */ 
241:     public function numFieldgroups() {
242:         return count($this->getFieldgroups()); 
243:     }
244: 
245:     /**
246:      * Return a FieldgroupArray of Fieldgroups using this field
247:      *
248:      * @return FieldgroupsArray
249:      *
250:      */ 
251:     public function getFieldgroups() {
252:         $fieldgroups = new FieldgroupsArray();
253:         foreach($this->fuel('fieldgroups') as $fieldgroup) {
254:             foreach($fieldgroup as $field) {
255:                 if($field->id == $this->id) {
256:                     $fieldgroups->add($fieldgroup); 
257:                     break;
258:                 }
259:             }
260:         }
261:         return $fieldgroups; 
262:     }
263: 
264:     /**
265:      * Return a TemplatesArray of Templates using this field
266:      *
267:      * @return TemplatesArray
268:      *
269:      */ 
270:     public function getTemplates() {
271:         $templates = new TemplatesArray();
272:         $fieldgroups = $this->getFieldgroups();
273:         foreach($this->templates as $template) {
274:             foreach($fieldgroups as $fieldgroup) {
275:                 if($template->fieldgroups_id == $fieldgroup->id) {
276:                     $templates->add($template); 
277:                     break;
278:                 }
279:             }
280:         }
281:         return $templates; 
282:     }
283: 
284: 
285:     /**
286:      * Return the default value for this field (if set), or null otherwise. 
287:      *
288:      */
289:     public function getDefaultValue() {
290:         $value = $this->get('default'); 
291:         if($value) return $value; 
292:         return null;
293:         
294:     }
295: 
296:     /**
297:      * Get the Inputfield object associated with this Field's Fieldtype
298:      *
299:      * @param Page $page
300:      * @param string $contextStr Optional context string to append to the Inputfield's name/id
301:      * @return Inputfield|null 
302:      *
303:      */
304:     public function ___getInputfield(Page $page, $contextStr = '') {
305: 
306:         if(!$this->type) return null;
307:         $inputfield = $this->type->getInputfield($page, $this);
308:         if(!$inputfield) return null; 
309: 
310:         // predefined field settings
311:         $inputfield->attr('name', $this->name . $contextStr); 
312:         $inputfield->label = $this->label;
313: 
314:         // custom field settings
315:         foreach($this->data as $key => $value) {
316:             if($inputfield->has($key)) {
317:                 $inputfield->set($key, $value); 
318:             }
319:         }
320: 
321:         return $inputfield; 
322:     }
323: 
324:     /**
325:      * Get any configuration fields associated with the Inputfield
326:      *
327:      * @return InputfieldWrapper
328:      *
329:      */
330:     public function ___getConfigInputfields() {
331: 
332:         $wrapper = new InputfieldWrapper();
333:         $fieldgroupContext = $this->flags & Field::flagFieldgroupContext; 
334: 
335:         if(!$fieldgroupContext) {
336:             $inputfields = new InputfieldWrapper;
337:             $inputfields->head = "Field type details";
338:             $inputfields->attr('title', 'Details');
339: 
340:             $fieldtypeInputfields = $this->type->getConfigInputfields($this); 
341:             if($fieldtypeInputfields) foreach($fieldtypeInputfields as $inputfield) {
342:                 $inputfields->append($inputfield); 
343:             }
344: 
345:             if(count($inputfields)) $wrapper->append($inputfields); 
346:         } else {
347:             // we currently exclude fieldtype configuration changes when in fieldgroup context
348:             // not sure that we need to, but keeping it simple to start
349:         }
350: 
351:         $inputfields = new InputfieldWrapper();
352:         $dummyPage = $this->fuel('pages')->get("/"); // only using this to satisfy param requirement 
353: 
354:         if($inputfield = $this->getInputfield($dummyPage)) {
355:             $inputfieldLabel = $inputfield->className(); 
356:             if(!$fieldgroupContext) $inputfields->head = "Input field settings";
357:             $inputfields->attr('title', 'Input'); 
358:             $inputfieldInputfields = $inputfield->getConfigInputfields();
359:             if($inputfieldInputfields) foreach($inputfieldInputfields as $i) { 
360:                 // currently we only support collapsed and columnWidth for fieldgroup context
361:                 // however we may support everything after starting with these limited options for awhile
362:                 if($fieldgroupContext && !in_array($i->name, array('collapsed', 'columnWidth'))) continue; 
363:                 $inputfields->append($i); 
364:             }
365:         }
366: 
367:         $wrapper->append($inputfields); 
368: 
369:         return $wrapper; 
370:     }
371: 
372: 
373:     public function getTable() {
374:         if(is_null(self::$lowercaseTables)) self::$lowercaseTables = $this->config->dbLowercaseTables ? true : false;
375:         $name = $this->settings['name'];
376:         if(self::$lowercaseTables) $name = strtolower($name); 
377:         return "field_" . $name;
378:     }
379: 
380:     /**
381:      * The string value of a Field is always it's name
382:      *
383:      */
384:     public function __toString() {
385:         return $this->settings['name']; 
386:     }
387: 
388:     public function __isset($key) {
389:         if(parent::__isset($key)) return true; 
390:         return isset($this->settings[$key]); 
391:     }
392: 
393:     
394: }
395: 
396: 
ProcessWire API documentation generated by ApiGen 2.6.0