AbstractObjectMutator::happens()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 4
ccs 2
cts 2
cp 1
crap 1
rs 10
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\Dev
48
 * @subpackage Apparat\Dev\Infrastructure
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
     * Twitter status URL
64
     *
65
     * @var string
66
     */
67
    const TWITTER_STATUS = 'https://twitter.com/%s/status/%s';
68
    /**
69
     * Facebook post URL
70
     *
71
     * @var string
72
     */
73
    const FACEBOOK_POST = 'https://www.facebook.com/%s/posts/%s';
74
    /**
75
     * Google+ post URL
76
     *
77
     * @var string
78
     */
79
    const GOOGLEPLUS_POST = 'https://plus.google.com/+%s/posts/%s';
80
    /**
81
     * Instagram post URL
82
     *
83
     * @var string
84
     */
85
    const INSTAGRAM_POST = 'https://www.instagram.com/p/%s/';
86
    /**
87
     * Fake data generator
88
     *
89
     * @var Generator
90
     */
91
    protected $generator;
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
     * Create a random signal with a particular probability
137
     *
138
     * @param float $probability Probability
139
     * @return bool Signal
140
     */
141 2
    protected function happens($probability = 0.0)
142
    {
143 2
        return rand(0, 100) <= (max(0, min(1, floatval($probability))) * 100);
144
    }
145
146
    /**
147
     * Set the object title
148
     *
149
     * @param ObjectInterface $object Object
150
     * @return ObjectInterface $object Object
151
     */
152 2
    protected function setTitle(ObjectInterface $object)
153
    {
154 2
        return $object->setTitle($this->generator->text(70));
155
    }
156
157
    /**
158
     * Set the object title
159
     *
160
     * @param ObjectInterface $object Object
161
     * @return ObjectInterface $object Object
162
     */
163 2
    protected function setLocation(ObjectInterface $object)
164
    {
165
        /** @noinspection PhpUndefinedMethodInspection */
166 2
        $object = $object->setLatitude($this->generator->latitude());
167
        /** @noinspection PhpUndefinedMethodInspection */
168 2
        $object = $object->setLongitude($this->generator->longitude());
169
        /** @var $object ObjectInterface */
170 2
        return $this->happens(.3) ? $object->setElevation($this->generator->randomFloat(5, -10, 1000)) : $object;
171
    }
172
173
    /**
174
     * Set the object description
175
     *
176
     * @param ObjectInterface $object Object
177
     * @return ObjectInterface $object Object
178
     */
179 2
    protected function setDescription(ObjectInterface $object)
180
    {
181 2
        return $object->setDescription($this->generator->text(200));
182
    }
183
184
    /**
185
     * Set the object abstract
186
     *
187
     * @param ObjectInterface $object Object
188
     * @return ObjectInterface $object Object
189
     */
190 2
    protected function setAbstract(ObjectInterface $object)
191
    {
192 2
        return $object->setAbstract($this->generator->realText(250));
193
    }
194
195
    /**
196
     * Set the object keywords
197
     *
198
     * @param ObjectInterface $object Object
199
     * @return ObjectInterface $object Object
200
     */
201 2
    protected function setKeywords(ObjectInterface $object)
202
    {
203 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...
204
    }
205
206
    /**
207
     * Set the object categories
208
     *
209
     * @param ObjectInterface $object Object
210
     * @return ObjectInterface $object Object
211
     */
212 2
    protected function setCategories(ObjectInterface $object)
213
    {
214 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...
215
    }
216
217
    /**
218
     * Set the object authors
219
     *
220
     * @param ObjectInterface $object Object
221
     * @return ObjectInterface $object Object
222
     */
223 2
    protected function setAuthors(ObjectInterface $object)
224
    {
225
        // Run through a random number of authors between 1 and 2
226 2
        for ($author = 0, $maxAuthors = rand(1, 2); $author < $maxAuthors; ++$author) {
227 2
            $this->setAdditionalAuthor($object);
228
        }
229
230 2
        return $object;
231
    }
232
233
    /**
234
     * Add an additional author to the object
235
     *
236
     * @param ObjectInterface $object Object
237
     * @return ObjectInterface
238
     */
239 2
    protected function setAdditionalAuthor(ObjectInterface $object)
240
    {
241 2
        $url = $this->happens(.3) ? $this->generator->url : '';
242 2
        $email = $this->happens(.7) ? $this->generator->email : '';
243 2
        $label = $this->happens(.5) ? $this->generator->name : '';
244 2
        $author = $this->formatRelation($url, $email, $label);
245 2
        if (strlen($author)) {
246 2
            $object->addRelation($author, Relation::CONTRIBUTED_BY);
247
        }
248
249 2
        return $object;
250
    }
251
252
    /**
253
     * Format a relation string
254
     *
255
     * @param string $url URL
256
     * @param string $email Email address
257
     * @param string $label Label
258
     * @return string Relation string
259
     */
260 2
    protected function formatRelation($url = '', $email = '', $label = '')
261
    {
262 2
        return implode(' ', array_filter([trim($url), trim($email) ? "<$email>" : '', trim($label)]));
263
    }
264
265
    /**
266
     * Set the object syndication URLs
267
     *
268
     * @param ObjectInterface $object Object
269
     * @return ObjectInterface $object Object
270
     */
271 1
    protected function setSyndication(ObjectInterface $object)
272
    {
273
        // Run through a random number of syndication URLs between 1 and 3
274 1
        for ($syndication = 0, $maxSyndication = rand(1, 2); $syndication < $maxSyndication; ++$syndication) {
275 1
            $this->setAdditionalSyndication($object);
276
        }
277
278 1
        return $object;
279
    }
280
281
    /**
282
     * Add an additional syndication URL to the object
283
     *
284
     * @param ObjectInterface $object Object
285
     * @return ObjectInterface $object Object
286
     */
287 1
    protected function setAdditionalSyndication(ObjectInterface $object)
288
    {
289
        $syndicationUrls = [
290 1
            sprintf(self::TWITTER_STATUS, $this->generator->userName, $this->generator->creditCardNumber),
291 1
            sprintf(self::FACEBOOK_POST, $this->generator->userName, $this->generator->creditCardNumber),
292 1
            sprintf(
293 1
                self::GOOGLEPLUS_POST,
294 1
                $this->generator->userName,
295 1
                substr(base64_encode($this->generator->md5), 0, 12)
296
            ),
297 1
            sprintf(self::INSTAGRAM_POST, substr(base64_encode($this->generator->md5), 0, 12))
298
        ];
299
300 1
        return $object->addRelation($this->generator->randomElement($syndicationUrls), Relation::SYNDICATED_TO);
301
    }
302
303
    /**
304
     * Set an object feature image
305
     *
306
     * @param ObjectInterface $object Object
307
     * @return ObjectInterface $object Object
308
     */
309 1
    protected function setFeatured(ObjectInterface $object)
310
    {
311 1
        return $object->setDomain('featured', $this->generator->imageUrl(1024, 768));
312
    }
313
}
314