getParentRenderable() !== null) { throw new FormDefinitionConsistencyException(sprintf('The renderable with identifier "%s" is already added to another element (element identifier: "%s").', $renderable->getIdentifier(), $renderable->getParentRenderable()->getIdentifier()), 1325665144); } $renderable->setIndex(count($this->renderables)); $renderable->setParentRenderable($this); $this->renderables[] = $renderable; } /** * Move $renderableToMove before $referenceRenderable * * This function will be wrapped by the subclasses, f.e. with an "movePageBefore" * or "moveElementBefore" method with the correct type hint. * * @param RenderableInterface $renderableToMove * @param RenderableInterface $referenceRenderable * @throws FormDefinitionConsistencyException * @internal */ protected function moveRenderableBefore(RenderableInterface $renderableToMove, RenderableInterface $referenceRenderable) { if ($renderableToMove->getParentRenderable() !== $referenceRenderable->getParentRenderable() || $renderableToMove->getParentRenderable() !== $this) { throw new FormDefinitionConsistencyException('Moved renderables need to be part of the same parent element.', 1326089744); } $reorderedRenderables = []; $i = 0; foreach ($this->renderables as $renderable) { if ($renderable === $renderableToMove) { continue; } if ($renderable === $referenceRenderable) { $reorderedRenderables[] = $renderableToMove; $renderableToMove->setIndex($i); $i++; } $reorderedRenderables[] = $renderable; $renderable->setIndex($i); $i++; } $this->renderables = $reorderedRenderables; } /** * Move $renderableToMove after $referenceRenderable * * This function will be wrapped by the subclasses, f.e. with an "movePageAfter" * or "moveElementAfter" method with the correct type hint. * * @param RenderableInterface $renderableToMove * @param RenderableInterface $referenceRenderable * @throws FormDefinitionConsistencyException * @internal */ protected function moveRenderableAfter(RenderableInterface $renderableToMove, RenderableInterface $referenceRenderable) { if ($renderableToMove->getParentRenderable() !== $referenceRenderable->getParentRenderable() || $renderableToMove->getParentRenderable() !== $this) { throw new FormDefinitionConsistencyException('Moved renderables need to be part of the same parent element.', 1477083145); } $reorderedRenderables = []; $i = 0; foreach ($this->renderables as $renderable) { if ($renderable === $renderableToMove) { continue; } $reorderedRenderables[] = $renderable; $renderable->setIndex($i); $i++; if ($renderable === $referenceRenderable) { $reorderedRenderables[] = $renderableToMove; $renderableToMove->setIndex($i); $i++; } } $this->renderables = $reorderedRenderables; } /** * Returns all RenderableInterface instances of this composite renderable recursively * * @return RenderableInterface[] * @internal */ public function getRenderablesRecursively(): array { $renderables = []; foreach ($this->renderables as $renderable) { $renderables[] = $renderable; if ($renderable instanceof CompositeRenderableInterface) { $renderables = array_merge($renderables, $renderable->getRenderablesRecursively()); } } return $renderables; } /** * Remove a renderable from this renderable. * * This function will be wrapped by the subclasses, f.e. with an "removePage" * or "removeElement" method with the correct type hint. * * @param RenderableInterface $renderableToRemove * @throws FormDefinitionConsistencyException * @internal */ protected function removeRenderable(RenderableInterface $renderableToRemove) { if ($renderableToRemove->getParentRenderable() !== $this) { throw new FormDefinitionConsistencyException('The renderable to be removed must be part of the calling parent renderable.', 1326090127); } $updatedRenderables = []; foreach ($this->renderables as $renderable) { if ($renderable === $renderableToRemove) { continue; } $updatedRenderables[] = $renderable; } $this->renderables = $updatedRenderables; $renderableToRemove->onRemoveFromParentRenderable(); } /** * Register this element at the parent form, if there is a connection to the parent form. * * @internal */ public function registerInFormIfPossible() { parent::registerInFormIfPossible(); foreach ($this->renderables as $renderable) { $renderable->registerInFormIfPossible(); } } /** * This function is called after a renderable has been removed from its parent * renderable. * This just passes the event down to all child renderables of this composite renderable. * * @internal */ public function onRemoveFromParentRenderable() { foreach ($this->renderables as $renderable) { $renderable->onRemoveFromParentRenderable(); } parent::onRemoveFromParentRenderable(); } }