Completed
Push — master ( 1ec5c0...49fc0a )
by Joschi
03:28
created

AbstractObjectMutator   A

Complexity

Total Complexity 29

Size/Duplication

Total Lines 252
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 96.49%

Importance

Changes 2
Bugs 0 Features 2
Metric Value
dl 0
loc 252
ccs 55
cts 57
cp 0.9649
rs 10
c 2
b 0
f 2
wmc 29
lcom 1
cbo 3

15 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A setTitle() 0 4 1
A setLocation() 0 9 2
A setDescription() 0 4 1
A setKeywords() 0 4 1
A setCategories() 0 4 1
A setAuthors() 0 9 2
B setAdditionalAuthor() 0 12 5
A setSyndication() 0 9 2
A setAdditionalSyndication() 0 12 1
A setFeatured() 0 4 1
A happens() 0 4 1
A formatRelation() 0 4 2
C __call() 0 23 7
A setAbstract() 0 4 1
1
<?php
2
3
/**
4
 * apparat-dev
5
 *
6
 * @category    Apparat
7
 * @package     Apparat\Dev
8
 * @subpackage  Apparat\Dev\Infrastructure
9
 * @author      Joschi Kuphal <[email protected]> / @jkphl
10
 * @copyright   Copyright © 2016 Joschi Kuphal <[email protected]> / @jkphl
11
 * @license     http://opensource.org/licenses/MIT The MIT License (MIT)
12
 */
13
14
/***********************************************************************************
15
 *  The MIT License (MIT)
16
 *
17
 *  Copyright © 2016 Joschi Kuphal <[email protected]> / @jkphl
18
 *
19
 *  Permission is hereby granted, free of charge, to any person obtaining a copy of
20
 *  this software and associated documentation files (the "Software"), to deal in
21
 *  the Software without restriction, including without limitation the rights to
22
 *  use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
23
 *  the Software, and to permit persons to whom the Software is furnished to do so,
24
 *  subject to the following conditions:
25
 *
26
 *  The above copyright notice and this permission notice shall be included in all
27
 *  copies or substantial portions of the Software.
28
 *
29
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
31
 *  FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
32
 *  COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
33
 *  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
34
 *  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35
 ***********************************************************************************/
36
37
namespace Apparat\Dev\Infrastructure\Mutator;
38
39
use Apparat\Dev\Ports\RuntimeException;
40
use Apparat\Object\Domain\Model\Object\ObjectInterface;
41
use Apparat\Object\Ports\Types\Relation;
42
use Faker\Generator;
43
44
/**
45
 * Abstract object mutator
46
 *
47
 * @package Apparat\Server
48
 * @subpackage Apparat\Dev\Infrastructure\Mutator
49
 * @method ObjectInterface setRandomTitle(ObjectInterface $object, $probability)
50
 * @method ObjectInterface setRandomDescription(ObjectInterface $object, $probability)
51
 * @method ObjectInterface setRandomAbstract(ObjectInterface $object, $probability)
52
 * @method ObjectInterface setRandomCategories(ObjectInterface $object, $probability)
53
 * @method ObjectInterface setRandomKeywords(ObjectInterface $object, $probability)
54
 * @method ObjectInterface setRandomLocation(ObjectInterface $object, $probability)
55
 * @method ObjectInterface setRandomSyndication(ObjectInterface $object, $probability)
56
 * @method ObjectInterface setRandomFeatured(ObjectInterface $object, $probability)
57
 * @method ObjectInterface setRandomAdditionalAuthor(ObjectInterface $object, $probability)
58
 * @method ObjectInterface setRandomAdditionalSyndication(ObjectInterface $object, $probability)
59
 */
