TYPO3 CMS  TYPO3_6-2
AbstractElementView.php
Go to the documentation of this file.
1 <?php
3 
22 abstract class AbstractElementView {
23 
29  protected $model;
30 
34  protected $expectedModelName;
35 
41  protected $elementWrap = '
42  <li>
43  <element />
44  </li>
45  ';
46 
53  protected $noWrap = FALSE;
54 
60  public function __construct(\TYPO3\CMS\Form\Domain\Model\Element\AbstractElement $model) {
61  if ($this->isValidModel($model) === FALSE) {
62  throw new \RuntimeException('Unexpected model "' . get_class($model) . '".');
63  }
64  $this->model = $model;
65  }
66 
73  protected function isValidModel(\TYPO3\CMS\Form\Domain\Model\Element\AbstractElement $model) {
74  return is_a($model, $this->getExpectedModelName($model));
75  }
76 
83  protected function getExpectedModelName(\TYPO3\CMS\Form\Domain\Model\Element\AbstractElement $model) {
84  if (!isset($this->expectedModelName)) {
85  $specificName = \TYPO3\CMS\Form\Utility\FormUtility::getInstance()->getLastPartOfClassName($this);
86  $this->expectedModelName = 'TYPO3\\CMS\\Form\\Domain\\Model\\Element\\' . $specificName . 'Element';
87  }
89  }
90 
101  protected function parseXML(\DOMDocument $dom, \DOMNode $reference) {
102  $node = $reference->firstChild;
103  while (!is_null($node)) {
104  $deleteNode = FALSE;
105  $nodeType = $node->nodeType;
106  $nodeName = $node->nodeName;
107  switch ($nodeType) {
108  case XML_TEXT_NODE:
109  break;
110  case XML_ELEMENT_NODE:
111  switch ($nodeName) {
112  case 'containerWrap':
113  $this->replaceNodeWithFragment($dom, $node, $this->render('containerWrap'));
114  $deleteNode = TRUE;
115  break;
116  case 'elements':
117  $replaceNode = $this->getChildElements($dom);
118  $node->parentNode->replaceChild($replaceNode, $node);
119  break;
120  case 'button':
121 
122  case 'fieldset':
123 
124  case 'form':
125 
126  case 'input':
127 
128  case 'optgroup':
129 
130  case 'select':
131  $this->setAttributes($node);
132  break;
133  case 'label':
134  if (!strrchr(get_class($this), 'AdditionalElement')) {
135  if ($this->model->additionalIsSet($nodeName)) {
136  $this->replaceNodeWithFragment($dom, $node, $this->getAdditional('label'));
137  }
138  $deleteNode = TRUE;
139  } else {
140  if ($this->model->additionalIsSet($nodeName)) {
141  $this->setAttributeWithValueofOtherAttribute($node, 'for', 'id');
142  } else {
143  $deleteNode = TRUE;
144  }
145  }
146  break;
147  case 'legend':
148  if (!strrchr(get_class($this), 'AdditionalElement')) {
149  if ($this->model->additionalIsSet($nodeName)) {
150  $this->replaceNodeWithFragment($dom, $node, $this->getAdditional('legend'));
151  }
152  $deleteNode = TRUE;
153  }
154  break;
155  case 'textarea':
156 
157  case 'option':
158  $this->setAttributes($node);
159  $appendNode = $dom->createTextNode($this->getElementData());
160  $node->appendChild($appendNode);
161  break;
162  case 'errorvalue':
163 
164  case 'labelvalue':
165 
166  case 'legendvalue':
167 
168  case 'mandatoryvalue':
169  $replaceNode = $dom->createTextNode($this->getAdditionalValue());
170  $node->parentNode->insertBefore($replaceNode, $node);
171  $deleteNode = TRUE;
172  break;
173  case 'mandatory':
174 
175  case 'error':
176  if ($this->model->additionalIsSet($nodeName)) {
177  $this->replaceNodeWithFragment($dom, $node, $this->getAdditional($nodeName));
178  }
179  $deleteNode = TRUE;
180  break;
181  case 'content':
182 
183  case 'header':
184 
185  case 'textblock':
186  $replaceNode = $dom->createTextNode($this->getElementData(FALSE));
187  $node->parentNode->insertBefore($replaceNode, $node);
188  $deleteNode = TRUE;
189  break;
190  }
191  break;
192  }
193  // Parse the child nodes of this node if available
194  if ($node->hasChildNodes()) {
195  $this->parseXML($dom, $node);
196  }
197  // Get the current node for deletion if replaced. We need this because nextSibling can be empty
198  $oldNode = $node;
199  // Go to next sibling to parse
200  $node = $node->nextSibling;
201  // Delete the old node. This can only be done after going to the next sibling
202  if ($deleteNode) {
203  $oldNode->parentNode->removeChild($oldNode);
204  }
205  }
206  }
207 
215  public function render($type = 'element', $returnFirstChild = TRUE) {
216  // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept
217  $previousValueOfEntityLoader = libxml_disable_entity_loader(TRUE);
218  $useLayout = $this->getLayout((string) $type);
219  $dom = new \DOMDocument('1.0', 'utf-8');
220  $dom->formatOutput = TRUE;
221  $dom->preserveWhiteSpace = FALSE;
222  $dom->loadXML($useLayout);
223  $this->parseXML($dom, $dom);
224  libxml_disable_entity_loader($previousValueOfEntityLoader);
225  if ($returnFirstChild) {
226  return $dom->firstChild;
227  } else {
228  return $dom;
229  }
230  }
231 
238  public function getLayout($type) {
240  $layoutHandler = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Form\\Layout');
241  switch ($type) {
242  case 'element':
243  $layoutDefault = $this->layout;
244  $objectClass = get_class($this);
245  $type = \TYPO3\CMS\Form\Utility\FormUtility::getInstance()->getLastPartOfClassName($this, TRUE);
246  if (strrchr($objectClass, 'AdditionalElement')) {
247  $additionalModel = $this->model->getAdditionalObjectByKey($type);
248  $layoutOverride = $additionalModel->getLayout();
249  } else {
250  $layoutOverride = $this->model->getLayout();
251  }
252  $layout = $layoutHandler->getLayoutByObject($type, $layoutDefault, $layoutOverride);
253  break;
254  case 'elementWrap':
255  $layoutDefault = $this->elementWrap;
256  $elementWrap = $layoutHandler->getLayoutByObject($type, $layoutDefault, $layoutOverride);
257  $layout = str_replace('<element />', $this->getLayout('element'), $elementWrap);
258  break;
259  case 'containerWrap':
260  $layoutDefault = $this->containerWrap;
261  $layout = $layoutHandler->getLayoutByObject($type, $layoutDefault, $layoutOverride);
262  break;
263  }
264  return $layout;
265  }
266 
275  public function replaceNodeWithFragment(\DOMDocument $dom, \DOMNode $node, \DOMNode $value) {
276  $replaceNode = $dom->createDocumentFragment();
277  $domNode = $dom->importNode($value, TRUE);
278  $replaceNode->appendChild($domNode);
279  $node->parentNode->insertBefore($replaceNode, $node);
280  }
281 
289  public function setAttributes(\DOMElement $domElement) {
290  $attributes = $this->model->getAttributes();
291  foreach ($attributes as $key => $attribute) {
292  if (!empty($attribute)) {
293  $value = htmlspecialchars($attribute->getValue(), ENT_QUOTES);
294  if ($value !== '') {
295  $domElement->setAttribute($key, $value);
296  }
297  }
298  }
299  }
300 
308  public function setAttribute(\DOMElement $domElement, $key) {
309  $value = htmlspecialchars($this->model->getAttributeValue((string) $key), ENT_QUOTES);
310  if ($value !== '') {
311  $domElement->setAttribute($key, $value);
312  }
313  }
314 
324  public function setAttributeWithValueofOtherAttribute(\DOMElement $domElement, $key, $other) {
325  $value = htmlspecialchars($this->model->getAttributeValue((string) $other), ENT_QUOTES);
326  if ($value !== '') {
327  $domElement->setAttribute($key, $value);
328  }
329  }
330 
337  protected function createAdditional($class) {
338  $class = strtolower((string) $class);
339  $className = 'TYPO3\\CMS\\Form\\View\\Form\\Additional\\' . ucfirst($class) . 'AdditionalElementView';
340  return \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance($className, $this->model);
341  }
342 
349  public function getAdditional($key) {
350  $additional = $this->createAdditional($key);
351  return $additional->render();
352  }
353 
362  public function getElementData($encodeSpecialCharacters = TRUE) {
363  $elementData = $this->model->getData();
364  if ($encodeSpecialCharacters) {
365  $elementData = htmlspecialchars($elementData, ENT_QUOTES);
366  }
367  return $elementData;
368  }
369 
376  public function getElementWrapId() {
377  $elementId = (int)$this->model->getElementId();
378  $wrapId = 'csc-form-' . $elementId;
379  return $wrapId;
380  }
381 
388  public function getElementWrapType() {
389  $elementType = strtolower(\TYPO3\CMS\Form\Utility\FormUtility::getInstance()->getLastPartOfClassName($this));
390  $wrapType = 'csc-form-element csc-form-element-' . $elementType;
391  return $wrapType;
392  }
393 
399  public function getElementWraps() {
400  $wraps = array(
401  $this->getElementWrapId(),
402  $this->getElementWrapType()
403  );
404  return implode(' ', $wraps);
405  }
406 
414  public function noWrap() {
415  return $this->noWrap;
416  }
417 
418 }
__construct(\TYPO3\CMS\Form\Domain\Model\Element\AbstractElement $model)
isValidModel(\TYPO3\CMS\Form\Domain\Model\Element\AbstractElement $model)
setAttributeWithValueofOtherAttribute(\DOMElement $domElement, $key, $other)
parseXML(\DOMDocument $dom, \DOMNode $reference)
replaceNodeWithFragment(\DOMDocument $dom, \DOMNode $node, \DOMNode $value)
render($type='element', $returnFirstChild=TRUE)
getExpectedModelName(\TYPO3\CMS\Form\Domain\Model\Element\AbstractElement $model)