• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mixerapi / mixerapi-dev / 12990519882

27 Jan 2025 01:52PM UTC coverage: 87.726% (+0.3%) from 87.451%
12990519882

Pull #156

github

web-flow
Merge 49751d88f into 9d91f041b
Pull Request #156: Adds beforeSerialize and afterSerialize events

44 of 44 new or added lines in 3 files covered. (100.0%)

7 existing lines in 2 files now uncovered.

922 of 1051 relevant lines covered (87.73%)

3.29 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.0
/plugins/json-ld-view/src/JsonSerializer.php
1
<?php
2
declare(strict_types=1);
3

4
namespace MixerApi\JsonLdView;
5

6
use Cake\Core\Configure;
7
use Cake\Datasource\EntityInterface;
8
use Cake\Datasource\Paging\PaginatedResultSet;
9
use Cake\Datasource\ResultSetInterface;
10
use Cake\Event\Event;
11
use Cake\Event\EventManager;
12
use Cake\Http\ServerRequest;
13
use Cake\ORM\Entity;
14
use Cake\View\Helper\PaginatorHelper;
15
use MixerApi\Core\View\SerializableAssociation;
16
use ReflectionException;
17
use RuntimeException;
18

19
/**
20
 * Creates a JSON-LD resource
21
 *
22
 * @uses \MixerApi\Core\View\SerializableAssociation
23
 * @link https://json-ld.org/
24
 * @link https://lists.w3.org/Archives/Public/public-hydra/2015Oct/0163.html
25
 */
