Skip to content

Commit 3773eaf

Browse files
authored
Merge pull request #4 from MaplePHP/develop
v3.1.0
2 parents b3d3d1f + 2db3b7f commit 3773eaf

25 files changed

Lines changed: 1331 additions & 313 deletions

README.md

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
DTO stands for **Darn Tidy Object**, a playful twist on the traditional Data Transfer Object. But this isn’t your average DTO. It’s a fully-loaded toolkit for **traversing, transforming, and tidying up structured data** in PHP with style, power, and simplicity.
44

5+
_It also makes your life easier by ensuring every piece of data is returned in the correct type-helping. Whether you expect an int, string, bool, or even a callable, DTO gives you strict, reliable access to your data with minimal effort._
6+
7+
---
58

69
## 📦 Installation
710

@@ -10,13 +13,15 @@ composer require maplephp/dto
1013
```
1114

1215
## 📘 Documentation
13-
- [Why DTO?](https://maplephp.github.io/DTO/docs/intro#why-dto)
14-
- [Traverse Collection](https://maplephp.github.io/DTO/docs/traverse)
15-
- [Format string](https://maplephp.github.io/DTO/docs/format-string)
16-
- [Format Number](https://maplephp.github.io/DTO/docs/format-number)
17-
- [Format Clock](https://maplephp.github.io/DTO/docs/format-clock)
18-
- [Format Dom](https://maplephp.github.io/DTO/docs/format-dom)
1916

17+
* [Why DTO?](https://maplephp.github.io/DTO/docs/intro#why-dto)
18+
* [Traverse Collection](https://maplephp.github.io/DTO/docs/traverse)
19+
* [Format string](https://maplephp.github.io/DTO/docs/format-string)
20+
* [Format Number](https://maplephp.github.io/DTO/docs/format-number)
21+
* [Format Clock](https://maplephp.github.io/DTO/docs/format-clock)
22+
* [Format Dom](https://maplephp.github.io/DTO/docs/format-dom)
23+
24+
---
2025

2126
## How It Works
2227

@@ -60,6 +65,26 @@ echo $obj->article->content->strExcerpt()->strUcFirst();
6065

6166
---
6267

68+
### Correct Type Handling (with ease)
69+
70+
No more clunky `is_numeric` checks or `intval` casts. DTO makes it simple to extract values in the exact type you expect:
71+
72+
```php
73+
$orderId = $dto->order->id->toInt();
74+
// Result: 1234 (int)
75+
```
76+
77+
Handle flexible types cleanly with fallbacks:
78+
79+
```php
80+
$callback = $dto->settings->onReady->acceptType(['callable', 'null']);
81+
if (is_callable($callback)) {
82+
$callback(); // Result: Runs a startup hook or closure
83+
}
84+
```
85+
86+
---
87+
6388
### Built-In Data Transformation
6489

6590
Transform values directly using built-in helpers like:
@@ -130,4 +155,6 @@ print_r($updated->toArray());
130155

131156
---
132157

133-
Now go forth, write cleaner code, and let DTO handle the messy parts.
158+
Now go forth, write cleaner code, and let DTO handle the messy parts.
159+
160+
---

composer.json

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
{
22
"name": "maplephp/dto",
33
"type": "library",
4-
"version": "v3.0.0",
54
"description": "DTO library in PHP provides benefits such as encapsulating data, enforcing immutability and facilitating data transformation.",
65
"keywords": [
76
"dto",
@@ -32,16 +31,15 @@
3231
}
3332
],
3433
"require": {
35-
"php": ">=8.0",
36-
"maplephp/swiftrender": "^2.0"
34+
"php": ">=8.2"
35+
},
36+
"require-dev": {
37+
"maplephp/unitary": "^2.0"
3738
},
3839
"autoload": {
3940
"psr-4": {
4041
"MaplePHP\\DTO\\": "src"
4142
}
4243
},
43-
"minimum-stability": "dev",
44-
"require-dev": {
45-
"maplephp/unitary": "dev-main"
46-
}
44+
"minimum-stability": "dev"
4745
}

src/Dom/Document.php

Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
<?php
2+
3+
/**
4+
* @Package: MaplePHP - DOM Main class
5+
* @Author: Daniel Ronkainen
6+
* @Licence: Apache-2.0 license, Copyright © Daniel Ronkainen
7+
Don't delete this comment, its part of the license.
8+
*/
9+
10+
namespace MaplePHP\DTO\Dom;
11+
12+
use MaplePHP\DTO\Interfaces\DocumentInterface;
13+
use MaplePHP\DTO\Interfaces\ElementInterface;
14+
15+
class Document implements DocumentInterface
16+
{
17+
public const TAG_NO_ENDING = [
18+
"meta",
19+
"link",
20+
"img",
21+
"br",
22+
"hr",
23+
"input",
24+
"keygen",
25+
"param",
26+
"source",
27+
"track",
28+
"embed"
29+
];
30+
31+
protected $elements;
32+
private $html;
33+
private $elem;
34+
private static $inst;
35+
36+
/**
37+
* Will output get
38+
* @return string
39+
*/
40+
public function __toString(): string
41+
{
42+
return $this->get();
43+
}
44+
45+
/**
46+
* Get get Dom/document (Will only trigger execute once per instance)
47+
* @return string
48+
*/
49+
public function get(): string
50+
{
51+
if ($this->html === null) {
52+
$this->execute();
53+
}
54+
return $this->html;
55+
}
56+
57+
/**
58+
* Init DOM instance
59+
* @param string $key DOM access key
60+
* @return self
61+
*/
62+
public static function dom(string $key): self
63+
{
64+
if (empty(self::$inst[$key])) {
65+
self::$inst[$key] = self::withDom($key);
66+
}
67+
return self::$inst[$key];
68+
}
69+
70+
/**
71+
* Init DOM instance
72+
* @param string $key DOM access key
73+
* @return self
74+
*/
75+
public static function withDom(string $key): self
76+
{
77+
self::$inst[$key] = new self();
78+
return self::$inst[$key];
79+
}
80+
81+
/**
82+
* Create and bind tag to a key so it can be overwritten
83+
* @param string $tag HTML tag (without brackets)
84+
* @param string $key Bind tag to key
85+
* @param bool|boolean $prepend Prepend instead of append
86+
* @return ElementInterface
87+
*/
88+
public function bindTag(string $tag, string $key, bool $prepend = false): ElementInterface
89+
{
90+
if ($prepend) {
91+
$this->elem = $this->createPrepend($tag, null, $key);
92+
} else {
93+
$this->elem = $this->create($tag, null, $key);
94+
}
95+
return $this->elem;
96+
}
97+
98+
/**
99+
* Create (append) element
100+
*
101+
* @param string $element HTML tag (without brackets)
102+
* @param null $value add value to tag
103+
* @param string|null $bind
104+
* @return ElementInterface
105+
*/
106+
public function create($element, $value = null, ?string $bind = null): ElementInterface
107+
{
108+
$inst = new Element($element, $value);
109+
110+
if ($bind !== null) {
111+
$this->elements[$bind] = $inst;
112+
} else {
113+
$this->elements[] = $inst;
114+
}
115+
116+
return $inst;
117+
}
118+
119+
/**
120+
* Prepend element first
121+
* @param string $element HTML tag (without brackets)
122+
* @param string $value add value to tag
123+
* @return ElementInterface
124+
*/
125+
public function createPrepend(string $element, ?string $value = null, ?string $bind = null): ElementInterface
126+
{
127+
$inst = new Element($element, $value);
128+
if ($this->elements === null) {
129+
$this->elements = [];
130+
}
131+
if ($bind !== null) {
132+
//$new[$bind] = $inst;
133+
$this->elements = array_merge([$bind => $inst], $this->elements);
134+
} else {
135+
$this->elements = array_merge([$inst], $this->elements);
136+
}
137+
138+
return $inst;
139+
}
140+
141+
/**
142+
* Get one element from key
143+
* @return ElementInterface|null
144+
*/
145+
public function getElement(string $key): ?ElementInterface
146+
{
147+
return ($this->elements[$key] ?? null);
148+
}
149+
150+
/**
151+
* Get all elements
152+
* @return array
153+
*/
154+
public function getElements(): array
155+
{
156+
return $this->elements;
157+
}
158+
159+
/**
160+
* Get html tag
161+
* @param string $key
162+
* @return string|null
163+
*/
164+
public function getTag(string $key): ?string
165+
{
166+
return ($this->el[$key] ?? null);
167+
}
168+
169+
/**
170+
* Execute and get Dom/document
171+
* @param callable|null $call Can be used to manipulate element within feed
172+
* @return string
173+
*/
174+
public function execute(?callable $call = null): string
175+
{
176+
$this->html = "";
177+
178+
if ($this->elements === null) {
179+
if (method_exists($this, "withElement")) {
180+
$inst = $this->withElement();
181+
$this->elements[] = $inst;
182+
}
183+
}
184+
if (is_array($this->elements)) {
185+
$this->build($this->elements, $call);
186+
}
187+
188+
return $this->html;
189+
}
190+
191+
/**
192+
* Build document
193+
* @param array $arr elements
194+
* @param callable|null $call Can be used to manipulate element within feed
195+
* @return void
196+
*/
197+
private function build(array $arr, ?callable $call = null): void
198+
{
199+
foreach ($arr as $key => $elemObj) {
200+
$hasNoEnding = $this->elemHasEnding($elemObj->getEl());
201+
$this->buildCallable($elemObj, $key, $hasNoEnding, $call);
202+
203+
if (!$elemObj->hideTagValid()) {
204+
$this->html .= "\t<" . $elemObj->getEl() . $elemObj->buildAttr() . ">";
205+
}
206+
if (!$hasNoEnding) {
207+
$this->html .= $elemObj->getValue();
208+
}
209+
if (isset($elemObj->elements)) {
210+
$this->build($elemObj->elements, $call);
211+
}
212+
if (!$hasNoEnding && !$elemObj->hideTagValid()) {
213+
$this->html .= "</" . $elemObj->getEl() . ">\n";
214+
}
215+
if ($hasNoEnding && !$elemObj->hideTagValid()) {
216+
$this->html .= "\n";
217+
}
218+
}
219+
}
220+
221+
private function buildCallable($elemObj, $key, $hasNoEnding, ?callable $call): void
222+
{
223+
if ($call !== null) {
224+
$call($elemObj, $key, $hasNoEnding);
225+
}
226+
}
227+
228+
/**
229+
* Validate if element has ending
230+
* @param string $elem
231+
* @return bool
232+
*/
233+
final protected function elemHasEnding(string $elem): bool
234+
{
235+
return (in_array($elem, $this::TAG_NO_ENDING));
236+
}
237+
}

0 commit comments

Comments
 (0)