Passed
Pull Request — master (#3)
by
unknown
04:03
created

UserData::setDependencies()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 1
1
<?php
2
3
namespace Charcoal\Object;
4
5
use DateTime;
6
use DateTimeInterface;
7
use Exception;
8
use InvalidArgumentException;
9
10
// From `pimple/pimple`
11
use Pimple\Container;
12
13
// From `charcoal-core`
14
use Charcoal\Model\AbstractModel;
15
16
// From `charcoal-translation`
17
use Charcoal\Translator\TranslatorAwareTrait;
18
19
// From `charcoal-object`
20
use Charcoal\Object\UserDataInterface;
21
22
/**
23
 * User Data is a base model for objects typically submitted by the end-user of the application.
24
 */
25
class UserData extends AbstractModel implements
26
    UserDataInterface
27
{
28
    use TranslatorAwareTrait;
29
30
    /**
31
     * Client IP address of the end-user.
32
     *
33
     * @var integer|null
34
     */
35
    private $ip;
36
37
    /**
38
     * Language of the end-user or source URI.
39
     *
40
     * @var string|null
41
     */
42
    private $lang;
43
44
    /**
45
     * Source URL or identifier of end-user submission.
46
     *
47
     * @var string|null
48
     */
49
    private $origin;
50
51
    /**
52
     * Creation timestamp of submission.
53
     *
54
     * @var DateTimeInterface|null
55
     */
56
    private $ts;
57
58
    /**
59
     * Dependencies
60
     * @param Container $container DI Container.
61
     * @return void
62
     */
63
    public function setDependencies(Container $container)
64
    {
65
        parent::setDependencies($container);
66
67
        $this->setTranslator($container['translator']);
68
    }
69
70
71
    /**
72
     * Set the client IP address.
73
     *
74
     * @param  integer|null $ip The remote IP at object creation.
75
     * @return UserDataInterface Chainable
76
     */
77
    public function setIp($ip)
78
    {
79
        if ($ip === null) {
80
            $this->ip = null;
81
            return $this;
82
        }
83
84
        if (is_string($ip)) {
85
            $ip = ip2long($ip);
86
        } elseif (is_numeric($ip)) {
87
            $ip = (int)$ip;
88
        } else {
89
            $ip = 0;
90
        }
91
92
        $this->ip = $ip;
93
94
        return $this;
95
    }
96
97
    /**
98
     * Retrieve the client IP address.
99
     *
100
     * @return integer|null
101
     */
102
    public function ip()
103
    {
104
        return $this->ip;
105
    }
106
107
    /**
108
     * Set the origin language.
109
     *
110
     * @param  string $lang The language code.
111
     * @throws InvalidArgumentException If the argument is not a string.
112
     * @return UserDataInterface Chainable
113
     */
114 View Code Duplication
    public function setLang($lang)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
115
    {
116
        if ($lang !== null) {
117
            if (!is_string($lang)) {
118
                throw new InvalidArgumentException(
119
                    'Language must be a string'
120
                );
121
            }
122
        }
123
124
        $this->lang = $lang;
125
126
        return $this;
127
    }
128
129
    /**
130
     * Retrieve the language.
131
     *
132
     * @return string
133
     */
134
    public function lang()
135
    {
136
        return $this->lang;
137
    }
138
139
    /**
140
     * Set the origin of the object submission.
141
     *
142
     * @param  string $origin The source URL or identifier of the submission.
143
     * @throws InvalidArgumentException If the argument is not a string.
144
     * @return UserDataInterface Chainable
145
     */
146 View Code Duplication
    public function setOrigin($origin)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
147
    {
148
        if ($origin !== null) {
149
            if (!is_string($origin)) {
150
                throw new InvalidArgumentException(
151
                    'Origin must be a string.'
152
                );
153
            }
154
        }
155
156
        $this->origin = $origin;
157
158
        return $this;
159
    }
160
161
    /**
162
     * Resolve the origin of the user data.
163
     *
164
     * @todo   Use PSR-7 Request, if available, instead of PHP's environment variables.
165
     * @return string
166
     */
167
    public function resolveOrigin()
0 ignored issues
show
Coding Style introduced by
resolveOrigin uses the super-global variable $GLOBALS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
168
    {
169
        $origin = '';
170
        if (PHP_SAPI == 'cli') {
171
            $argv = $GLOBALS['argv'];
172
173
            /** Assume its a Charcoal script */
174
            if (isset($argv[0])) {
175
                if (strpos($argv[0], 'bin/charcoal') !== false) {
176
                    $origin = array_slice($argv, 1);
177
                    $origin = implode(' ', $origin);
178
                } else {
179
                    $origin = implode(' ', $argv);
180
                }
181
            }
182
        } else {
183
            $host = getenv('HTTP_HOST');
184
            if ($host) {
185
                $origin = 'http';
186
187
                if (getenv('HTTPS') === 'on') {
188
                    $origin .= 's';
189
                }
190
191
                $origin .= '://'.$host;
192
            }
193
            $origin .= getenv('REQUEST_URI');
194
        }
195
196
        return $origin;
197
    }
198
199
    /**
200
     * Retrieve the origin of the object submission.
201
     *
202
     * @return string
203
     */
204
    public function origin()
205
    {
206
        return $this->origin;
207
    }
208
209
    /**
210
     * Set when the object was created.
211
     *
212
     * @param  DateTime|string|null $timestamp The timestamp at object's creation.
213
     *     NULL is accepted and instances of DateTimeInterface are recommended;
214
     *     any other value will be converted (if possible) into one.
215
     * @throws InvalidArgumentException If the timestamp is invalid.
216
     * @return UserDataInterface Chainable
217
     */
218 View Code Duplication
    public function setTs($timestamp)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
219
    {
220
        if ($timestamp === null) {
221
            $this->ts = null;
222
            return $this;
223
        }
224
225
        if (is_string($timestamp)) {
226
            try {
227
                $timestamp = new DateTime($timestamp);
228
            } catch (Exception $e) {
229
                throw new InvalidArgumentException(sprintf(
230
                    'Invalid timestamp: %s',
231
                    $e->getMessage()
232
                ), 0, $e);
233
            }
234
        }
235
236
        if (!$timestamp instanceof DateTimeInterface) {
237
            throw new InvalidArgumentException(
238
                'Invalid timestamp value. Must be a date/time string or a DateTime object.'
239
            );
240
        }
241
242
        $this->ts = $timestamp;
243
244
        return $this;
245
    }
246
247
    /**
248
     * Retrieve the creation timestamp.
249
     *
250
     * @return DateTime|null
251
     */
252
    public function ts()
253
    {
254
        return $this->ts;
255
    }
256
257
    /**
258
     * Event called before _creating_ the object.
259
     *
260
     * @see    Charcoal\Source\StorableTrait::preSave() For the "create" Event.
261
     * @return boolean
262
     */
263
    public function preSave()
264
    {
265
        $result = parent::preSave();
266
267
        $this->setTs('now');
268
269
        if (getenv('REMOTE_ADDR')) {
270
            $this->setIp(getenv('REMOTE_ADDR'));
271
        }
272
273
        if (!isset($this->origin)) {
274
            $this->setOrigin($this->resolveOrigin());
275
        }
276
277
        return $result;
278
    }
279
}
280