Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Modules/Clients/Models/Contact.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public function addresses(): HasManyThrough

public function getFullNameAttribute(): string
{
return trim($this->first_name . ' ' . $this->last_name);
return mb_trim($this->first_name . ' ' . $this->last_name);
}

public function getPrimaryEmailAttribute(): ?string
Expand Down
252 changes: 252 additions & 0 deletions Modules/Core/DTOs/BlockDTO.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
<?php

namespace Modules\Core\DTOs;

use Modules\Core\Enums\ReportBlockType;

/**
* Data Transfer Object for report builder blocks.
*
* Represents a single block in the report template layout with its configuration,
* position, and metadata. Blocks can be system-provided or user-cloned.
*
* Example JSON:
* {
* "id": "block_company_header",
* "type": "company_header",
* "position": {
* "x": 0,
* "y": 0,
* "width": 6,
* "height": 4
* },
* "config": {
* "show_vat_id": true,
* "show_phone": true,
* "font_size": 10
* },
* "label": "Company Header",
* "isCloneable": true,
* "dataSource": "company",
* "isCloned": false,
* "clonedFrom": null
* }
*/
class BlockDTO
{
//region Properties

private string $id = '';

private ReportBlockType|string $type = '';

private ?string $slug = null;

private ?GridPositionDTO $position = null;

private ?array $config = [];

private ?string $label = null;

private bool $isCloneable = false;

private ?string $dataSource = null;

private string $band = 'header';

private bool $isCloned = false;

private ?string $clonedFrom = null;

//endregion

//region Static Factory Methods

/**
* Create a system block with default configuration.
*/
public static function system(string $type, GridPositionDTO $position, array $config): self
{
$dto = new self();
$dto->setType($type);
$dto->setPosition($position);
$dto->setConfig($config);
$dto->setIsCloneable(true);
$dto->setIsCloned(false);
$dto->setClonedFrom(null);

return $dto;
}

/**
* Create a cloned block from an original block.
*/
public static function clonedFrom(self $original, string $newId): self
{
$dto = new self();
$dto->setId($newId);
$dto->setType($original->getType());
$dto->setSlug($original->getSlug());

$originalPosition = $original->getPosition();
$newPosition = GridPositionDTO::create(
$originalPosition->getX(),
$originalPosition->getY(),
$originalPosition->getWidth(),
$originalPosition->getHeight()
);

$dto->setPosition($newPosition);
$dto->setConfig($original->getConfig());
$dto->setLabel($original->getLabel());
$dto->setIsCloneable($original->getIsCloneable());
$dto->setDataSource($original->getDataSource());
$dto->setBand($original->getBand());
$dto->setIsCloned(true);
$dto->setClonedFrom($original->getId());

return $dto;
}

//endregion

//region Getters

public function getId(): string
{
return $this->id;
}

public function getType(): ReportBlockType|string
{
return $this->type;
}

public function getSlug(): ?string
{
return $this->slug;
}

public function getPosition(): ?GridPositionDTO
{
return $this->position;
}

public function getConfig(): ?array
{
return $this->config;
}

public function getLabel(): ?string
{
return $this->label;
}

public function getIsCloneable(): bool
{
return $this->isCloneable;
}

public function getDataSource(): ?string
{
return $this->dataSource;
}

public function getIsCloned(): bool
{
return $this->isCloned;
}

public function getClonedFrom(): ?string
{
return $this->clonedFrom;
}

//endregion

//region Setters

public function setId(string $id): self
{
$this->id = $id;

return $this;
}

public function setType(ReportBlockType|string $type): self
{
$this->type = $type;

return $this;
}

public function setSlug(?string $slug): self
{
$this->slug = $slug;

return $this;
}

public function setPosition(GridPositionDTO $position): self
{
$this->position = $position;

return $this;
}

public function setConfig(?array $config): self
{
$this->config = $config;

return $this;
}

public function setLabel(?string $label): self
{
$this->label = $label;

return $this;
}

public function setIsCloneable(bool $isCloneable): self
{
$this->isCloneable = $isCloneable;

return $this;
}

public function setDataSource(?string $dataSource): self
{
$this->dataSource = $dataSource;

return $this;
}

public function setIsCloned(bool $isCloned): self
{
$this->isCloned = $isCloned;

return $this;
}

public function setClonedFrom(?string $clonedFrom): self
{
$this->clonedFrom = $clonedFrom;

return $this;
}

public function getBand(): string
{
return $this->band;
}

public function setBand(string $band): self
{
$this->band = $band;

return $this;
}

//endregion
}
137 changes: 137 additions & 0 deletions Modules/Core/DTOs/GridPositionDTO.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
<?php

namespace Modules\Core\DTOs;

use InvalidArgumentException;

/**
* Data Transfer Object for grid position coordinates.
*
* Represents a position in the report layout grid system.
*
* Example JSON:
* {
* "x": 0,
* "y": 0,
* "width": 6,
* "height": 4
* }
*/
class GridPositionDTO
{
//region Properties

private int $x;

private int $y;

private int $width;

private int $height;

//endregion

//region Constructor

/**
* GridPositionDTO constructor.
*
* No-arg constructor following DTO guidelines.
* Use setters or static factory methods to populate the DTO.
*/
public function __construct()
{
$this->x = 0;
$this->y = 0;
$this->width = 0;
$this->height = 0;
}

/**
* Static factory method to create a GridPositionDTO with all values.
*
* @param int $x X coordinate
* @param int $y Y coordinate
* @param int $width Width
* @param int $height Height
*
* @return self
*
* @throws InvalidArgumentException
*/
public static function create(int $x, int $y, int $width, int $height): self
{
if ($x < 0 || $y < 0) {
throw new InvalidArgumentException('x and y must be >= 0');
}
if ($width <= 0 || $height <= 0) {
throw new InvalidArgumentException('width and height must be > 0');
}

$dto = new self();
$dto->x = $x;
$dto->y = $y;
$dto->width = $width;
$dto->height = $height;

return $dto;
}

//endregion

//region Getters

public function getX(): int
{
return $this->x;
}

public function getY(): int
{
return $this->y;
}

public function getWidth(): int
{
return $this->width;
}

public function getHeight(): int
{
return $this->height;
}

//endregion

//region Setters

public function setX(int $x): self
{
$this->x = $x;

return $this;
}

public function setY(int $y): self
{
$this->y = $y;

return $this;
}

public function setWidth(int $width): self
{
$this->width = $width;

return $this;
}

public function setHeight(int $height): self
{
$this->height = $height;

return $this;
}

//endregion
}
Loading
Loading