00001 <?php
00002
00003 abstract class spunQ_Field implements spunQ_IField {
00004
00020 public static function normalizeTemplateCssParameter($class) {
00021 if ($class === NULL) {
00022 $class = '';
00023 } elseif (is_array($class)) {
00024 $description = spunQ_Type::getDescription($class);
00025 if ($description !== 'array<string>') {
00026 throw new spunQ_HtmlException('spunQ.html.form.field.UnrecognizedCssDeclaration', $description);
00027 }
00028 $class = implode(' ', $class);
00029 } elseif (!is_string($class)) {
00030 throw new spunQ_HtmlException('spunQ.html.form.field.UnrecognizedCssDeclaration', spunQ_Type::getDescription($class));
00031 }
00032 if (!preg_match('/^[a-z0-9 _-]*$/i', $class)) {
00033 throw new spunQ_HtmlException('spunQ.html.form.field.InvalidCssDeclaration', $class);
00034 }
00035 return $class;
00036 }
00037
00042 protected $name;
00043
00048 protected $container;
00049
00057 protected $useSubmittedValue = true;
00058
00063 protected $converters = array();
00064
00069 protected $validators = array();
00070
00076 protected $validationMessages = NULL;
00077
00083 protected $submittedValue = NULL;
00084
00089 protected $submittedRawValue = NULL;
00090
00097 public function __construct(spunQ_IFieldContainer $container, $name) {
00098 $this->name = $name;
00099 # the $container will call setContainer() on this field,
00100 # which will set $this->container, so there is no need
00101 # to set it manually here.
00102 $container->addField($this);
00103 return NULL;
00104 }
00105
00111 public function setUseSubmittedValue($useSubmittedValue = true) {
00112 $this->useSubmittedValue = $useSubmittedValue;
00113 return $this;
00114 }
00115
00120 public function getForm() {
00121 if ($this->container instanceof spunQ_Form) {
00122 return $this->container;
00123 }
00124 return $this->container->getForm();
00125 }
00126
00133 public function __clone() {
00134 $this->container = NULL;
00135 return NULL;
00136 }
00137
00141 public function getContainer() {
00142 return $this->container;
00143 }
00144
00148 public function setContainer(spunQ_IFieldContainer $container) {
00149 if ($this->container !== NULL) {
00150 $this->container->removeField($this);
00151 }
00152 $this->container = $container;
00153 return $this;
00154 }
00155
00159 public function getName() {
00160 return $this->name;
00161 }
00162
00166 public function getTypePath() {
00167 return $this->container->getTypeString() . '.' . $this->getTypePathPart();
00168 }
00169
00173 public function getTypePathPart() {
00174 return $this->getName();
00175 }
00176
00180 public function addConverter(spunQ_IFieldValueConverter $converter) {
00181 $this->converters[] = $converter;
00182 return $this;
00183 }
00184
00188 public function addValidator(spunQ_IFieldValidator $validator) {
00189 $this->validators[] = $validator;
00190 return $this;
00191 }
00192
00196 public function getConverters() {
00197 return $this->converters;
00198 }
00199
00203 public function getValidators() {
00204 return $this->validators;
00205 }
00206
00210 public function getHtmlId($postfix = '') {
00211 return $this->container->getFieldHtmlId($this, $postfix);
00212 }
00213
00217 public function getHtmlName() {
00218 return $this->container->getFieldHtmlName($this);
00219 }
00220
00224 public function getUseSubmittedValue() {
00225 return $this->useSubmittedValue;
00226 }
00227
00231 public function show($value = NULL, $template = NULL, $templateParameters = array(), $htmlIdPostFix = '') {
00232 if ($template === NULL) {
00233 $template = $this->getDefaultTemplate();
00234 }
00235 $templateParameters['value'] = $this->getDisplayValue($value);
00236 $templateParameters['field'] = $this;
00237 $templateParameters['htmlIdPostFix'] = $htmlIdPostFix;
00238 template($template, $templateParameters);
00239 return $this;
00240 }
00241
00245 public function showValidatorsJs() {
00246 $formTypeName = $this->getForm()->getTypeString();
00247 $typePath = $this->getTypePath();
00248 foreach ($this->validators as $i => $validator) {
00249 if (!$validator->showJsValidationString($typePath, $typePath . '.')) {
00250 echo "spunQ.form.registerValidator('$typePath', spunQ.form.validator.AjaxValidator('$formTypeName', '$typePath', $i));\n";
00251 }
00252 }
00253 return $this;
00254 }
00255
00259 public function submittedValueValid() {
00260 if (!$this->container->wasSubmitted()) {
00261 throw new spunQ_HtmlException('spunQ.html.form.field.NotSubmitted');
00262 }
00263 return count($this->getValidationMessages()) === 0;
00264 }
00265
00269 public function getSubmittedRawValue() {
00270 # calling $container->wasSubmitted() will guarantee that
00271 # _processSubmission() is invoked.
00272 if (!$this->container->wasSubmitted()) {
00273 throw new spunQ_HtmlException('spunQ.html.form.field.NotSubmitted');
00274 }
00275 return $this->submittedRawValue;
00276 }
00277
00281 public function getSubmittedValue() {
00282 # calling $container->wasSubmitted() will guarantee that
00283 # _processSubmission() is invoked.
00284 if (!$this->container->wasSubmitted()) {
00285 throw new spunQ_HtmlException('spunQ.html.form.field.NotSubmitted');
00286 }
00287 return $this->submittedValue;
00288 }
00289
00293 public function getValue() {
00294 return $this->getSubmittedValue();
00295 }
00296
00300 public function getDisplayValue($originalValue) {
00301 if ($this->getUseSubmittedValue() && $this->container->wasSubmitted()) {
00302 return $this->spunQToRaw($this->getSubmittedValue());
00303 }
00304 return $this->spunQToRaw($originalValue);
00305 }
00306
00310 public function getValidationMessages() {
00311 if ($this->validationMessages === NULL) {
00312 # the next call will ensure that _processSubmission() is invoked if
00313 # there is a submitted value for this field, which in turn will set
00314 # $this->validationMessages.
00315 if ($this->container->wasSubmitted()) {
00316 # no submitted value for this field, set validationmessages
00317 # manually
00318 if ($this->validationMessages === NULL) {
00319 $this->validationMessages = array();
00320 }
00321 } else {
00322 $this->validationMessages = array();
00323 }
00324 }
00325 return $this->validationMessages;
00326 }
00327
00331 public function getFieldByPath($path) {
00332 throw new spunQ_HtmlException('spunQ.html.form.FieldDoesNotExist', $this->getTypePath(), implode('.', $path));
00333 }
00334
00338 public function _processSubmission(&$rawValue) {
00339 # Just store relevant values and pass execution to rawToSpunQ().
00340 $this->submittedRawValue = $rawValue;
00341 $this->validationMessages = array();
00342 $result = $this->rawToSpunQ($rawValue);
00343 $this->submittedValue = $rawValue;
00344 return $result;
00345 }
00346
00353 protected function spunQToRaw($value) {
00354 foreach ($this->converters as $converter) {
00355 $value = $converter->convertSpunQToRaw($value);
00356 }
00357 return $value;
00358 }
00359
00366 protected function rawToSpunQ(&$value) {
00367 foreach (array_reverse($this->converters) as $converter) {
00368 $this->validationMessages = $converter->convertRawToSpunQ($this->getTypePath() . '.', $value);
00369 if (!empty($this->validationMessages)) {
00370 vdebug($this->getForm()->getName() . ' not submitted (validation message(s) for field "' . $this->getTypePath() . '": "' . implode('", "', $this->validationMessages) . '")');
00371 return false;
00372 }
00373 }
00374 foreach ($this->validators as $validator) {
00375 $message = $validator->validate($this->getTypePath() . '.', $value);
00376 if ($message !== NULL) {
00377 $this->validationMessages[] = $message;
00378 }
00379 }
00380 if (!empty($this->validationMessages)) {
00381 vdebug($this->getForm()->getName() . ' submitted, but validation for field "' . $this->getTypePath() . '" failed: "' . implode('", "', $this->validationMessages) . '")');
00382 }
00383 return true;
00384 }
00385
00391 protected function getDefaultTemplate() {
00392 return 'spunQ.form.field.text';
00393 }
00394
00395 }