ÿØÿà JFIF    ÿÛ „  ( %!1"%)+...383-7(-.+  -%%--------+------------/----------------------------ÿÀ  ¶" ÿÄ     ÿÄ @    !1AQaq‘¡"±ÁÑð2’BRráS‚ñ3b¢CT²Ò #cÿÄ    ÿÄ '   1!AQ2a"‘±#ÿÚ   ? ò(/p‘—–¢·,M|¯G»R£üešT. ôŸEoCFñ‡ 4ÔkåóxR|µÁ¨ÓDà!Ç´µ˜‡p ÍQ‹§!þž^õWsŒy  åÁ§$á«%ºq˜™JyyË0y«^Ϗ -3ÃÏËÈ£Æ\P’ä„s&•‹Üs üô'àWt¹pñCp$bÚF`·7.^)¾!)ÒÙ˜–ÅÏš^h¾ø³·ìe±ŒaeÖ—Í,e=B}Jéߦ$$½—šÙÜCC¯¶è8β–Åkèwx LÉngT±æ¹£Ócœ¿Í/©Éÿ ‰ÚCÒ­mq;Tt¶–}0"zÖPcd1š­¤tˆ„ÐÓâqú[™öUCŠ2޿د­É(¸ßúçšmW,Ò ºf‹Ån™ÄLêÁ8üÁkÁ€L¥ÍuJ1œôrÂSŒÓöt!7EUíïb)AËi¬â-ÙHk8òÁiXYwÅ)O^"ÇØriÛô{»wRUKÙÏÚlÓ¬€‚’שT ] ªb—ÊîKC^×M“xùäñz¬zJ× {4[¹M'IÆeH1LCWÕ]œûº WDæà°OÅ‚¹c²ÞuA–rL`HšpCez‡V’— Ž‚Ë„–ñ­'µR0ÕÖ=À:±G»C\nÆÉ5*¢ †3šhQ4ýÒi$Õ1"Ü]¢p-q3zcQ$ªö¨¥æf›‘»´ÝÚHá„e²JÇ–iÊ:·à¬Øc5Åk»Laª*wi [0Ówk ¦a¦0Õ²ÅÅ‚T¸’³q:Æ<¹ú Ò˜Æ}2VE•Ѐp¡Ô3Úº …h³^LJºçì¥Ánó|˜ÖˆÎˆ+« ¦dø‘Mº–d\ªDðÛ„Ì×LÝ——Ð9Ç|•FèçVm™¨€™3õS–9Äå¢<̉Ìm¢±`·º˜&Z²ž Ë®D«¶»6™‰©­HÈ Àá«h­i³04æ’hxœi3ï¨(ÓL·†‹¶ËpŒ ƒÜÒ? :õdsÀ –3æÓ·Üjâ¬9—]8n¼&]I F£¼…ì–—Œ0v°LǐÅfÛ2TÖ’aµ˜N@ÖBSÏ^à´4-±°b×nÈÈœÆD=KdŒø…ÄÈK,›ÖR§fjü$^ÔÎ!„6^ s:Üun\ôkCÞò÷<—Lúl Í›G¹ÀPá¼Nc¡šÒ…ÙWͳœ±vÊáЄ×9‹P‰cEØ‘™›µŸP<×g1 º©Ø¬wiÁ^l5× I/';Ë+´Z‡ÓÄFÕp[Èð’ HÄ ó 9¬Dl4“é±Ï”V=^Hð;žLädÉa‚°Ë,#/Ž~²BÔÛ QãñQtIeórVB,ÏÂf‹4#Μc‹É3ZIÖ Œ¢¥·üxa‡Ãçè„jŠ[5 Ä!U?,3žÎ×…ðdÓ÷háŠA‰ìÄ4÷ÃÜZÃE{‰®+W\ZÍE[‰»µk»MÝ­`¢©†˜ÃV‹-f¢¡†¢a«eŠ%«Y¨©q%jâd,Ôq`) ¤¦…šˆ ¦E>0Ùb²t–Ÿ  ÷jsςҒKÈcø(é›;k(’#ôŒQ ™C> õ³M9óºÆµ¤çâ;uÀ)5>RÔ¸fÓ~Ȧ—’-$fe«"FâUˆÊwµPÏu w+"åÉó¨6s™Û9(À¨ù©hE°½†n`m~“@©›p!Vkhµ Á1šbEqqÊ@ºèl›2 –Yã%‘‚hÛ{a¶‡ÅÞM²¬çL34®Çl]®‹ŽØŒm'RÜe35æöˆ­Á­ cP9šeÁköo´L³Ì=p8]”‡B¶,šº|ɏdzXˆØk*ÇÚ{#ñ‰pã(€¶‡9ý'šÜ³½¯kƒ†Â’ëSOƒ•Å®H6+a¢µˆ‹Y¨b˜b+XˆÖ!°u!¢"µˆˆn2ˆ Å0Ä`Å Ô®c(ÓÜGº•Ä»Œ âWî%q.áÐÄ÷î%umÍ£+ÜQ,Vn¦-GphU¸¢X­&,Gt ·K¢ÅÅ·¥RÄÊÉbKn N­R2g$VµÕó Qr#–ÓZUÏð0ÎtÙÀœz ëöo“Îk¯n„T°"SÞ+³/…€½"ižãO%Í%&Δâ‘ËØ´IˆÓ°Ë‰ÞM3.™yçÁzit›`4C`k¢¼á!álÄï sÂ[×!¤l¾æo"ƒIÔ'@ªu)3›ô®“@Z à¾] üœ'‡4¸PÞkÁ-qÄH‰ÓÍBd´ÿ —¹°ÄA&ÊUC„öz‚‚RæŠtf¬>˜ÑidšEçÑL÷áý¡V±h§­c¿¥¨ƒ@g¼…Ýö^ÞËc.ž„æ“I[ ª+·zÐÒÚ,½Ð»¶€C›7jk$๖€Ž¾ÅÙpp¶ÍþéΤ ½ØÎŒq ñpæžÅ¥#Øâ49ÃÂK^MYV“,¶Éz_òæ:…;Õ«¦I3âJ£¤û5$7Èxün\â]Êe¯(Ÿ&Ž‹¶2<6Ćf× æ¢ƱqWı[(ÙÂŽç‚T7¨@ÈÉÍß‚ïÙ"&3TYlGށ†)†#5ŠA©^T2ÆÁ†)©†©†¤yGXÁ†©"†)©¼ÅV WS†#©]R–r‹q5ÕbâWþBh¯u+ªÅÄ×ü„nÑ^êkªÁj‰jeœWˆÕÕ`µDµ2Ì+Ä µDµµ5Ô{¤Þ0RF’H÷AÛ<ÊÁ§ ƈæ0Ñ£ê4 öÚµ[¬/1²€â<-¬šö²r×0o×w ´xÐÒË„ g01¬„åEM蛇Ã\6µE›‘fÙO k÷CºnÓ1`iîÒ² áÂ!ÑLÄÿ ³¬\õ*:M=Ç»c‹2[‰ØsÕLò\ŒK L^™üÄN\¶#» Ç\……ßïIœÉ$¸ÎñÍ®ÔHÇ Ûí/´>Li”„†g^$ 7NÍÑÑ2M2ªNg=k½Ð}Ÿl6‡ —JWˆ”ÞéT·+µ¦üÂFè¢Vs6ýÆ4»2+2IÝ9ô9®ÇGÙÇ1+Ä8;*Õ§ž½D*îÑWÚçá3Ma¤·ˆ¥t}š²Ü…Q+Æüµ8HíS”üxGéÁˆ¦Ël„éÈ 5 µÄƒ6äÜ(kIš¯S†fÖ&¸®×v|Äyˆ*禌Éù@7-®Ä[]ÎÖ¿ê`º…=:…žJVnݳvðÖKE¼‚ »mà ÷f®:Ë ™–4rð¡4` ܹçž~‹C=œ…¾Ïj|VDtK.ƒ"9 Ï ­–éXá³6WÒïIL-Ї Ç home/smkb8269/public_html/wa.smk-almanshuriyah.sch.id/vendor/symfony/console/Helper/Table.php000064400000071766152267376070026157 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Helper; use Symfony\Component\Console\Exception\InvalidArgumentException; use Symfony\Component\Console\Exception\RuntimeException; use Symfony\Component\Console\Formatter\OutputFormatter; use Symfony\Component\Console\Formatter\WrappableOutputFormatterInterface; use Symfony\Component\Console\Output\ConsoleSectionOutput; use Symfony\Component\Console\Output\OutputInterface; /** * Provides helpers to display a table. * * @author Fabien Potencier * @author Саша Стаменковић * @author Abdellatif Ait boudad * @author Max Grigorian * @author Dany Maillard */ class Table { private const SEPARATOR_TOP = 0; private const SEPARATOR_TOP_BOTTOM = 1; private const SEPARATOR_MID = 2; private const SEPARATOR_BOTTOM = 3; private const BORDER_OUTSIDE = 0; private const BORDER_INSIDE = 1; private $headerTitle; private $footerTitle; /** * Table headers. */ private $headers = []; /** * Table rows. */ private $rows = []; private $horizontal = false; /** * Column widths cache. */ private $effectiveColumnWidths = []; /** * Number of columns cache. * * @var int */ private $numberOfColumns; /** * @var OutputInterface */ private $output; /** * @var TableStyle */ private $style; /** * @var array */ private $columnStyles = []; /** * User set column widths. * * @var array */ private $columnWidths = []; private $columnMaxWidths = []; /** * @var array|null */ private static $styles; private $rendered = false; public function __construct(OutputInterface $output) { $this->output = $output; if (!self::$styles) { self::$styles = self::initStyles(); } $this->setStyle('default'); } /** * Sets a style definition. */ public static function setStyleDefinition(string $name, TableStyle $style) { if (!self::$styles) { self::$styles = self::initStyles(); } self::$styles[$name] = $style; } /** * Gets a style definition by name. * * @return TableStyle */ public static function getStyleDefinition(string $name) { if (!self::$styles) { self::$styles = self::initStyles(); } if (isset(self::$styles[$name])) { return self::$styles[$name]; } throw new InvalidArgumentException(sprintf('Style "%s" is not defined.', $name)); } /** * Sets table style. * * @param TableStyle|string $name The style name or a TableStyle instance * * @return $this */ public function setStyle($name) { $this->style = $this->resolveStyle($name); return $this; } /** * Gets the current table style. * * @return TableStyle */ public function getStyle() { return $this->style; } /** * Sets table column style. * * @param TableStyle|string $name The style name or a TableStyle instance * * @return $this */ public function setColumnStyle(int $columnIndex, $name) { $this->columnStyles[$columnIndex] = $this->resolveStyle($name); return $this; } /** * Gets the current style for a column. * * If style was not set, it returns the global table style. * * @return TableStyle */ public function getColumnStyle(int $columnIndex) { return $this->columnStyles[$columnIndex] ?? $this->getStyle(); } /** * Sets the minimum width of a column. * * @return $this */ public function setColumnWidth(int $columnIndex, int $width) { $this->columnWidths[$columnIndex] = $width; return $this; } /** * Sets the minimum width of all columns. * * @return $this */ public function setColumnWidths(array $widths) { $this->columnWidths = []; foreach ($widths as $index => $width) { $this->setColumnWidth($index, $width); } return $this; } /** * Sets the maximum width of a column. * * Any cell within this column which contents exceeds the specified width will be wrapped into multiple lines, while * formatted strings are preserved. * * @return $this */ public function setColumnMaxWidth(int $columnIndex, int $width): self { if (!$this->output->getFormatter() instanceof WrappableOutputFormatterInterface) { throw new \LogicException(sprintf('Setting a maximum column width is only supported when using a "%s" formatter, got "%s".', WrappableOutputFormatterInterface::class, get_debug_type($this->output->getFormatter()))); } $this->columnMaxWidths[$columnIndex] = $width; return $this; } /** * @return $this */ public function setHeaders(array $headers) { $headers = array_values($headers); if (!empty($headers) && !\is_array($headers[0])) { $headers = [$headers]; } $this->headers = $headers; return $this; } public function setRows(array $rows) { $this->rows = []; return $this->addRows($rows); } /** * @return $this */ public function addRows(array $rows) { foreach ($rows as $row) { $this->addRow($row); } return $this; } /** * @return $this */ public function addRow($row) { if ($row instanceof TableSeparator) { $this->rows[] = $row; return $this; } if (!\is_array($row)) { throw new InvalidArgumentException('A row must be an array or a TableSeparator instance.'); } $this->rows[] = array_values($row); return $this; } /** * Adds a row to the table, and re-renders the table. * * @return $this */ public function appendRow($row): self { if (!$this->output instanceof ConsoleSectionOutput) { throw new RuntimeException(sprintf('Output should be an instance of "%s" when calling "%s".', ConsoleSectionOutput::class, __METHOD__)); } if ($this->rendered) { $this->output->clear($this->calculateRowCount()); } $this->addRow($row); $this->render(); return $this; } /** * @return $this */ public function setRow($column, array $row) { $this->rows[$column] = $row; return $this; } /** * @return $this */ public function setHeaderTitle(?string $title): self { $this->headerTitle = $title; return $this; } /** * @return $this */ public function setFooterTitle(?string $title): self { $this->footerTitle = $title; return $this; } /** * @return $this */ public function setHorizontal(bool $horizontal = true): self { $this->horizontal = $horizontal; return $this; } /** * Renders table to output. * * Example: * * +---------------+-----------------------+------------------+ * | ISBN | Title | Author | * +---------------+-----------------------+------------------+ * | 99921-58-10-7 | Divine Comedy | Dante Alighieri | * | 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens | * | 960-425-059-0 | The Lord of the Rings | J. R. R. Tolkien | * +---------------+-----------------------+------------------+ */ public function render() { $divider = new TableSeparator(); if ($this->horizontal) { $rows = []; foreach ($this->headers[0] ?? [] as $i => $header) { $rows[$i] = [$header]; foreach ($this->rows as $row) { if ($row instanceof TableSeparator) { continue; } if (isset($row[$i])) { $rows[$i][] = $row[$i]; } elseif ($rows[$i][0] instanceof TableCell && $rows[$i][0]->getColspan() >= 2) { // Noop, there is a "title" } else { $rows[$i][] = null; } } } } else { $rows = array_merge($this->headers, [$divider], $this->rows); } $this->calculateNumberOfColumns($rows); $rowGroups = $this->buildTableRows($rows); $this->calculateColumnsWidth($rowGroups); $isHeader = !$this->horizontal; $isFirstRow = $this->horizontal; $hasTitle = (bool) $this->headerTitle; foreach ($rowGroups as $rowGroup) { $isHeaderSeparatorRendered = false; foreach ($rowGroup as $row) { if ($divider === $row) { $isHeader = false; $isFirstRow = true; continue; } if ($row instanceof TableSeparator) { $this->renderRowSeparator(); continue; } if (!$row) { continue; } if ($isHeader && !$isHeaderSeparatorRendered) { $this->renderRowSeparator( $isHeader ? self::SEPARATOR_TOP : self::SEPARATOR_TOP_BOTTOM, $hasTitle ? $this->headerTitle : null, $hasTitle ? $this->style->getHeaderTitleFormat() : null ); $hasTitle = false; $isHeaderSeparatorRendered = true; } if ($isFirstRow) { $this->renderRowSeparator( $isHeader ? self::SEPARATOR_TOP : self::SEPARATOR_TOP_BOTTOM, $hasTitle ? $this->headerTitle : null, $hasTitle ? $this->style->getHeaderTitleFormat() : null ); $isFirstRow = false; $hasTitle = false; } if ($this->horizontal) { $this->renderRow($row, $this->style->getCellRowFormat(), $this->style->getCellHeaderFormat()); } else { $this->renderRow($row, $isHeader ? $this->style->getCellHeaderFormat() : $this->style->getCellRowFormat()); } } } $this->renderRowSeparator(self::SEPARATOR_BOTTOM, $this->footerTitle, $this->style->getFooterTitleFormat()); $this->cleanup(); $this->rendered = true; } /** * Renders horizontal header separator. * * Example: * * +-----+-----------+-------+ */ private function renderRowSeparator(int $type = self::SEPARATOR_MID, string $title = null, string $titleFormat = null) { if (0 === $count = $this->numberOfColumns) { return; } $borders = $this->style->getBorderChars(); if (!$borders[0] && !$borders[2] && !$this->style->getCrossingChar()) { return; } $crossings = $this->style->getCrossingChars(); if (self::SEPARATOR_MID === $type) { [$horizontal, $leftChar, $midChar, $rightChar] = [$borders[2], $crossings[8], $crossings[0], $crossings[4]]; } elseif (self::SEPARATOR_TOP === $type) { [$horizontal, $leftChar, $midChar, $rightChar] = [$borders[0], $crossings[1], $crossings[2], $crossings[3]]; } elseif (self::SEPARATOR_TOP_BOTTOM === $type) { [$horizontal, $leftChar, $midChar, $rightChar] = [$borders[0], $crossings[9], $crossings[10], $crossings[11]]; } else { [$horizontal, $leftChar, $midChar, $rightChar] = [$borders[0], $crossings[7], $crossings[6], $crossings[5]]; } $markup = $leftChar; for ($column = 0; $column < $count; ++$column) { $markup .= str_repeat($horizontal, $this->effectiveColumnWidths[$column]); $markup .= $column === $count - 1 ? $rightChar : $midChar; } if (null !== $title) { $titleLength = Helper::width(Helper::removeDecoration($formatter = $this->output->getFormatter(), $formattedTitle = sprintf($titleFormat, $title))); $markupLength = Helper::width($markup); if ($titleLength > $limit = $markupLength - 4) { $titleLength = $limit; $formatLength = Helper::width(Helper::removeDecoration($formatter, sprintf($titleFormat, ''))); $formattedTitle = sprintf($titleFormat, Helper::substr($title, 0, $limit - $formatLength - 3).'...'); } $titleStart = intdiv($markupLength - $titleLength, 2); if (false === mb_detect_encoding($markup, null, true)) { $markup = substr_replace($markup, $formattedTitle, $titleStart, $titleLength); } else { $markup = mb_substr($markup, 0, $titleStart).$formattedTitle.mb_substr($markup, $titleStart + $titleLength); } } $this->output->writeln(sprintf($this->style->getBorderFormat(), $markup)); } /** * Renders vertical column separator. */ private function renderColumnSeparator(int $type = self::BORDER_OUTSIDE): string { $borders = $this->style->getBorderChars(); return sprintf($this->style->getBorderFormat(), self::BORDER_OUTSIDE === $type ? $borders[1] : $borders[3]); } /** * Renders table row. * * Example: * * | 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens | */ private function renderRow(array $row, string $cellFormat, string $firstCellFormat = null) { $rowContent = $this->renderColumnSeparator(self::BORDER_OUTSIDE); $columns = $this->getRowColumns($row); $last = \count($columns) - 1; foreach ($columns as $i => $column) { if ($firstCellFormat && 0 === $i) { $rowContent .= $this->renderCell($row, $column, $firstCellFormat); } else { $rowContent .= $this->renderCell($row, $column, $cellFormat); } $rowContent .= $this->renderColumnSeparator($last === $i ? self::BORDER_OUTSIDE : self::BORDER_INSIDE); } $this->output->writeln($rowContent); } /** * Renders table cell with padding. */ private function renderCell(array $row, int $column, string $cellFormat): string { $cell = $row[$column] ?? ''; $width = $this->effectiveColumnWidths[$column]; if ($cell instanceof TableCell && $cell->getColspan() > 1) { // add the width of the following columns(numbers of colspan). foreach (range($column + 1, $column + $cell->getColspan() - 1) as $nextColumn) { $width += $this->getColumnSeparatorWidth() + $this->effectiveColumnWidths[$nextColumn]; } } // str_pad won't work properly with multi-byte strings, we need to fix the padding if (false !== $encoding = mb_detect_encoding($cell, null, true)) { $width += \strlen($cell) - mb_strwidth($cell, $encoding); } $style = $this->getColumnStyle($column); if ($cell instanceof TableSeparator) { return sprintf($style->getBorderFormat(), str_repeat($style->getBorderChars()[2], $width)); } $width += Helper::length($cell) - Helper::length(Helper::removeDecoration($this->output->getFormatter(), $cell)); $content = sprintf($style->getCellRowContentFormat(), $cell); $padType = $style->getPadType(); if ($cell instanceof TableCell && $cell->getStyle() instanceof TableCellStyle) { $isNotStyledByTag = !preg_match('/^<(\w+|(\w+=[\w,]+;?)*)>.+<\/(\w+|(\w+=\w+;?)*)?>$/', $cell); if ($isNotStyledByTag) { $cellFormat = $cell->getStyle()->getCellFormat(); if (!\is_string($cellFormat)) { $tag = http_build_query($cell->getStyle()->getTagOptions(), '', ';'); $cellFormat = '<'.$tag.'>%s'; } if (strstr($content, '')) { $content = str_replace('', '', $content); $width -= 3; } if (strstr($content, '')) { $content = str_replace('', '', $content); $width -= \strlen(''); } } $padType = $cell->getStyle()->getPadByAlign(); } return sprintf($cellFormat, str_pad($content, $width, $style->getPaddingChar(), $padType)); } /** * Calculate number of columns for this table. */ private function calculateNumberOfColumns(array $rows) { $columns = [0]; foreach ($rows as $row) { if ($row instanceof TableSeparator) { continue; } $columns[] = $this->getNumberOfColumns($row); } $this->numberOfColumns = max($columns); } private function buildTableRows(array $rows): TableRows { /** @var WrappableOutputFormatterInterface $formatter */ $formatter = $this->output->getFormatter(); $unmergedRows = []; for ($rowKey = 0; $rowKey < \count($rows); ++$rowKey) { $rows = $this->fillNextRows($rows, $rowKey); // Remove any new line breaks and replace it with a new line foreach ($rows[$rowKey] as $column => $cell) { $colspan = $cell instanceof TableCell ? $cell->getColspan() : 1; if (isset($this->columnMaxWidths[$column]) && Helper::width(Helper::removeDecoration($formatter, $cell)) > $this->columnMaxWidths[$column]) { $cell = $formatter->formatAndWrap($cell, $this->columnMaxWidths[$column] * $colspan); } if (!strstr($cell ?? '', "\n")) { continue; } $escaped = implode("\n", array_map([OutputFormatter::class, 'escapeTrailingBackslash'], explode("\n", $cell))); $cell = $cell instanceof TableCell ? new TableCell($escaped, ['colspan' => $cell->getColspan()]) : $escaped; $lines = explode("\n", str_replace("\n", "\n", $cell)); foreach ($lines as $lineKey => $line) { if ($colspan > 1) { $line = new TableCell($line, ['colspan' => $colspan]); } if (0 === $lineKey) { $rows[$rowKey][$column] = $line; } else { if (!\array_key_exists($rowKey, $unmergedRows) || !\array_key_exists($lineKey, $unmergedRows[$rowKey])) { $unmergedRows[$rowKey][$lineKey] = $this->copyRow($rows, $rowKey); } $unmergedRows[$rowKey][$lineKey][$column] = $line; } } } } return new TableRows(function () use ($rows, $unmergedRows): \Traversable { foreach ($rows as $rowKey => $row) { $rowGroup = [$row instanceof TableSeparator ? $row : $this->fillCells($row)]; if (isset($unmergedRows[$rowKey])) { foreach ($unmergedRows[$rowKey] as $row) { $rowGroup[] = $row instanceof TableSeparator ? $row : $this->fillCells($row); } } yield $rowGroup; } }); } private function calculateRowCount(): int { $numberOfRows = \count(iterator_to_array($this->buildTableRows(array_merge($this->headers, [new TableSeparator()], $this->rows)))); if ($this->headers) { ++$numberOfRows; // Add row for header separator } if (\count($this->rows) > 0) { ++$numberOfRows; // Add row for footer separator } return $numberOfRows; } /** * fill rows that contains rowspan > 1. * * @throws InvalidArgumentException */ private function fillNextRows(array $rows, int $line): array { $unmergedRows = []; foreach ($rows[$line] as $column => $cell) { if (null !== $cell && !$cell instanceof TableCell && !\is_scalar($cell) && !(\is_object($cell) && method_exists($cell, '__toString'))) { throw new InvalidArgumentException(sprintf('A cell must be a TableCell, a scalar or an object implementing "__toString()", "%s" given.', get_debug_type($cell))); } if ($cell instanceof TableCell && $cell->getRowspan() > 1) { $nbLines = $cell->getRowspan() - 1; $lines = [$cell]; if (strstr($cell, "\n")) { $lines = explode("\n", str_replace("\n", "\n", $cell)); $nbLines = \count($lines) > $nbLines ? substr_count($cell, "\n") : $nbLines; $rows[$line][$column] = new TableCell($lines[0], ['colspan' => $cell->getColspan(), 'style' => $cell->getStyle()]); unset($lines[0]); } // create a two dimensional array (rowspan x colspan) $unmergedRows = array_replace_recursive(array_fill($line + 1, $nbLines, []), $unmergedRows); foreach ($unmergedRows as $unmergedRowKey => $unmergedRow) { $value = $lines[$unmergedRowKey - $line] ?? ''; $unmergedRows[$unmergedRowKey][$column] = new TableCell($value, ['colspan' => $cell->getColspan(), 'style' => $cell->getStyle()]); if ($nbLines === $unmergedRowKey - $line) { break; } } } } foreach ($unmergedRows as $unmergedRowKey => $unmergedRow) { // we need to know if $unmergedRow will be merged or inserted into $rows if (isset($rows[$unmergedRowKey]) && \is_array($rows[$unmergedRowKey]) && ($this->getNumberOfColumns($rows[$unmergedRowKey]) + $this->getNumberOfColumns($unmergedRows[$unmergedRowKey]) <= $this->numberOfColumns)) { foreach ($unmergedRow as $cellKey => $cell) { // insert cell into row at cellKey position array_splice($rows[$unmergedRowKey], $cellKey, 0, [$cell]); } } else { $row = $this->copyRow($rows, $unmergedRowKey - 1); foreach ($unmergedRow as $column => $cell) { if (!empty($cell)) { $row[$column] = $unmergedRow[$column]; } } array_splice($rows, $unmergedRowKey, 0, [$row]); } } return $rows; } /** * fill cells for a row that contains colspan > 1. */ private function fillCells(iterable $row) { $newRow = []; foreach ($row as $column => $cell) { $newRow[] = $cell; if ($cell instanceof TableCell && $cell->getColspan() > 1) { foreach (range($column + 1, $column + $cell->getColspan() - 1) as $position) { // insert empty value at column position $newRow[] = ''; } } } return $newRow ?: $row; } private function copyRow(array $rows, int $line): array { $row = $rows[$line]; foreach ($row as $cellKey => $cellValue) { $row[$cellKey] = ''; if ($cellValue instanceof TableCell) { $row[$cellKey] = new TableCell('', ['colspan' => $cellValue->getColspan()]); } } return $row; } /** * Gets number of columns by row. */ private function getNumberOfColumns(array $row): int { $columns = \count($row); foreach ($row as $column) { $columns += $column instanceof TableCell ? ($column->getColspan() - 1) : 0; } return $columns; } /** * Gets list of columns for the given row. */ private function getRowColumns(array $row): array { $columns = range(0, $this->numberOfColumns - 1); foreach ($row as $cellKey => $cell) { if ($cell instanceof TableCell && $cell->getColspan() > 1) { // exclude grouped columns. $columns = array_diff($columns, range($cellKey + 1, $cellKey + $cell->getColspan() - 1)); } } return $columns; } /** * Calculates columns widths. */ private function calculateColumnsWidth(iterable $groups) { for ($column = 0; $column < $this->numberOfColumns; ++$column) { $lengths = []; foreach ($groups as $group) { foreach ($group as $row) { if ($row instanceof TableSeparator) { continue; } foreach ($row as $i => $cell) { if ($cell instanceof TableCell) { $textContent = Helper::removeDecoration($this->output->getFormatter(), $cell); $textLength = Helper::width($textContent); if ($textLength > 0) { $contentColumns = str_split($textContent, ceil($textLength / $cell->getColspan())); foreach ($contentColumns as $position => $content) { $row[$i + $position] = $content; } } } } $lengths[] = $this->getCellWidth($row, $column); } } $this->effectiveColumnWidths[$column] = max($lengths) + Helper::width($this->style->getCellRowContentFormat()) - 2; } } private function getColumnSeparatorWidth(): int { return Helper::width(sprintf($this->style->getBorderFormat(), $this->style->getBorderChars()[3])); } private function getCellWidth(array $row, int $column): int { $cellWidth = 0; if (isset($row[$column])) { $cell = $row[$column]; $cellWidth = Helper::width(Helper::removeDecoration($this->output->getFormatter(), $cell)); } $columnWidth = $this->columnWidths[$column] ?? 0; $cellWidth = max($cellWidth, $columnWidth); return isset($this->columnMaxWidths[$column]) ? min($this->columnMaxWidths[$column], $cellWidth) : $cellWidth; } /** * Called after rendering to cleanup cache data. */ private function cleanup() { $this->effectiveColumnWidths = []; $this->numberOfColumns = null; } /** * @return array */ private static function initStyles(): array { $borderless = new TableStyle(); $borderless ->setHorizontalBorderChars('=') ->setVerticalBorderChars(' ') ->setDefaultCrossingChar(' ') ; $compact = new TableStyle(); $compact ->setHorizontalBorderChars('') ->setVerticalBorderChars('') ->setDefaultCrossingChar('') ->setCellRowContentFormat('%s ') ; $styleGuide = new TableStyle(); $styleGuide ->setHorizontalBorderChars('-') ->setVerticalBorderChars(' ') ->setDefaultCrossingChar(' ') ->setCellHeaderFormat('%s') ; $box = (new TableStyle()) ->setHorizontalBorderChars('─') ->setVerticalBorderChars('│') ->setCrossingChars('┼', '┌', '┬', '┐', '┤', '┘', '┴', '└', '├') ; $boxDouble = (new TableStyle()) ->setHorizontalBorderChars('═', '─') ->setVerticalBorderChars('║', '│') ->setCrossingChars('┼', '╔', '╤', '╗', '╢', '╝', '╧', '╚', '╟', '╠', '╪', '╣') ; return [ 'default' => new TableStyle(), 'borderless' => $borderless, 'compact' => $compact, 'symfony-style-guide' => $styleGuide, 'box' => $box, 'box-double' => $boxDouble, ]; } private function resolveStyle($name): TableStyle { if ($name instanceof TableStyle) { return $name; } if (isset(self::$styles[$name])) { return self::$styles[$name]; } throw new InvalidArgumentException(sprintf('Style "%s" is not defined.', $name)); } } home/smkb8269/public_html/test.smk-almanshuriyah.sch.id/system/libraries/Table.php000064400000030051152267741220024114 0ustar00 $val) { $this->template[$key] = $val; } log_message('info', 'Table Class Initialized'); } // -------------------------------------------------------------------- /** * Set the template * * @param array $template * @return bool */ public function set_template($template) { if ( ! is_array($template)) { return FALSE; } $this->template = $template; return TRUE; } // -------------------------------------------------------------------- /** * Set the table heading * * Can be passed as an array or discreet params * * @param mixed * @return CI_Table */ public function set_heading($args = array()) { $this->heading = $this->_prep_args(func_get_args()); return $this; } // -------------------------------------------------------------------- /** * Set columns. Takes a one-dimensional array as input and creates * a multi-dimensional array with a depth equal to the number of * columns. This allows a single array with many elements to be * displayed in a table that has a fixed column count. * * @param array $array * @param int $col_limit * @return array */ public function make_columns($array = array(), $col_limit = 0) { if ( ! is_array($array) OR count($array) === 0 OR ! is_int($col_limit)) { return FALSE; } // Turn off the auto-heading feature since it's doubtful we // will want headings from a one-dimensional array $this->auto_heading = FALSE; if ($col_limit === 0) { return $array; } $new = array(); do { $temp = array_splice($array, 0, $col_limit); if (count($temp) < $col_limit) { for ($i = count($temp); $i < $col_limit; $i++) { $temp[] = ' '; } } $new[] = $temp; } while (count($array) > 0); return $new; } // -------------------------------------------------------------------- /** * Set "empty" cells * * Can be passed as an array or discreet params * * @param mixed $value * @return CI_Table */ public function set_empty($value) { $this->empty_cells = $value; return $this; } // -------------------------------------------------------------------- /** * Add a table row * * Can be passed as an array or discreet params * * @param mixed * @return CI_Table */ public function add_row($args = array()) { $this->rows[] = $this->_prep_args(func_get_args()); return $this; } // -------------------------------------------------------------------- /** * Prep Args * * Ensures a standard associative array format for all cell data * * @param array * @return array */ protected function _prep_args($args) { // If there is no $args[0], skip this and treat as an associative array // This can happen if there is only a single key, for example this is passed to table->generate // array(array('foo'=>'bar')) if (isset($args[0]) && count($args) === 1 && is_array($args[0]) && ! isset($args[0]['data'])) { $args = $args[0]; } foreach ($args as $key => $val) { is_array($val) OR $args[$key] = array('data' => $val); } return $args; } // -------------------------------------------------------------------- /** * Add a table caption * * @param string $caption * @return CI_Table */ public function set_caption($caption) { $this->caption = $caption; return $this; } // -------------------------------------------------------------------- /** * Generate the table * * @param mixed $table_data * @return string */ public function generate($table_data = NULL) { // The table data can optionally be passed to this function // either as a database result object or an array if ( ! empty($table_data)) { if ($table_data instanceof CI_DB_result) { $this->_set_from_db_result($table_data); } elseif (is_array($table_data)) { $this->_set_from_array($table_data); } } // Is there anything to display? No? Smite them! if (empty($this->heading) && empty($this->rows)) { return 'Undefined table data'; } // Compile and validate the template date $this->_compile_template(); // Validate a possibly existing custom cell manipulation function if (isset($this->function) && ! is_callable($this->function)) { $this->function = NULL; } // Build the table! $out = $this->template['table_open'].$this->newline; // Add any caption here if ($this->caption) { $out .= ''.$this->caption.''.$this->newline; } // Is there a table heading to display? if ( ! empty($this->heading)) { $out .= $this->template['thead_open'].$this->newline.$this->template['heading_row_start'].$this->newline; foreach ($this->heading as $heading) { $temp = $this->template['heading_cell_start']; foreach ($heading as $key => $val) { if ($key !== 'data') { $temp = str_replace('template['heading_cell_end']; } $out .= $this->template['heading_row_end'].$this->newline.$this->template['thead_close'].$this->newline; } // Build the table rows if ( ! empty($this->rows)) { $out .= $this->template['tbody_open'].$this->newline; $i = 1; foreach ($this->rows as $row) { if ( ! is_array($row)) { break; } // We use modulus to alternate the row colors $name = fmod($i++, 2) ? '' : 'alt_'; $out .= $this->template['row_'.$name.'start'].$this->newline; foreach ($row as $cell) { $temp = $this->template['cell_'.$name.'start']; foreach ($cell as $key => $val) { if ($key !== 'data') { $temp = str_replace('empty_cells; } elseif (isset($this->function)) { $out .= call_user_func($this->function, $cell); } else { $out .= $cell; } $out .= $this->template['cell_'.$name.'end']; } $out .= $this->template['row_'.$name.'end'].$this->newline; } $out .= $this->template['tbody_close'].$this->newline; } $out .= $this->template['table_close']; // Clear table class properties before generating the table $this->clear(); return $out; } // -------------------------------------------------------------------- /** * Clears the table arrays. Useful if multiple tables are being generated * * @return CI_Table */ public function clear() { $this->rows = array(); $this->heading = array(); $this->auto_heading = TRUE; return $this; } // -------------------------------------------------------------------- /** * Set table data from a database result object * * @param CI_DB_result $object Database result object * @return void */ protected function _set_from_db_result($object) { // First generate the headings from the table column names if ($this->auto_heading === TRUE && empty($this->heading)) { $this->heading = $this->_prep_args($object->list_fields()); } foreach ($object->result_array() as $row) { $this->rows[] = $this->_prep_args($row); } } // -------------------------------------------------------------------- /** * Set table data from an array * * @param array $data * @return void */ protected function _set_from_array($data) { if ($this->auto_heading === TRUE && empty($this->heading)) { $this->heading = $this->_prep_args(array_shift($data)); } foreach ($data as &$row) { $this->rows[] = $this->_prep_args($row); } } // -------------------------------------------------------------------- /** * Compile Template * * @return void */ protected function _compile_template() { if ($this->template === NULL) { $this->template = $this->_default_template(); return; } $this->temp = $this->_default_template(); foreach (array('table_open', 'thead_open', 'thead_close', 'heading_row_start', 'heading_row_end', 'heading_cell_start', 'heading_cell_end', 'tbody_open', 'tbody_close', 'row_start', 'row_end', 'cell_start', 'cell_end', 'row_alt_start', 'row_alt_end', 'cell_alt_start', 'cell_alt_end', 'table_close') as $val) { if ( ! isset($this->template[$val])) { $this->template[$val] = $this->temp[$val]; } } } // -------------------------------------------------------------------- /** * Default Template * * @return array */ protected function _default_template() { return array( 'table_open' => '', 'thead_open' => '', 'thead_close' => '', 'heading_row_start' => '', 'heading_row_end' => '', 'heading_cell_start' => '', 'tbody_open' => '', 'tbody_close' => '', 'row_start' => '', 'row_end' => '', 'cell_start' => '', 'row_alt_start' => '', 'row_alt_end' => '', 'cell_alt_start' => '', 'table_close' => '
', 'heading_cell_end' => '
', 'cell_end' => '
', 'cell_alt_end' => '
' ); } } lib/phpspreadsheet/phpspreadsheet/src/PhpSpreadsheet/Worksheet/Table.php000064400000042217152270363510034641 0ustar00home/smkb8269/public_html/lms.smk-almanshuriyah.sch.id|AddressRange|AddressRange|array{0: int, 1: int, 2: int, 3: int}|array{0: int, 1: int}|string $range * A simple string containing a Cell range like 'A1:E10' is permitted * or passing in an array of [$fromColumnIndex, $fromRow, $toColumnIndex, $toRow] (e.g. [3, 5, 6, 8]), * or an AddressRange object. * @param string $name (e.g. Table1) */ public function __construct(AddressRange|string|array $range = '', string $name = '') { $this->style = new TableStyle(); $this->autoFilter = new AutoFilter($range); $this->setRange($range); $this->setName($name); } /** * Code to execute when this table is unset(). */ public function __destruct() { $this->workSheet = null; } /** * Get Table name. */ public function getName(): string { return $this->name; } /** * Set Table name. * * @throws PhpSpreadsheetException */ public function setName(string $name): self { $name = trim($name); if (!empty($name)) { if (strlen($name) === 1 && in_array($name, ['C', 'c', 'R', 'r'])) { throw new PhpSpreadsheetException('The table name is invalid'); } if (StringHelper::countCharacters($name) > 255) { throw new PhpSpreadsheetException('The table name cannot be longer than 255 characters'); } // Check for A1 or R1C1 cell reference notation if ( preg_match(Coordinate::A1_COORDINATE_REGEX, $name) || preg_match('/^R\[?\-?[0-9]*\]?C\[?\-?[0-9]*\]?$/i', $name) ) { throw new PhpSpreadsheetException('The table name can\'t be the same as a cell reference'); } if (!preg_match('/^[\p{L}_\\\]/iu', $name)) { throw new PhpSpreadsheetException('The table name must begin a name with a letter, an underscore character (_), or a backslash (\)'); } if (!preg_match('/^[\p{L}_\\\][\p{L}\p{M}0-9\._]+$/iu', $name)) { throw new PhpSpreadsheetException('The table name contains invalid characters'); } $this->checkForDuplicateTableNames($name, $this->workSheet); $this->updateStructuredReferences($name); } $this->name = $name; return $this; } /** * @throws PhpSpreadsheetException */ private function checkForDuplicateTableNames(string $name, ?Worksheet $worksheet): void { // Remember that table names are case-insensitive $tableName = StringHelper::strToLower($name); if ($worksheet !== null && StringHelper::strToLower($this->name) !== $name) { $spreadsheet = $worksheet->getParentOrThrow(); foreach ($spreadsheet->getWorksheetIterator() as $sheet) { foreach ($sheet->getTableCollection() as $table) { if (StringHelper::strToLower($table->getName()) === $tableName && $table != $this) { throw new PhpSpreadsheetException("Spreadsheet already contains a table named '{$this->name}'"); } } } } } private function updateStructuredReferences(string $name): void { if (!$this->workSheet || !$this->name) { return; } // Remember that table names are case-insensitive if (StringHelper::strToLower($this->name) !== StringHelper::strToLower($name)) { // We need to check all formula cells that might contain fully-qualified Structured References // that refer to this table, and update those formulae to reference the new table name $spreadsheet = $this->workSheet->getParentOrThrow(); foreach ($spreadsheet->getWorksheetIterator() as $sheet) { $this->updateStructuredReferencesInCells($sheet, $name); } $this->updateStructuredReferencesInNamedFormulae($spreadsheet, $name); } } private function updateStructuredReferencesInCells(Worksheet $worksheet, string $newName): void { $pattern = '/' . preg_quote($this->name, '/') . '\[/mui'; foreach ($worksheet->getCoordinates(false) as $coordinate) { $cell = $worksheet->getCell($coordinate); if ($cell->getDataType() === DataType::TYPE_FORMULA) { $formula = $cell->getValueString(); if (preg_match($pattern, $formula) === 1) { $formula = preg_replace($pattern, "{$newName}[", $formula); $cell->setValueExplicit($formula, DataType::TYPE_FORMULA); } } } } private function updateStructuredReferencesInNamedFormulae(Spreadsheet $spreadsheet, string $newName): void { $pattern = '/' . preg_quote($this->name, '/') . '\[/mui'; foreach ($spreadsheet->getNamedFormulae() as $namedFormula) { $formula = $namedFormula->getValue(); if (preg_match($pattern, $formula) === 1) { $formula = preg_replace($pattern, "{$newName}[", $formula) ?? ''; $namedFormula->setValue($formula); } } } /** * Get show Header Row. */ public function getShowHeaderRow(): bool { return $this->showHeaderRow; } /** * Set show Header Row. */ public function setShowHeaderRow(bool $showHeaderRow): self { $this->showHeaderRow = $showHeaderRow; return $this; } /** * Get show Totals Row. */ public function getShowTotalsRow(): bool { return $this->showTotalsRow; } /** * Set show Totals Row. */ public function setShowTotalsRow(bool $showTotalsRow): self { $this->showTotalsRow = $showTotalsRow; return $this; } /** * Get allow filter. * If false, autofiltering is disabled for the table, if true it is enabled. */ public function getAllowFilter(): bool { return $this->allowFilter; } /** * Set show Autofiltering. * Disabling autofiltering has the same effect as hiding the filter button on all the columns in the table. */ public function setAllowFilter(bool $allowFilter): self { $this->allowFilter = $allowFilter; return $this; } /** * Get Table Range. */ public function getRange(): string { return $this->range; } /** * Set Table Cell Range. * * @param AddressRange|AddressRange|AddressRange|array{0: int, 1: int, 2: int, 3: int}|array{0: int, 1: int}|string $range * A simple string containing a Cell range like 'A1:E10' is permitted * or passing in an array of [$fromColumnIndex, $fromRow, $toColumnIndex, $toRow] (e.g. [3, 5, 6, 8]), * or an AddressRange object. */ public function setRange(AddressRange|string|array $range = ''): self { // extract coordinate if ($range !== '') { [, $range] = Worksheet::extractSheetTitle(Validations::validateCellRange($range), true); } if (empty($range)) { // Discard all column rules $this->columns = []; $this->range = ''; return $this; } if (!str_contains($range, ':')) { throw new PhpSpreadsheetException('Table must be set on a range of cells.'); } [$width, $height] = Coordinate::rangeDimension($range); if ($width < 1 || $height < 1) { throw new PhpSpreadsheetException('The table range must be at least 1 column and row'); } $this->range = $range; $this->autoFilter->setRange($range); // Discard any column rules that are no longer valid within this range [$rangeStart, $rangeEnd] = Coordinate::rangeBoundaries($this->range); foreach ($this->columns as $key => $value) { $colIndex = Coordinate::columnIndexFromString($key); if (($rangeStart[0] > $colIndex) || ($rangeEnd[0] < $colIndex)) { unset($this->columns[$key]); } } return $this; } /** * Set Table Cell Range to max row. */ public function setRangeToMaxRow(): self { if ($this->workSheet !== null) { $thisrange = $this->range; $range = (string) preg_replace('/\d+$/', (string) $this->workSheet->getHighestRow(), $thisrange); if ($range !== $thisrange) { $this->setRange($range); } } return $this; } /** * Get Table's Worksheet. */ public function getWorksheet(): ?Worksheet { return $this->workSheet; } /** * Set Table's Worksheet. */ public function setWorksheet(?Worksheet $worksheet = null): self { if ($this->name !== '' && $worksheet !== null) { $spreadsheet = $worksheet->getParentOrThrow(); $tableName = StringHelper::strToUpper($this->name); foreach ($spreadsheet->getWorksheetIterator() as $sheet) { foreach ($sheet->getTableCollection() as $table) { if (StringHelper::strToUpper($table->getName()) === $tableName) { throw new PhpSpreadsheetException("Workbook already contains a table named '{$this->name}'"); } } } } $this->workSheet = $worksheet; $this->autoFilter->setParent($worksheet); return $this; } /** * Get all Table Columns. * * @return Table\Column[] */ public function getColumns(): array { return $this->columns; } /** * Validate that the specified column is in the Table range. * * @param string $column Column name (e.g. A) * * @return int The column offset within the table range */ public function isColumnInRange(string $column): int { if (empty($this->range)) { throw new PhpSpreadsheetException('No table range is defined.'); } $columnIndex = Coordinate::columnIndexFromString($column); [$rangeStart, $rangeEnd] = Coordinate::rangeBoundaries($this->range); if (($rangeStart[0] > $columnIndex) || ($rangeEnd[0] < $columnIndex)) { throw new PhpSpreadsheetException('Column is outside of current table range.'); } return $columnIndex - $rangeStart[0]; } /** * Get a specified Table Column Offset within the defined Table range. * * @param string $column Column name (e.g. A) * * @return int The offset of the specified column within the table range */ public function getColumnOffset(string $column): int { return $this->isColumnInRange($column); } /** * Get a specified Table Column. * * @param string $column Column name (e.g. A) */ public function getColumn(string $column): Table\Column { $this->isColumnInRange($column); if (!isset($this->columns[$column])) { $this->columns[$column] = new Table\Column($column, $this); } return $this->columns[$column]; } /** * Get a specified Table Column by it's offset. * * @param int $columnOffset Column offset within range (starting from 0) */ public function getColumnByOffset(int $columnOffset): Table\Column { [$rangeStart, $rangeEnd] = Coordinate::rangeBoundaries($this->range); $pColumn = Coordinate::stringFromColumnIndex($rangeStart[0] + $columnOffset); return $this->getColumn($pColumn); } /** * Set Table. * * @param string|Table\Column $columnObjectOrString * A simple string containing a Column ID like 'A' is permitted */ public function setColumn(string|Table\Column $columnObjectOrString): self { if ((is_string($columnObjectOrString)) && (!empty($columnObjectOrString))) { $column = $columnObjectOrString; } elseif ($columnObjectOrString instanceof Table\Column) { $column = $columnObjectOrString->getColumnIndex(); } else { throw new PhpSpreadsheetException('Column is not within the table range.'); } $this->isColumnInRange($column); if (is_string($columnObjectOrString)) { $this->columns[$columnObjectOrString] = new Table\Column($columnObjectOrString, $this); } else { $columnObjectOrString->setTable($this); $this->columns[$column] = $columnObjectOrString; } ksort($this->columns); return $this; } /** * Clear a specified Table Column. * * @param string $column Column name (e.g. A) */ public function clearColumn(string $column): self { $this->isColumnInRange($column); if (isset($this->columns[$column])) { unset($this->columns[$column]); } return $this; } /** * Shift an Table Column Rule to a different column. * * Note: This method bypasses validation of the destination column to ensure it is within this Table range. * Nor does it verify whether any column rule already exists at $toColumn, but will simply override any existing value. * Use with caution. * * @param string $fromColumn Column name (e.g. A) * @param string $toColumn Column name (e.g. B) */ public function shiftColumn(string $fromColumn, string $toColumn): self { $fromColumn = strtoupper($fromColumn); $toColumn = strtoupper($toColumn); if (isset($this->columns[$fromColumn])) { $this->columns[$fromColumn]->setTable(); $this->columns[$fromColumn]->setColumnIndex($toColumn); $this->columns[$toColumn] = $this->columns[$fromColumn]; $this->columns[$toColumn]->setTable($this); unset($this->columns[$fromColumn]); ksort($this->columns); } return $this; } /** * Get table Style. */ public function getStyle(): TableStyle { return $this->style; } /** * Set table Style. */ public function setStyle(TableStyle $style): self { $this->style = $style; return $this; } /** * Get AutoFilter. */ public function getAutoFilter(): AutoFilter { return $this->autoFilter; } /** * Set AutoFilter. */ public function setAutoFilter(AutoFilter $autoFilter): self { $this->autoFilter = $autoFilter; return $this; } /** * Implement PHP __clone to create a deep clone, not just a shallow copy. */ public function __clone() { $vars = get_object_vars($this); foreach ($vars as $key => $value) { if (is_object($value)) { if ($key === 'workSheet') { // Detach from worksheet $this->{$key} = null; } else { $this->{$key} = clone $value; } } elseif ((is_array($value)) && ($key === 'columns')) { // The columns array of \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet\Table objects $this->{$key} = []; foreach ($value as $k => $v) { $this->{$key}[$k] = clone $v; // attach the new cloned Column to this new cloned Table object $this->{$key}[$k]->setTable($this); } } else { $this->{$key} = $value; } } } /** * toString method replicates previous behavior by returning the range if object is * referenced as a property of its worksheet. */ public function __toString(): string { return (string) $this->range; } } home/smkb8269/public_html/system/libraries/Table.php000064400000027740152270522100016331 0ustar00 $val) { $this->template[$key] = $val; } log_message('info', 'Table Class Initialized'); } // -------------------------------------------------------------------- /** * Set the template * * @param array $template * @return bool */ public function set_template($template) { if ( ! is_array($template)) { return FALSE; } $this->template = $template; return TRUE; } // -------------------------------------------------------------------- /** * Set the table heading * * Can be passed as an array or discreet params * * @param mixed * @return CI_Table */ public function set_heading($args = array()) { $this->heading = $this->_prep_args(func_get_args()); return $this; } // -------------------------------------------------------------------- /** * Set columns. Takes a one-dimensional array as input and creates * a multi-dimensional array with a depth equal to the number of * columns. This allows a single array with many elements to be * displayed in a table that has a fixed column count. * * @param array $array * @param int $col_limit * @return array */ public function make_columns($array = array(), $col_limit = 0) { if ( ! is_array($array) OR count($array) === 0 OR ! is_int($col_limit)) { return FALSE; } // Turn off the auto-heading feature since it's doubtful we // will want headings from a one-dimensional array $this->auto_heading = FALSE; if ($col_limit === 0) { return $array; } $new = array(); do { $temp = array_splice($array, 0, $col_limit); if (count($temp) < $col_limit) { for ($i = count($temp); $i < $col_limit; $i++) { $temp[] = ' '; } } $new[] = $temp; } while (count($array) > 0); return $new; } // -------------------------------------------------------------------- /** * Set "empty" cells * * Can be passed as an array or discreet params * * @param mixed $value * @return CI_Table */ public function set_empty($value) { $this->empty_cells = $value; return $this; } // -------------------------------------------------------------------- /** * Add a table row * * Can be passed as an array or discreet params * * @param mixed * @return CI_Table */ public function add_row($args = array()) { $this->rows[] = $this->_prep_args(func_get_args()); return $this; } // -------------------------------------------------------------------- /** * Prep Args * * Ensures a standard associative array format for all cell data * * @param array * @return array */ protected function _prep_args($args) { // If there is no $args[0], skip this and treat as an associative array // This can happen if there is only a single key, for example this is passed to table->generate // array(array('foo'=>'bar')) if (isset($args[0]) && count($args) === 1 && is_array($args[0]) && ! isset($args[0]['data'])) { $args = $args[0]; } foreach ($args as $key => $val) { is_array($val) OR $args[$key] = array('data' => $val); } return $args; } // -------------------------------------------------------------------- /** * Add a table caption * * @param string $caption * @return CI_Table */ public function set_caption($caption) { $this->caption = $caption; return $this; } // -------------------------------------------------------------------- /** * Generate the table * * @param mixed $table_data * @return string */ public function generate($table_data = NULL) { // The table data can optionally be passed to this function // either as a database result object or an array if ( ! empty($table_data)) { if ($table_data instanceof CI_DB_result) { $this->_set_from_db_result($table_data); } elseif (is_array($table_data)) { $this->_set_from_array($table_data); } } // Is there anything to display? No? Smite them! if (empty($this->heading) && empty($this->rows)) { return 'Undefined table data'; } // Compile and validate the template date $this->_compile_template(); // Validate a possibly existing custom cell manipulation function if (isset($this->function) && ! is_callable($this->function)) { $this->function = NULL; } // Build the table! $out = $this->template['table_open'].$this->newline; // Add any caption here if ($this->caption) { $out .= ''.$this->caption.''.$this->newline; } // Is there a table heading to display? if ( ! empty($this->heading)) { $out .= $this->template['thead_open'].$this->newline.$this->template['heading_row_start'].$this->newline; foreach ($this->heading as $heading) { $temp = $this->template['heading_cell_start']; foreach ($heading as $key => $val) { if ($key !== 'data') { $temp = str_replace('template['heading_cell_end']; } $out .= $this->template['heading_row_end'].$this->newline.$this->template['thead_close'].$this->newline; } // Build the table rows if ( ! empty($this->rows)) { $out .= $this->template['tbody_open'].$this->newline; $i = 1; foreach ($this->rows as $row) { if ( ! is_array($row)) { break; } // We use modulus to alternate the row colors $name = fmod($i++, 2) ? '' : 'alt_'; $out .= $this->template['row_'.$name.'start'].$this->newline; foreach ($row as $cell) { $temp = $this->template['cell_'.$name.'start']; foreach ($cell as $key => $val) { if ($key !== 'data') { $temp = str_replace('empty_cells; } elseif (isset($this->function)) { $out .= call_user_func($this->function, $cell); } else { $out .= $cell; } $out .= $this->template['cell_'.$name.'end']; } $out .= $this->template['row_'.$name.'end'].$this->newline; } $out .= $this->template['tbody_close'].$this->newline; } $out .= $this->template['table_close']; // Clear table class properties before generating the table $this->clear(); return $out; } // -------------------------------------------------------------------- /** * Clears the table arrays. Useful if multiple tables are being generated * * @return CI_Table */ public function clear() { $this->rows = array(); $this->heading = array(); $this->auto_heading = TRUE; return $this; } // -------------------------------------------------------------------- /** * Set table data from a database result object * * @param CI_DB_result $object Database result object * @return void */ protected function _set_from_db_result($object) { // First generate the headings from the table column names if ($this->auto_heading === TRUE && empty($this->heading)) { $this->heading = $this->_prep_args($object->list_fields()); } foreach ($object->result_array() as $row) { $this->rows[] = $this->_prep_args($row); } } // -------------------------------------------------------------------- /** * Set table data from an array * * @param array $data * @return void */ protected function _set_from_array($data) { if ($this->auto_heading === TRUE && empty($this->heading)) { $this->heading = $this->_prep_args(array_shift($data)); } foreach ($data as &$row) { $this->rows[] = $this->_prep_args($row); } } // -------------------------------------------------------------------- /** * Compile Template * * @return void */ protected function _compile_template() { if ($this->template === NULL) { $this->template = $this->_default_template(); return; } $this->temp = $this->_default_template(); foreach (array('table_open', 'thead_open', 'thead_close', 'heading_row_start', 'heading_row_end', 'heading_cell_start', 'heading_cell_end', 'tbody_open', 'tbody_close', 'row_start', 'row_end', 'cell_start', 'cell_end', 'row_alt_start', 'row_alt_end', 'cell_alt_start', 'cell_alt_end', 'table_close') as $val) { if ( ! isset($this->template[$val])) { $this->template[$val] = $this->temp[$val]; } } } // -------------------------------------------------------------------- /** * Default Template * * @return array */ protected function _default_template() { return array( 'table_open' => '', 'thead_open' => '', 'thead_close' => '', 'heading_row_start' => '', 'heading_row_end' => '', 'heading_cell_start' => '', 'tbody_open' => '', 'tbody_close' => '', 'row_start' => '', 'row_end' => '', 'cell_start' => '', 'row_alt_start' => '', 'row_alt_end' => '', 'cell_alt_start' => '', 'table_close' => '
', 'heading_cell_end' => '
', 'cell_end' => '
', 'cell_alt_end' => '
' ); } }