addElement($element, $fontStyle, $paragraphStyle); } } else { // All other elements array_unshift($args, $element); // Prepend element name to the beginning of args array return call_user_func_array([$this, 'addElement'], $args); } } return null; } /** * Add element. * * Each element has different number of parameters passed * * @param string $elementName * * @return \PhpOffice\PhpWord\Element\AbstractElement */ protected function addElement($elementName) { $elementClass = __NAMESPACE__ . '\\' . $elementName; $this->checkValidity($elementName); // Get arguments $args = func_get_args(); $withoutP = in_array($this->container, ['TextRun', 'Footnote', 'Endnote', 'ListItemRun', 'Field']); if ($withoutP && ($elementName == 'Text' || $elementName == 'PreserveText')) { $args[3] = null; // Remove paragraph style for texts in textrun } // Create element using reflection $reflection = new ReflectionClass($elementClass); $elementArgs = $args; array_shift($elementArgs); // Shift the $elementName off the beginning of array /** @var \PhpOffice\PhpWord\Element\AbstractElement $element Type hint */ $element = $reflection->newInstanceArgs($elementArgs); // Set parent container $element->setParentContainer($this); $element->setElementIndex($this->countElements() + 1); $element->setElementId(); $this->elements[] = $element; return $element; } /** * Get all elements. * * @return \PhpOffice\PhpWord\Element\AbstractElement[] */ public function getElements() { return $this->elements; } /** * Returns the element at the requested position. * * @param int $index * * @return null|\PhpOffice\PhpWord\Element\AbstractElement */ public function getElement($index) { if (array_key_exists($index, $this->elements)) { return $this->elements[$index]; } return null; } /** * Removes the element at requested index. * * @param int|\PhpOffice\PhpWord\Element\AbstractElement $toRemove */ public function removeElement($toRemove): void { if (is_int($toRemove) && array_key_exists($toRemove, $this->elements)) { unset($this->elements[$toRemove]); } elseif ($toRemove instanceof \PhpOffice\PhpWord\Element\AbstractElement) { foreach ($this->elements as $key => $element) { if ($element->getElementId() === $toRemove->getElementId()) { unset($this->elements[$key]); return; } } } } /** * Count elements. * * @return int */ public function countElements() { return count($this->elements); } /** * Check if a method is allowed for the current container. * * @param string $method * * @return bool */ private function checkValidity($method) { $generalContainers = [ 'Section', 'Header', 'Footer', 'Footnote', 'Endnote', 'Cell', 'TextRun', 'TextBox', 'ListItemRun', 'TrackChange', ]; $validContainers = [ 'Text' => $generalContainers, 'Bookmark' => $generalContainers, 'Link' => $generalContainers, 'TextBreak' => $generalContainers, 'Image' => $generalContainers, 'OLEObject' => $generalContainers, 'Field' => $generalContainers, 'Line' => $generalContainers, 'Shape' => $generalContainers, 'FormField' => $generalContainers, 'SDT' => $generalContainers, 'TrackChange' => $generalContainers, 'TextRun' => ['Section', 'Header', 'Footer', 'Cell', 'TextBox', 'TrackChange', 'ListItemRun'], 'ListItem' => ['Section', 'Header', 'Footer', 'Cell', 'TextBox'], 'ListItemRun' => ['Section', 'Header', 'Footer', 'Cell', 'TextBox'], 'Table' => ['Section', 'Header', 'Footer', 'Cell', 'TextBox'], 'CheckBox' => ['Section', 'Header', 'Footer', 'Cell', 'TextRun'], 'TextBox' => ['Section', 'Header', 'Footer', 'Cell'], 'Footnote' => ['Section', 'TextRun', 'Cell', 'ListItemRun'], 'Endnote' => ['Section', 'TextRun', 'Cell'], 'PreserveText' => ['Section', 'Header', 'Footer', 'Cell'], 'Title' => ['Section', 'Cell'], 'TOC' => ['Section'], 'PageBreak' => ['Section'], 'Chart' => ['Section', 'Cell'], ]; // Special condition, e.g. preservetext can only exists in cell when // the cell is located in header or footer $validSubcontainers = [ 'PreserveText' => [['Cell'], ['Header', 'Footer', 'Section']], 'Footnote' => [['Cell', 'TextRun'], ['Section']], 'Endnote' => [['Cell', 'TextRun'], ['Section']], ]; // Check if a method is valid for current container if (isset($validContainers[$method])) { if (!in_array($this->container, $validContainers[$method])) { throw new BadMethodCallException("Cannot add {$method} in {$this->container}."); } } // Check if a method is valid for current container, located in other container if (isset($validSubcontainers[$method])) { $rules = $validSubcontainers[$method]; $containers = $rules[0]; $allowedDocParts = $rules[1]; foreach ($containers as $container) { if ($this->container == $container && !in_array($this->getDocPart(), $allowedDocParts)) { throw new BadMethodCallException("Cannot add {$method} in {$this->container}."); } } } return true; } }