Skip to content

Commit db201bd

Browse files
initial
1 parent 8c2a580 commit db201bd

18 files changed

+866
-0
lines changed

.editorconfig

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
; This file is for unifying the coding style for different editors and IDEs.
2+
; More information at http://editorconfig.org
3+
4+
root = false
5+
6+
[*]
7+
indent_style = space
8+
indent_size = 4
9+
charset = "utf-8"
10+
end_of_line = lf
11+
insert_final_newline = true
12+
trim_trailing_whitespace = true
13+
14+
[*.yml]
15+
indent_style = space
16+
indent_size = 2

.gitignore

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
build/
2+
tmp/
3+
vendor/
4+
composer.lock
5+
.idea/

.scrutinizer.yml

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
imports:
2+
- php
3+
4+
filter:
5+
excluded_paths:
6+
- docs/
7+
- tests/
8+
tools:
9+
php_mess_detector: true
10+
php_cpd:
11+
excluded_dirs:
12+
- docs/
13+
- tests/
14+
php_loc:
15+
excluded_dirs:
16+
- docs/
17+
- tests/
18+
php_pdepend:
19+
excluded_dirs:
20+
1: docs/
21+
2: tests/

README.md

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# FractalTransformerView plugin for CakePHP
2+
3+
## Installation
4+
5+
You can install this plugin into your CakePHP application using [composer](http://getcomposer.org).
6+
7+
The recommended way to install composer packages is:
8+
9+
```
10+
composer require your-name-here/FractalTransformerView
11+
```

composer.json

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"name": "andrej-griniuk/cakephp-fractal-transformer-view",
3+
"description": "CakePHP view builder utilizing Fractal library for entities transformation",
4+
"type": "cakephp-plugin",
5+
"keywords": ["cakephp", "api", "json", "rest", "fractal"],
6+
"homepage": "http://github.com/andrej-griniuk/cakephp-fractal-transformer-view",
7+
"license": "MIT",
8+
"authors": [
9+
{
10+
"name": "Andrej Griniuk",
11+
"email": "[email protected]"
12+
}
13+
],
14+
"require": {
15+
"php": ">=5.5.0",
16+
"cakephp/cakephp": "~3.1",
17+
"league/fractal": "^0.13.0@dev"
18+
},
19+
"require-dev": {
20+
"phpunit/phpunit": "*"
21+
},
22+
"autoload": {
23+
"psr-4": {
24+
"FractalTransformerView\\": "src"
25+
}
26+
},
27+
"autoload-dev": {
28+
"psr-4": {
29+
"FractalTransformerView\\Test\\": "tests",
30+
"Cake\\Test\\": "./vendor/cakephp/cakephp/tests"
31+
}
32+
}
33+
}

phpunit.xml

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?xml version="1.0" encoding="UTF-8"?><phpunit
2+
colors="true"
3+
processIsolation="false"
4+
stopOnFailure="false"
5+
syntaxCheck="false"
6+
backupGlobals="false"
7+
bootstrap="./tests/bootstrap.php"
8+
>
9+
<php>
10+
<ini name="memory_limit" value="-1"/>
11+
<ini name="apc.enable_cli" value="1"/>
12+
</php>
13+
14+
<!-- Add any additional test suites you want to run here -->
15+
<testsuites>
16+
<testsuite name="Version Test Suite">
17+
<directory>./tests/TestCase</directory>
18+
</testsuite>
19+
</testsuites>
20+
21+
<filter>
22+
<blacklist>
23+
<directory suffix=".php">./docs</directory>
24+
<directory suffix=".php">./vendor</directory>
25+
<file>./tests/bootstrap.php</file>
26+
</blacklist>
27+
<!-- this is required, even if empty, until
28+
https://github.com/sebastianbergmann/phpunit/issues/1872
29+
is resolved -->
30+
<whitelist processUncoveredFilesFromWhitelist="true">
31+
<directory suffix=".php">src</directory>
32+
</whitelist>
33+
</filter>
34+
35+
<!-- Setup a listener for fixtures -->
36+
<listeners>
37+
<listener
38+
class="\Cake\TestSuite\Fixture\FixtureInjector"
39+
file="./vendor/cakephp/cakephp/src/TestSuite/Fixture/FixtureInjector.php">
40+
<arguments>
41+
<object class="\Cake\TestSuite\Fixture\FixtureManager" />
42+
</arguments>
43+
</listener>
44+
</listeners>
45+
46+
</phpunit>