26
class JsonSerializer
27
{
28
    private ?ServerRequest $request;
29

30
    private ?PaginatorHelper $paginator;
31

32
    /**
33
     * JSON-LD data array
34
     *
35
     * @var mixed
36
     */
37
    private mixed $data;
38

39
    /**
40
     * JsonLd config
41
     *
42
     * @var array|null
43
     */
44
    private ?array $config;
45

46
    /**
47
     * @var string
48
     */
49
    private string $hydra = '';
50

51
    /**
52
     * If constructed without parameters collection meta data will not be added to JSON-LD $data
53
     *
54
     * @param mixed $serialize the data to be converted into a JSON-LD array
55
     * @param \Cake\Http\ServerRequest|null $request optional ServerRequest
56
     * @param \Cake\View\Helper\PaginatorHelper|null $paginator optional PaginatorHelper
57
     */
58
    public function __construct(mixed $serialize, ?ServerRequest $request = null, ?PaginatorHelper $paginator = null)
59
    {
60
        $this->request = $request;
8✔
61
        $this->paginator = $paginator;
8✔
62

63
        $jsonLd = $this->recursion($serialize);
8✔
64
        $this->config = Configure::read('JsonLdView');
8✔
65
        if (isset($this->config['isHydra']) && $this->config['isHydra']) {
8✔
UNCOV
66
            $this->hydra = 'hydra:';
×
67
        }
68

69
        if ($jsonLd instanceof ResultSetInterface || $jsonLd instanceof PaginatedResultSet) {
8✔
70
            $this->data = $this->collection($jsonLd);
4✔
71
        } elseif (is_subclass_of($jsonLd, Entity::class)) {
4✔
72
            $this->data = $this->item($jsonLd);
3✔
73
        } else {
74
            $this->data = $serialize;
1✔
75
        }
76
    }
77

78
    /**
79
     * Serializes data as json-ld
80
     *
81
     * @param int $jsonOptions JSON options see https://www.php.net/manual/en/function.json-encode.php
82
     * @return string
83
     * @throws \RuntimeException
84
     */
85
    public function asJson(int $jsonOptions = 0): string
86
    {
87
        EventManager::instance()->dispatch(new Event('MixerApi.JsonLdView.beforeSerialize', $this));
6✔
88

89
        $json = json_encode($this->data, $jsonOptions);
6✔
90

91
        if ($json === false) {
6✔
92
            throw new RuntimeException(json_last_error_msg(), json_last_error());
1✔
93
        }
94

95
        EventManager::instance()->dispatch(new Event('MixerApi.JsonLdView.afterSerialize', $this, [
5✔
96
            'data' => $json,
5✔
97
        ]));
5✔
98

99
        return $json;
5✔
100
    }
101

102
    /**
103
     * Get JSON-LD data as an array
104
     *
105
     * @return array|null
106
     */
107
    public function getData(): ?array
108
    {
109
        return $this->data;
2✔
110
    }
111

112
    /**
113
     * Recursive method for converting mixed data into JSON-LD. This method converts instances of Cake\ORM\Entity into
114
     * JSON-LD resources, but does not serialize the data.
115
     *
116
     * @param mixed $mixed data to be serialized
117
     * @return array|\Cake\Datasource\EntityInterface|\Cake\Datasource\ResultSetInterface
118
     */
119
    private function recursion(mixed &$mixed): mixed
120
    {
121
        if ($mixed instanceof ResultSetInterface || $mixed instanceof PaginatedResultSet || is_array($mixed)) {
8✔
122
            foreach ($mixed as $item) {
6✔
123
                $this->recursion($item);
6✔
124
            }
125
        } elseif ($mixed instanceof EntityInterface) {
8✔
126
            $serializableAssocation = new SerializableAssociation($mixed);
7✔
127

128
            $mixed = $this->resource($mixed, $serializableAssocation);
7✔
129

130
            foreach ($serializableAssocation->getAssociations() as $value) {
7✔
131
                $this->recursion($value);
6✔
132
            }
133
        }
134

135
        return $mixed;
8✔
136
    }
137

138
    /**
139
     * JSON-LD array for collection requests
140
     *
141
     * @param mixed $jsonLd the data to be converted into a JSON-LD array
142
     * @return array
143
     */
144
    private function collection(mixed $jsonLd): array
145
    {
146
        $return = [];
4✔
147

148
        try {
149
            if ($jsonLd instanceof PaginatedResultSet) {
4✔
150
                $entity = $jsonLd->toArray()[0];
1✔
151
            } else {
152
                $entity = $jsonLd->first();
3✔
153
            }
154

155
            if ($entity instanceof JsonLdDataInterface) {
4✔
156
                $return['@context'] = $entity->getJsonLdContext();
4✔
157
            }
UNCOV
158
        } catch (ReflectionException $e) {
×
159
        }
160

161
        if ($this->request instanceof ServerRequest) {
4✔
162
            $return['@id'] = $this->request->getPath();
4✔
163
        }
164

165
        $return['@type'] = $this->hydra . 'Collection';
4✔
166
        $return[$this->hydra . 'pageItems'] = intval($jsonLd->count());
4✔
167
        $return[$this->hydra . 'totalItems'] = null;
4✔
168

169
        if ($this->paginator instanceof PaginatorHelper) {
4✔
170
            $url = (string)$this->request->getUri();
4✔
171
            $id = parse_url($url, PHP_URL_PATH);
4✔
172
            $query = parse_url($url, PHP_URL_QUERY);
4✔
173

174
            if (!empty($query)) {
4✔
175
                $id .= '?' . $query;
1✔
176
            }
177

178
            $return['view'] = [
4✔
179
                '@id' => $id,
4✔
180
                '@type' => 'PartialCollectionView',
4✔
181
                $this->hydra . 'next' => $this->paginator->next(),
4✔
182
                $this->hydra . 'prev' => $this->paginator->prev(),
4✔
183
                $this->hydra . 'first' => $this->paginator->first(),
4✔
184
                $this->hydra . 'last' => $this->paginator->last(),
4✔
185
            ];
4✔
186
            $return[$this->hydra . 'totalItems'] = intval($this->paginator->counter());
4✔
187
        }
188

189
        $return[$this->hydra . 'member'] = $jsonLd;
4✔
190

191
        return $return;
4✔
192
    }
193

194
    /**
195
     * JSON-LD array for item requests
196
     *
197
     * @param mixed $jsonLd the data to be converted into a JSON-LD array
198
     * @return array
199
     */
200
    private function item(mixed $jsonLd): array
201
    {
202
        $links = [];
3✔
203

204
        if ($this->request instanceof ServerRequest) {
3✔
205
            $links['@id'] = $this->request->getPath();
3✔
206
        }
207

208
        if ($jsonLd instanceof JsonLdDataInterface) {
3✔
209
            $links['@type'] = $jsonLd->getJsonLdType();
3✔
210
            $links['@context'] = $jsonLd->getJsonLdContext();
3✔
211
        }
212

213
        if (!is_array($jsonLd)) {
3✔
214
            $jsonLd = $jsonLd->toArray();
3✔
215
        }
216

217
        return array_merge($links, $jsonLd);
3✔
218
    }
219

220
    /**
221
     * Creates a JSON-LD Resource
222
     *
223
     * Requires an instance of Cake\ORM\Entity or EntityInterface and a SerializableAssociation instance
224
     *
225
     * @param \Cake\Datasource\EntityInterface $entity Cake\ORM\Entity or EntityInterface
226
     * @param \MixerApi\Core\View\SerializableAssociation $serializable SerializableAssociation
227
     * @return \Cake\Datasource\EntityInterface
228
     */
229
    private function resource(EntityInterface $entity, SerializableAssociation $serializable): EntityInterface
230
    {
231
        foreach ($serializable->getAssociations() as $property => $value) {
7✔
232
            if (!is_array($value) && !$value instanceof EntityInterface) {
6✔
UNCOV
233
                $entity->unset($property);
×
234
            }
235
        }
236

237
        if ($entity instanceof JsonLdDataInterface) {
7✔
238
            $entity->set('@id', $entity->getJsonLdIdentifier($entity));
7✔
239
            $entity->set('@type', $entity->getJsonLdType());
7✔
240
            $entity->set('@context', $entity->getJsonLdContext());
7✔
241
        }
242

243
        return $entity;
7✔
244
    }
245
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc