vendor/contao-bootstrap/grid/src/GridBuilder.php line 75

Open in your IDE?
  1. <?php
  2. /**
  3.  * Contao Bootstrap grid.
  4.  *
  5.  * @filesource
  6.  */
  7. declare(strict_types=1);
  8. namespace ContaoBootstrap\Grid;
  9. use Contao\StringUtil;
  10. use ContaoBootstrap\Core\Environment;
  11. use ContaoBootstrap\Grid\Definition\Column;
  12. use ContaoBootstrap\Grid\Definition\Grid;
  13. use ContaoBootstrap\Grid\Exception\GridNotFound;
  14. use ContaoBootstrap\Grid\Model\GridModel;
  15. use RuntimeException;
  16. use function array_search;
  17. use function assert;
  18. use function is_numeric;
  19. /**
  20.  * GridBuilder builds the grid class from the database definition.
  21.  */
  22. final class GridBuilder
  23. {
  24.     /**
  25.      * Grid model.
  26.      */
  27.     private ?GridModel $model null;
  28.     /**
  29.      * Cache of grid being built.
  30.      */
  31.     private ?Grid $grid null;
  32.     /**
  33.      * Core Environment.
  34.      */
  35.     private Environment $environment;
  36.     /**
  37.      * @param Environment $environment The Core Environment.
  38.      */
  39.     public function __construct(Environment $environment)
  40.     {
  41.         $this->environment $environment;
  42.     }
  43.     /**
  44.      * Build a grid.
  45.      *
  46.      * @param int $gridId THe grid id.
  47.      *
  48.      * @throws RuntimeException When Grid does not exist.
  49.      */
  50.     public function build(int $gridId): Grid
  51.     {
  52.         $this->loadModel($gridId);
  53.         $this->createGrid();
  54.         return $this->finish();
  55.     }
  56.     /**
  57.      * Load grid model from the database.
  58.      *
  59.      * @param int $gridId THe grid id.
  60.      *
  61.      * @throws GridNotFound When Grid does not exist.
  62.      */
  63.     protected function loadModel(int $gridId): void
  64.     {
  65.         $model GridModel::findOneBy('id'$gridId);
  66.         if (! $model instanceof GridModel) {
  67.             throw GridNotFound::withId($gridId);
  68.         }
  69.         $this->model $model;
  70.     }
  71.     /**
  72.      * Create the grid from the model.
  73.      */
  74.     private function createGrid(): void
  75.     {
  76.         assert($this->model instanceof GridModel);
  77.         $this->grid = new Grid();
  78.         $sizes      StringUtil::deserialize($this->model->sizestrue);
  79.         $this->buildRow();
  80.         foreach ($sizes as $size) {
  81.             $field      $size 'Size';
  82.             $definition StringUtil::deserialize($this->model->{$field}, true);
  83.             if ($size === $this->environment->getConfig()->get('grid.default_size''xs')) {
  84.                 $size '';
  85.             }
  86.             $this->buildSize($size$definition$sizes);
  87.         }
  88.     }
  89.     /**
  90.      * Build the row.
  91.      */
  92.     private function buildRow(): void
  93.     {
  94.         assert($this->model instanceof GridModel);
  95.         assert($this->grid instanceof Grid);
  96.         if ($this->model->noGutters) {
  97.             $this->grid->addClass('no-gutters');
  98.         }
  99.         if ($this->model->rowClass) {
  100.             $this->grid->addClass($this->model->rowClass);
  101.         }
  102.         if ($this->model->align) {
  103.             $this->grid->align($this->model->align);
  104.         }
  105.         if (! $this->model->justify) {
  106.             return;
  107.         }
  108.         $this->grid->justify($this->model->justify);
  109.     }
  110.     /**
  111.      * Build a grid size.
  112.      *
  113.      * @param string                    $size       Grid size.
  114.      * @param list<array<string,mixed>> $definition Definition.
  115.      * @param list<string|int>          $sizes      List of defined sizes.
  116.      */
  117.     private function buildSize(string $size, array $definition, array $sizes): void
  118.     {
  119.         assert($this->grid instanceof Grid);
  120.         foreach ($definition as $columnDefinition) {
  121.             $column $this->buildColumn($columnDefinition$size$sizes);
  122.             $this->grid->addColumn($column$size);
  123.         }
  124.     }
  125.     /**
  126.      * Build a column.
  127.      *
  128.      * @param array<string,mixed> $definition Column definition.
  129.      * @param string              $size       The column size.
  130.      * @param list<string|int>    $sizes      List of defined sizes.
  131.      */
  132.     private function buildColumn(array $definitionstring $size, array $sizes): Column
  133.     {
  134.         $column = new Column();
  135.         $this->buildColumnWidth($definition$column);
  136.         $this->buildColumnResets($definition$column$size$sizes);
  137.         if ($definition['order']) {
  138.             $column->order((int) $definition['order']);
  139.         }
  140.         if ($definition['align']) {
  141.             $column->align($definition['align']);
  142.         }
  143.         if ($definition['offset']) {
  144.             $offset $this->parseOffset($definition['offset']);
  145.             $column->offset($offset);
  146.         }
  147.         if ($definition['class']) {
  148.             $column->cssClass($definition['class']);
  149.         }
  150.         return $column;
  151.     }
  152.     /**
  153.      * Finish the grid building.
  154.      */
  155.     private function finish(): Grid
  156.     {
  157.         assert($this->grid instanceof Grid);
  158.         $grid        $this->grid;
  159.         $this->grid  null;
  160.         $this->model null;
  161.         return $grid;
  162.     }
  163.     /**
  164.      * Parse the offset definition value.
  165.      *
  166.      * @param mixed $offset Raw offset value.
  167.      *
  168.      * @return mixed
  169.      */
  170.     private function parseOffset($offset)
  171.     {
  172.         if ($offset === 'null') {
  173.             $offset 0;
  174.         } elseif (is_numeric($offset)) {
  175.             $offset = (int) $offset;
  176.         }
  177.         return $offset;
  178.     }
  179.     /**
  180.      * Build the column width.
  181.      *
  182.      * @param array<string,mixed> $definition The grid column definition.
  183.      * @param Column              $column     The column.
  184.      */
  185.     private function buildColumnWidth(array $definitionColumn $column): void
  186.     {
  187.         if (! $definition['width']) {
  188.             return;
  189.         }
  190.         switch ($definition['width']) {
  191.             case 'variable':
  192.                 $column->variableWidth();
  193.                 break;
  194.             case 'auto':
  195.             case 'equal':
  196.                 break;
  197.             case 'null':
  198.                 $column->width(0);
  199.                 break;
  200.             default:
  201.                 $column->width((int) $definition['width']);
  202.         }
  203.     }
  204.     /**
  205.      * Build the column resets.
  206.      *
  207.      * @param array<string,mixed> $definition The grid column definition.
  208.      * @param Column              $column     The column.
  209.      * @param string              $size       The column size.
  210.      * @param list<string|int>    $sizes      List of defined sizes.
  211.      */
  212.     private function buildColumnResets(array $definitionColumn $columnstring $size, array $sizes): void
  213.     {
  214.         switch ($definition['reset']) {
  215.             case '2':
  216.                 $key  array_search($size$sizes);
  217.                 $next $key ? ($sizes[$key 1] ?? null) : null;
  218.                 if ($next) {
  219.                     $column->limitedReset((string) $next);
  220.                     break;
  221.                 }
  222.                 // No break here,
  223.             case '1':
  224.                 $column->reset();
  225.                 break;
  226.             default:
  227.                 // Do nothing.
  228.         }
  229.     }
  230. }