src/Serializer/ArraySerializer.php

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
namespace FractalTransformerView\Serializer;
3+
4+
use League\Fractal\Serializer\ArraySerializer as Serializer;
5+
6+
class ArraySerializer extends Serializer
7+
{
8+
9+
public function collection($resourceKey, array $data)
10+
{
11+
return $data;
12+
}
13+
14+
}

src/View/FractalTransformerView.php

+165
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
<?php
2+
namespace FractalTransformerView\View;
3+
4+
use Cake\Event\EventManager;
5+
use Cake\Network\Request;
6+
use Cake\Network\Response;
7+
use FractalTransformerView\Serializer\ArraySerializer;
8+
use Cake\Core\Configure;
9+
use Cake\Datasource\EntityInterface;
10+
use Cake\ORM\Query;
11+
use Cake\ORM\ResultSet;
12+
use Cake\Utility\Hash;
13+
use Cake\View\JsonView;
14+
use Exception;
15+
use League\Fractal\Manager;
16+
use League\Fractal\Resource\Collection;
17+
use League\Fractal\Resource\Item;
18+
use League\Fractal\TransformerAbstract;
19+
20+
/**
21+
* FractalTransformerView class
22+
*/
23+
class FractalTransformerView extends JsonView
24+
{
25+
/**
26+
* Constructor
27+
*
28+
* @param \Cake\Network\Request $request Request instance.
29+
* @param \Cake\Network\Response $response Response instance.
30+
* @param \Cake\Event\EventManager $eventManager EventManager instance.
31+
* @param array $viewOptions An array of view options
32+
*/
33+
public function __construct(
34+
Request $request = null,
35+
Response $response = null,
36+
EventManager $eventManager = null,
37+
array $viewOptions = []
38+
) {
39+
parent::__construct($request, $response, $eventManager, $viewOptions);
40+
41+
$this->_specialVars[] = '_transform';
42+
}
43+
44+
/**
45+
* Get transform class name for given var by figuring out which entity it belongs to. Return FALSE otherwise
46+
*
47+
* @param $var
48+
* @return bool|string
49+
*/
50+
protected function getTransformerClass($var)
51+
{
52+
$entity = null;
53+
if ($var instanceof Query) {
54+
$entity = $var->repository()->newEntity();
55+
} elseif ($var instanceof ResultSet) {
56+
$entity = $var->first();
57+
} elseif ($var instanceof EntityInterface) {
58+
$entity = $var;
59+
} elseif (is_array($var)) {
60+
$entity = reset($var);
61+
}
62+
63+
if (!$entity || !is_object($entity)) {
64+
return false;
65+
}
66+
67+
$entityClass = get_class($entity);
68+
$transformerClass = str_replace('\\Model\\Entity\\', '\\Model\\Transformer\\', $entityClass) . 'Transformer';
69+
70+
if (!class_exists($transformerClass)) {
71+
return false;
72+
}
73+
74+
return $transformerClass;
75+
}
76+
77+
/**
78+
* Get transformer for given var
79+
*
80+
* @param $var
81+
* @param bool $varName
82+
* @return bool
83+
* @throws Exception
84+
*/
85+
protected function getTransformer($var, $varName = false)
86+
{
87+
$_transform = $this->get('_transform');
88+
$transformerClass = $varName
89+
? Hash::get((array)$_transform, $varName)
90+
: $_transform;
91+
92+
if (is_null($transformerClass)) {
93+
$transformerClass = $this->getTransformerClass($var);
94+
}
95+
96+
if ($transformerClass === false) {
97+
return false;
98+
}
99+
100+
if (!class_exists($transformerClass)) {
101+
throw new Exception(sprintf('Invalid Transformer class: %s', $transformerClass));
102+
}
103+
104+
$transformer = new $transformerClass;
105+
if (!($transformer instanceof TransformerAbstract)) {
106+
throw new Exception(sprintf('Transformer class not instance of TransformerAbstract: %s',
107+
$transformerClass));
108+
}
109+
110+
return $transformer;
111+
}
112+
113+
/**
114+
* Transform var using given manager
115+
*
116+
* @param Manager $manager
117+
* @param $var
118+
* @param bool $varName
119+
* @return array
120+
* @throws Exception
121+
*/
122+
protected function transform(Manager $manager, $var, $varName = false)
123+
{
124+
if (!$transformer = $this->getTransformer($var, $varName)) {
125+
return $var;
126+
}
127+
128+
if (is_array($var) || $var instanceof Query || $var instanceof ResultSet) {
129+
$resource = new Collection($var, $transformer);
130+
} elseif ($var instanceof EntityInterface) {
131+
$resource = new Item($var, $transformer);
132+
} else {
133+
throw new Exception('Unserializable variable');
134+
}
135+
136+
return $manager->createData($resource)->toArray();
137+
}
138+
139+
/**
140+
* Returns data to be serialized.
141+
*
142+
* @param bool $serialize
143+
* @return array|mixed
144+
* @throws Exception
145+
*/
146+
protected function _dataToSerialize($serialize = true)
147+
{
148+
$data = parent::_dataToSerialize($serialize);
149+
150+
$serializer = new ArraySerializer();
151+
$manager = new Manager();
152+
$manager->setSerializer($serializer);
153+
154+
if (is_array($data)) {
155+
foreach ($data as $varName => &$var) {
156+
$var = $this->transform($manager, $var, $varName);
157+
}
158+
unset($var);
159+
} else {
160+
$data = $this->transform($manager, $data);
161+
}
162+
163+
return $data;
164+
}
165+
}