60
abstract class AbstractObjectMutator implements ObjectMutatorInterface
61
{
62
    /**
63
     * Fake data generator
64
     *
65
     * @var Generator
66
     */
67
    protected $generator;
68
    /**
69
     * Twitter status URL
70
     *
71
     * @var string
72
     */
73
    const TWITTER_STATUS = 'https://twitter.com/%s/status/%s';
74
    /**
75
     * Facebook post URL
76
     *
77
     * @var string
78
     */
79
    const FACEBOOK_POST = 'https://www.facebook.com/%s/posts/%s';
80
    /**
81
     * Google+ post URL
82
     *
83
     * @var string
84
     */
85
    const GOOGLEPLUS_POST = 'https://plus.google.com/+%s/posts/%s';
86
    /**
87
     * Instagram post URL
88
     *
89
     * @var string
90
     */
91
    const INSTAGRAM_POST = 'https://www.instagram.com/p/%s/';
92
93
    /**
94
     * Abstract object mutator constructor
95
     *
96
     * @param Generator $generator
97
     */
98 2
    public function __construct(Generator $generator)
99
    {
100 2
        $this->generator = $generator;
101 2
    }
102
103
    /**
104
     * Magic setter for randomization of setter calls
105
     *
106
     * @param string $method Method name
107
     * @param array $arguments Arguments
108
     * @return ObjectInterface Object
109
     * @throws RuntimeException If the randomized setter is invalid
110
     */
111 4
    public function __call($method, array $arguments)
112
    {
113
        // If the randomized setter is invalid
114 4
        $setterMethod = 'set'.substr($method, 9);
115 4
        if (strncmp('setRandom', $method, 9) || !is_callable([$this, $setterMethod])) {
116 1
            throw new RuntimeException(
117 1
                sprintf('Invalid randomized setter "%s"', $setterMethod),
118 1
                RuntimeException::INVALID_RANDOMIZED_SETTER
119
            );
120
        }
121
122
        // If no object is given
123 3
        if (!count($arguments) || !($arguments[0] instanceof ObjectInterface)) {
124 1
            throw new RuntimeException('Invalid mutator subject', RuntimeException::INVALID_MUTATOR_SUBJECT);
125
        }
126
127
        // If the setter call should be randomized
128 2
        if ((count($arguments) > 1) && !$this->happens($arguments[1])) {
129 2
            return $arguments[0];
130
        }
131
132 2
        return $this->$setterMethod(...$arguments);
133
    }
134
135
136
    /**
137
     * Set the object title
138
     *
139
     * @param ObjectInterface $object Object
140
     * @return ObjectInterface $object Object
141
     */
142 2
    protected function setTitle(ObjectInterface $object)
143
    {
144 2
        return $object->setTitle($this->generator->text(70));
145
    }
146
147
    /**
148
     * Set the object title
149
     *
150
     * @param ObjectInterface $object Object
151
     * @return ObjectInterface $object Object
152
     */
153 2
    protected function setLocation(ObjectInterface $object)
154
    {
155
        /** @noinspection PhpUndefinedMethodInspection */
156 2
        $object = $object->setLatitude($this->generator->latitude());
157
        /** @noinspection PhpUndefinedMethodInspection */
158 2
        $object = $object->setLongitude($this->generator->longitude());
159
        /** @var $object ObjectInterface */
160 2
        return $this->happens(.3) ? $object->setElevation($this->generator->randomFloat(5, -10, 1000)) : $object;
161
    }
162
163
    /**
164
     * Set the object description
165
     *
166
     * @param ObjectInterface $object Object
167
     * @return ObjectInterface $object Object
168
     */
169 2
    protected function setDescription(ObjectInterface $object)
170
    {
171 2
        return $object->setDescription($this->generator->text(200));
172
    }
173
174
    /**
175
     * Set the object abstract
176
     *
177
     * @param ObjectInterface $object Object
178
     * @return ObjectInterface $object Object
179
     */
180
    protected function setAbstract(ObjectInterface $object)
181
    {
182
        return $object->setAbstract($this->generator->realText(250));
183
    }
184
185
    /**
186
     * Set the object keywords
187
     *
188
     * @param ObjectInterface $object Object
189
     * @return ObjectInterface $object Object
190
     */
191 2
    protected function setKeywords(ObjectInterface $object)
192
    {
193 2
        return $object->setKeywords($this->generator->words(rand(0, 5)));
0 ignored issues
show
Bug introduced by
It seems like $this->generator->words(rand(0, 5)) targeting Faker\Generator::words() can also be of type string; however, Apparat\Object\Domain\Mo...nterface::setKeywords() does only seem to accept array, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
194
    }
195
196
    /**
197
     * Set the object categories
198
     *
199
     * @param ObjectInterface $object Object
200
     * @return ObjectInterface $object Object
201
     */
202 2
    protected function setCategories(ObjectInterface $object)
203
    {
204 2
        return $object->setCategories($this->generator->words(rand(0, 5)));
0 ignored issues
show
Bug introduced by
It seems like $this->generator->words(rand(0, 5)) targeting Faker\Generator::words() can also be of type string; however, Apparat\Object\Domain\Mo...erface::setCategories() does only seem to accept array, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
205
    }
206
207
    /**
208
     * Set the object authors
209
     *
210
     * @param ObjectInterface $object Object
211
     * @return ObjectInterface $object Object
212
     */
213 2
    protected function setAuthors(ObjectInterface $object)
214
    {
215
        // Run through a random number of authors between 1 and 2
216 2
        for ($author = 0, $maxAuthors = rand(1, 2); $author < $maxAuthors; ++$author) {
217 2
            $this->setAdditionalAuthor($object);
218
        }
219
220 2
        return $object;
221
    }
222
223
    /**
224
     * Add an additional author to the object
225
     *
226
     * @param ObjectInterface $object Object
227
     * @return ObjectInterface
228
     */
229 2
    protected function setAdditionalAuthor(ObjectInterface $object)
230
    {
231 2
        $url = $this->happens(.3) ? $this->generator->url : '';
232 2
        $email = $this->happens(.7) ? $this->generator->email : '';
233 2
        $label = $this->happens(.5) ? $this->generator->name : '';
234 2
        $author = $this->formatRelation($url, $email, $label);
235 2
        if (strlen($author)) {
236 2
            $object->addRelation($author, Relation::CONTRIBUTED_BY);
237
        }
238
239 2
        return $object;
240
    }
241
242
    /**
243
     * Set the object syndication URLs
244
     *
245
     * @param ObjectInterface $object Object
246
     * @return ObjectInterface $object Object
247
     */
248 1
    protected function setSyndication(ObjectInterface $object)
249
    {
250
        // Run through a random number of syndication URLs between 1 and 3
251 1
        for ($syndication = 0, $maxSyndication = rand(1, 2); $syndication < $maxSyndication; ++$syndication) {
252 1
            $this->setAdditionalSyndication($object);
253
        }
254
255 1
        return $object;
256
    }
257
258
    /**
259
     * Add an additional syndication URL to the object
260
     *
261
     * @param ObjectInterface $object Object
262
     * @return ObjectInterface $object Object
263
     */
264 1
    protected function setAdditionalSyndication(ObjectInterface $object)
265
    {
266
        $syndicationUrls = [
267 1
            sprintf(self::TWITTER_STATUS, $this->generator->userName, $this->generator->creditCardNumber),
268 1
            sprintf(self::FACEBOOK_POST, $this->generator->userName, $this->generator->creditCardNumber),
269 1
            sprintf(self::GOOGLEPLUS_POST, $this->generator->userName,
270 1
                substr(base64_encode($this->generator->md5), 0, 12)),
271 1
            sprintf(self::INSTAGRAM_POST, substr(base64_encode($this->generator->md5), 0, 12))
272
        ];
273
274 1
        return $object->addRelation($this->generator->randomElement($syndicationUrls), Relation::SYNDICATED_TO);
0 ignored issues
show
Bug introduced by
The call to randomElement() misses some required arguments starting with $'b'.
Loading history...
275
    }
276
277
    /**
278
     * Set an object feature image
279
     *
280
     * @param ObjectInterface $object Object
281
     * @return ObjectInterface $object Object
282
     */
283 1
    protected function setFeatured(ObjectInterface $object)
284
    {
285 1
        return $object->setDomainProperty('featured', $this->generator->imageUrl(1024, 768));
286
    }
287
288
    /**
289
     * Create a random signal with a particular probability
290
     *
291
     * @param float $probability Probability
292
     * @return bool Signal
293
     */
294 2
    protected function happens($probability = 0.0)
295
    {
296 2
        return rand(0, 100) <= (max(0, min(1, floatval($probability))) * 100);
297
    }
298
299
    /**
300
     * Format a relation string
301
     *
302
     * @param string $url URL
303
     * @param string $email Email address
304
     * @param string $label Label
305
     * @return string Relation string
306
     */
307 2
    protected function formatRelation($url = '', $email = '', $label = '')
308
    {
309 2
        return implode(' ', array_filter([trim($url), trim($email) ? "<$email>" : '', trim($label)]));
310
    }
311
}
312