registerArgument('as', 'string', ''); $this->registerArgument('accept', 'array', 'Values for the accept attribute', false, []); $this->registerArgument('errorClass', 'string', 'CSS class to set if there are errors for this ViewHelper', false, 'f3-form-error'); $this->registerArgument('multiple', 'boolean', 'Defines the upload element accepting multiple files', false, false); } public function render(): string { $output = ''; $name = $this->getName(); $as = $this->arguments['as']; $accept = $this->arguments['accept']; $multiple = $this->arguments['multiple']; $resource = $this->getUploadedResource(); if (!empty($accept)) { $this->tag->addAttribute('accept', implode(',', $accept)); } if ($resource !== null) { if ($resource instanceof FileReference) { $resourcePointerValue = $resource->getUid() ?? ('file:' . $resource->getOriginalResource()->getOriginalFile()->getUid()); $output .= $this->buildResourcePointerInput( 0, (string)$resourcePointerValue, $this->buildResourcePointerIdAttribute(), ); } elseif ($resource instanceof ObjectStorage) { foreach ($resource as $file) { $index = $resource->getPosition($file); $resourcePointerValue = $file->getUid() ?? ('file:' . $file->getOriginalResource()->getOriginalFile()->getUid()); $output .= $this->buildResourcePointerInput( $index, (string)$resourcePointerValue, $this->buildResourcePointerIdAttribute('-' . $index), ); } } $this->templateVariableContainer->add($as, $resource); $output .= $this->renderChildren(); $this->templateVariableContainer->remove($as); } foreach (['name', 'type', 'tmp_name', 'error', 'size'] as $fieldName) { $this->registerFieldNameForFormTokenGeneration($name . '[' . $fieldName . ']'); } $this->tag->addAttribute('type', 'file'); if ($multiple === true) { $this->tag->addAttribute('name', $name . '[]'); $this->tag->addAttribute('multiple', true); } else { $this->tag->addAttribute('name', $name); } $this->setErrorClassAttribute(); $output .= $this->tag->render(); return $output; } private function buildResourcePointerInput(int $index, string $resourcePointerValue, string $idAttribute): string { $name = htmlspecialchars($this->getName()); $hmac = htmlspecialchars($this->hashService->appendHmac($resourcePointerValue, HashScope::ResourcePointer->prefix())); return ''; } private function buildResourcePointerIdAttribute(string $suffix = ''): string { if (!isset($this->additionalArguments['id'])) { return ''; } return ' id="' . htmlspecialchars($this->additionalArguments['id']) . '-file-reference' . $suffix . '"'; } /** * Return a previously uploaded resource. * Return NULL if errors occurred during property mapping for this property. */ private function getUploadedResource(): FileReference|ObjectStorage|null { if ($this->getMappingResultsForProperty()->hasErrors()) { return null; } $resource = $this->getValueAttribute(); if ($resource instanceof ObjectStorage) { return $resource; } if ($resource instanceof FileReference) { // When multiple uploads are enabled but the stored value is a single // FileReference, wrap it in an ObjectStorage so that the Fluid template's // f:for ViewHelper receives an iterable instead of crashing. if ($this->arguments['multiple']) { $storage = new ObjectStorage(); $storage->attach($resource); return $storage; } return $resource; } return $this->propertyMapper->convert($resource, FileReference::class); } }