tests/App/Model/Entity/Article.php

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
namespace FractalTransformerView\Test\App\Model\Entity;
4+
5+
use Cake\ORM\Entity;
6+
7+
/**
8+
* Tests entity class used for asserting correct loading
9+
*
10+
*/
11+
class Article extends Entity
12+
{
13+
14+
}

tests/App/Model/Entity/Author.php

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
namespace FractalTransformerView\Test\App\Model\Entity;
4+
5+
use Cake\ORM\Entity;
6+
7+
/**
8+
* Tests entity class used for asserting correct loading
9+
*
10+
*/
11+
class Author extends Entity
12+
{
13+
14+
}
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
namespace FractalTransformerView\Test\App\Model\Table;
3+
4+
use Cake\ORM\Table;
5+
6+
/**
7+
* Article table class
8+
*
9+
*/
10+
class ArticlesTable extends Table
11+
{
12+
13+
}
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
namespace FractalTransformerView\Test\App\Model\Table;
3+
4+
use Cake\ORM\Query;
5+
use Cake\ORM\Table;
6+
7+
/**
8+
* Author table class
9+
*
10+
*/
11+
class AuthorsTable extends Table
12+
{
13+
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
namespace FractalTransformerView\Test\App\Model\Transformer;
3+
4+
use FractalTransformerView\Test\App\Model\Entity\Article;
5+
use League\Fractal\TransformerAbstract;
6+
7+
class ArticleTransformer extends TransformerAbstract
8+
{
9+
/**
10+
* Creates a response item for each instance
11+
*
12+
* @param Article $article post entity
13+
* @return array transformed post
14+
*/
15+
public function transform(Article $article)
16+
{
17+
return [
18+
'title' => $article->get('title')
19+
];
20+
}
21+
}

0 commit comments

Comments
 (0)