Skip to content

Instantly share code, notes, and snippets.

@cododel
Created October 27, 2024 15:44
Show Gist options
  • Save cododel/31d275631c9a8ec550d3bdfa327115ea to your computer and use it in GitHub Desktop.
Save cododel/31d275631c9a8ec550d3bdfa327115ea to your computer and use it in GitHub Desktop.
PHP HTML Dom Static Builder
<?php
namespace App\Services\Table;
use App\Services\HTML\HTMLElement;
class Cell extends HTMLElement
{
public static function getTagName(): string
{
return 'td';
}
public function rowSpan(int $rowSpan): static
{
$this->attr('rowspan', $rowSpan);
return $this;
}
public function colSpan(int $colSpan): static
{
$this->attr('colspan', $colSpan);
return $this;
}
public function span(int $rowSpan = 1, int $colSpan = 1): static
{
return $this->rowSpan($rowSpan)->colSpan($colSpan);
}
public function width(int $width): static
{
$this->attr('width', $width);
return $this;
}
public function height(int $height): static
{
$this->attr('height', $height);
return $this;
}
}
<?php
namespace App\Services\HTML;
use App\Services\HTML\Modules\Module;
abstract class HTMLElement
{
protected static $modules = [];
protected $attributes = [];
protected $classList = [];
protected $children = [];
public function __call($method, $args)
{
foreach (self::$modules as $module) {
$callback = $module::getCallback($this);
if (is_callable($callback)) {
return call_user_func($callback, ...$args);
}
}
return $this;
}
abstract protected static function getTagName(): string;
public function attr(string $name, $value)
{
$this->attributes[$name] = $value;
return $this;
}
public function getAttributes(): array
{
return $this->attributes;
}
public function render()
{
$attributes = '';
foreach ($this->attributes as $name => $value) {
$attributes .= " $name=\"$value\"";
}
if (!empty($this->classList)) {
$attributes .= ' class="' . implode(' ', $this->classList) . '"';
}
$html = "<{$this->getTagName()} $attributes>";
foreach ($this->children as $child) {
if ($child instanceof HTMLElement) $html .= $child->render();
else $html .= (string) $child;
}
$html .= "</{$this->getTagName()}>";
return $html;
}
public function children(array|HTMLElement|string|int $children): static
{
if (is_array($children)) {
foreach ($children as $child) {
$this->children($child);
}
} else {
$this->children[] = $children;
}
return $this;
}
public function class(string $class): static
{
$this->classList[] = $class;
return $this;
}
public function getInnerText(): string
{
$text = '';
foreach ($this->children as $child) {
if ($child instanceof HTMLElement) $text .= $child->getInnerText();
else $text .= $child;
}
return $text;
}
public function getInnerHTML(): string
{
$html = '';
foreach ($this->children as $child) {
if ($child instanceof HTMLElement) $html .= $child->render();
else $html .= $child;
}
return $html;
}
public function getOuterHTML(): string
{
return $this->render();
}
public static function registerModule(string $module)
{
$moduleName = $module::getModuleName();
if (!property_exists(static::class, $moduleName)) {
static::$modules[$moduleName] = $module;
} else {
throw new \Exception("Module name {$module::getModuleName()} is not allowed, it is a reserved name.");
}
}
public static function getModules(): array
{
return static::$modules;
}
public static function make(array|string|int|null $children = []): static
{
$element = new static();
if (!empty($children)) {
$element->children($children);
}
return $element;
}
}
<?php
namespace App\Services\Table;
use App\Services\HTML\HTMLElement;
class Row extends HTMLElement
{
public static function getTagName(): string
{
return 'tr';
}
}
<?php
namespace App\Services\Table;
use App\Services\HTML\HTMLElement;
class Table extends HTMLElement
{
private $data;
public static function getTagName(): string
{
return 'table';
}
public function getValue(int $column, int $row)
{
return $this->data[$row][$column] ?? null;
}
}
@cododel
Copy link
Author

cododel commented Oct 27, 2024

Usage example:

(Formulas in this script are not evaluated)

    $table = Table::make()
      ->class('text-center')
      ->children([
        Row::make([
          Cell::make("Финансовый результат по видам деятельности, связанным с исполнением договора №")
            ->class('font-bold')
            ->width(200)
            ->colSpan(2),
          Cell::make($contract_number),
          Cell::make("от"),
          Cell::make($contract_date),
        ]),
        Row::make([
          Cell::make("Параметры: ИГК")->colSpan(2),
          Cell::make($igk),
        ]),
        Row::make([
          Cell::make("Период:")->colSpan(2),
          Cell::make($contract_date),
          Cell::make("-"),
          Cell::make($obligation_date),
        ]),
        Row::make([
          Cell::make("Показатель")->span(2, 2),
          Cell::make("Доходы")->rowSpan(2),
          Cell::make("Расходы")->colSpan(3),
          Cell::make("Прибыль (+) убыток (-)")->rowSpan(2),
        ]),
        Row::make([
          Cell::make("Себестоимость продаж"),
          Cell::make("Общехозяйственные (АУП)"),
          Cell::make("Коммерческие расходы")
        ]),
        Row::make([
          Cell::make("Выручка от продаж (всего)")->colSpan(2),
          Cell::make($total_revenue),
          Cell::make($cost_of_goods_sold),
          Cell::make($general_expenses),
          Cell::make($commercial_expenses),
          Cell::make("=C5-D5-E5-F5"),
        ]),
        Row::make([
          Cell::make("Выручка от продаж  ИГК"),
          Cell::make($igk),
          Cell::make($contract_revenue),
          Cell::make($contract_expenses),
          Cell::make("=E5*100/D5/100*D6"),
          Cell::make("=F5*100/D5/100*D6"),
          Cell::make("=C6-D6-E6-F6"),
        ]),
      ]);
      ```

@cododel
Copy link
Author

cododel commented Oct 30, 2024

Subscribe to my telegram channel, don’t miss new interesting solutions

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment