Skip to content

Commit 6bbdbdd

Browse files
committed
first commit
0 parents  commit 6bbdbdd

4 files changed

Lines changed: 279 additions & 0 deletions

File tree

composer.json

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"name": "focalstrategy/view_objects",
3+
"description": "Decouples data from the view",
4+
"authors": [
5+
{
6+
"name": "Shane Glee",
7+
"email": "shane@focalstrategy.com"
8+
}
9+
],
10+
"require": {
11+
"focalstrategy/filter":"^1.0"
12+
},
13+
"autoload": {
14+
"psr-4": {
15+
"FocalStrategy\\ViewObjects\\": "src"
16+
}
17+
},
18+
"config": {
19+
"github-oauth": {
20+
"github.com": "af8e077799a15b74a85ebe9c126db26b87fe69df"
21+
}
22+
}
23+
}

src/Fillable.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
3+
namespace FocalStrategy\ViewObjects;
4+
5+
interface Fillable
6+
{
7+
}

src/Transformer.php

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
<?php
2+
3+
namespace FocalStrategy\ViewObjects;
4+
5+
use Exception;
6+
use FocalStrategy\Filter\FilterManager;
7+
use FocalStrategy\Filter\HasFilterManager;
8+
use FocalStrategy\ViewObjects\Fillable;
9+
use Illuminate\Support\Collection;
10+
11+
class Transformer
12+
{
13+
private $from;
14+
private $nested = [];
15+
private $with = [];
16+
17+
public function __construct(FilterManager $filter)
18+
{
19+
$this->filter = $filter;
20+
}
21+
22+
/**
23+
* Set the from class, if not set Array is assumed.
24+
*
25+
* @param [type]
26+
*/
27+
public function from($class)
28+
{
29+
$this->from = $class;
30+
31+
return $this;
32+
}
33+
34+
/**
35+
* Set the to class, if not set Array is assumed.
36+
*
37+
* @param [type]
38+
*/
39+
public function to($class)
40+
{
41+
if (!class_implements($class, Fillable::class)) {
42+
throw new Exception('View Object does not implement Fillable');
43+
}
44+
45+
$this->to = $class;
46+
47+
return $this;
48+
}
49+
50+
public function with($data, $cl = null)
51+
{
52+
$name = 'setArray';
53+
if ($cl) {
54+
$name = 'set'.last(explode('\\', $cl));
55+
}
56+
$this->with[$name] = $data;
57+
58+
return $this;
59+
}
60+
61+
public function withNested($path, callable $nested)
62+
{
63+
$this->nested[$path] = $nested;
64+
65+
return $this;
66+
}
67+
68+
69+
public function transform($data)
70+
{
71+
$single = false;
72+
if (!($data instanceof Collection) && !is_array($data)) {
73+
$data = collect([$data]);
74+
$single = true;
75+
}
76+
77+
78+
$result = collect([]);
79+
if (count($data) > 0) {
80+
if ($this->from == null
81+
|| get_class($data->first()) === $this->from
82+
|| get_class($data->get(0)) === $this->from) {
83+
$target = $this->to;
84+
85+
if ($target === null) {
86+
$result = $data->map(function ($itm) use ($target) {
87+
$cl = is_array($itm) ? $itm : $itm->toArray();
88+
89+
return $cl;
90+
});
91+
} else {
92+
$result = $data->map(function ($itm) use ($target) {
93+
$cl = new $target();
94+
$name = 'setArray';
95+
if ($this->from != null) {
96+
$name = 'set'.last(explode('\\', $this->from));
97+
}
98+
99+
$cl->$name($itm);
100+
101+
$cl = $this->handleNested($itm, $cl);
102+
$cl = $this->handleWiths($cl);
103+
104+
if ($this->hasTrait(HasFilterManager::class)) {
105+
$cl->setFilterManager($this->filter);
106+
}
107+
return $cl;
108+
});
109+
}
110+
} else {
111+
throw new Exception('From '.get_class($data->first()).' does not match expected '.($this->from));
112+
}
113+
}
114+
115+
return $single ? $result->first() : $result;
116+
}
117+
118+
public function handleNested($obj, $cl)
119+
{
120+
if (count($this->nested) > 0) {
121+
foreach ($this->nested as $path => $callable) {
122+
if ($obj->{$path} != null) {
123+
$result = $callable(new self($this->filter), $obj->{$path});
124+
$cl->$path = $result;
125+
}
126+
}
127+
}
128+
return $cl;
129+
}
130+
131+
public function handleWiths($cl)
132+
{
133+
foreach ($this->with as $method => $data) {
134+
$cl->$method($data);
135+
}
136+
return $cl;
137+
}
138+
139+
private function hasTrait($source, $trait)
140+
{
141+
return in_array($trait, class_uses($source));
142+
}
143+
}

src/ViewObject.php

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
<?php
2+
3+
namespace FocalStrategy\ViewObjects;
4+
5+
use JsonSerializable;
6+
use FocalStrategy\ViewObjects\Fillable;
7+
use ArrayAccess;
8+
9+
abstract class ViewObject implements Fillable, JsonSerializable, ArrayAccess
10+
{
11+
protected $required = [];
12+
protected $data = [];
13+
14+
/**
15+
* @param array Data to pass in, should be overriden in a subclass
16+
*/
17+
public function __construct(array $required = [])
18+
{
19+
$this->required = $required;
20+
}
21+
22+
/**
23+
* @param string Property Name
24+
*
25+
* @return string|null
26+
*/
27+
public function __get($name)
28+
{
29+
if (isset($this->data[$name])) {
30+
return $this->data[$name];
31+
}
32+
33+
return;
34+
}
35+
36+
public function __set($key, $value)
37+
{
38+
$this->data[$key] = $value;
39+
}
40+
41+
public function __isset($name)
42+
{
43+
return isset($this->data[$name]);
44+
}
45+
46+
/**
47+
* From JsonSerializable interface - allows json_encode to work.
48+
*
49+
* @return string
50+
*/
51+
public function jsonSerialize()
52+
{
53+
$this->checkRequired();
54+
55+
return $this->data;
56+
}
57+
58+
public function raw()
59+
{
60+
$this->checkRequired();
61+
62+
return $this->data;
63+
}
64+
65+
public function offsetSet($offset, $value)
66+
{
67+
if (is_null($offset)) {
68+
$this->data[] = $value;
69+
} else {
70+
$this->data[$offset] = $value;
71+
}
72+
}
73+
74+
public function offsetExists($offset)
75+
{
76+
return isset($this->data[$offset]);
77+
}
78+
79+
public function offsetUnset($offset)
80+
{
81+
unset($this->data[$offset]);
82+
}
83+
84+
public function offsetGet($offset)
85+
{
86+
return isset($this->data[$offset]) ? $this->data[$offset] : null;
87+
}
88+
89+
public static function getFactory()
90+
{
91+
if (property_exists(get_called_class(), 'factory')) {
92+
$c = get_called_class();
93+
return $c::$factory;
94+
}
95+
return null;
96+
}
97+
98+
private function checkRequired()
99+
{
100+
foreach ($this->required as $required) {
101+
if (!isset($this->data[$required]) || $this->data[$required] === null) {
102+
throw new \Exception('Missing required field: '.$required);
103+
}
104+
}
105+
}
106+
}

0 commit comments

Comments
 (0)