Completed
Push — 2.0-dev ( 6b251c...6edcee )
by George
02:26
created

Cache   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 189
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 3

Test Coverage

Coverage 52.17%

Importance

Changes 9
Bugs 2 Features 1
Metric Value
wmc 17
c 9
b 2
f 1
lcom 2
cbo 3
dl 0
loc 189
ccs 24
cts 46
cp 0.5217
rs 10

10 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 3
A getItems() 0 11 2
A getOption() 0 4 2
deleteItem() 0 1 ?
A deleteItems() 0 14 3
A setOption() 0 6 1
hasItem() 0 1 ?
A saveDeferred() 0 6 1
A commit() 0 18 4
A convertItemExpiryToSeconds() 0 9 1
1
<?php
2
/**
3
 * Part of the Joomla Framework Cache Package
4
 *
5
 * @copyright  Copyright (C) 2005 - 2015 Open Source Matters, Inc. All rights reserved.
6
 * @license    GNU General Public License version 2 or later; see LICENSE
7
 */
8
9
namespace Joomla\Cache;
10
11
use Joomla\Cache\Item\HasExpirationDateInterface;
12
use Psr\Cache\CacheItemPoolInterface;
13
use Psr\Cache\CacheItemInterface;
14
use Joomla\Cache\Exception\InvalidArgumentException;
15
use DateTime;
16
17
/**
18
 * Joomla! Caching Class
19
 *
20
 * @since  1.0
21
 */
22
abstract class Cache implements CacheItemPoolInterface
23
{
24
	/**
25
	 * The options for the cache object.
26
	 *
27
	 * @var    \ArrayAccess
28
	 * @since  1.0
29
	 */
30
	protected $options;
31
32
	/**
33
	 * The deferred items to store
34
	 *
35
	 * @var    array
36
	 * @since  1.0
37
	 */
38
	private $deferred = array();
39
40
	/**
41
	 * Constructor.
42
	 *
43
	 * @param   mixed  $options  An options array, or an object that implements \ArrayAccess
44
	 *
45
	 * @since   1.0
46
	 * @throws  \RuntimeException
47
	 */
48 8
	public function __construct($options = array())
49
	{
50 8
		if (! ($options instanceof \ArrayAccess || is_array($options)))
51 8
		{
52 4
			throw new InvalidArgumentException(sprintf('%s requires an options array or an object that implements \\ArrayAccess', __CLASS__));
53
		}
54
55 8
		$this->options = $options;
0 ignored issues
show
Documentation Bug introduced by
It seems like $options can also be of type array. However, the property $options is declared as type object<ArrayAccess>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

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

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
56 8
	}
57
58
	/**
59
	 * Obtain multiple CacheItems by their unique keys.
60
	 *
61
	 * @param   array  $keys  A list of keys that can obtained in a single operation.
62
	 *
63
	 * @return  array  An associative array of CacheItem objects keyed on the cache key.
64
	 *
65
	 * @since   1.0
66
	 */
67 3
	public function getItems(array $keys = array())
68
	{
69 3
		$result = array();
70
71 3
		foreach ($keys as $key)
72
		{
73 3
			$result[$key] = $this->getItem($key);
74 3
		}
75
76 3
		return $result;
77
	}
78
79
	/**
80
	 * Get an option from the Cache instance.
81
	 *
82
	 * @param   string  $key  The name of the option to get.
83
	 *
84
	 * @return  mixed  The option value.
85
	 *
86
	 * @since   1.0
87
	 */
88 4
	public function getOption($key)
89
	{
90 4
		return isset($this->options[$key]) ? $this->options[$key] : null;
91
	}
92
93
	/**
94
	 * Delete a cached data entry by id.
95
	 *
96
	 * @param   string  $key  The cache data id.
97
	 *
98
	 * @return  boolean
99
	 *
100
	 * @since   1.0
101
	 */
102
	abstract public function deleteItem($key);
103
104
	/**
105
	 * Remove multiple cache items in a single operation.
106
	 *
107
	 * @param   array  $keys  The array of keys to be removed.
108
	 *
109
	 * @return  bool  True if the items were successfully removed. False if there was an error.
110
	 *
111
	 * @since   1.0
112
	 */
113 5
	public function deleteItems(array $keys)
114
	{
115 5
		$result = true;
116
117 5
		foreach ($keys as $key)
118
		{
119 5
			if (!$this->deleteItem($key))
120 5
			{
121
				$result = false;
122
			}
123 5
		}
124
125 5
		return $result;
126
	}
127
128
	/**
129
	 * Set an option for the Cache instance.
130
	 *
131
	 * @param   string  $key    The name of the option to set.
132
	 * @param   mixed   $value  The option value to set.
133
	 *
134
	 * @return  Cache  This object for method chaining.
135
	 *
136
	 * @since   1.0
137
	 */
138 4
	public function setOption($key, $value)
139
	{
140 4
		$this->options[$key] = $value;
141
142 4
		return $this;
143
	}
144
145
	/**
146
	 * Method to determine whether a storage entry has been set for a key.
147
	 *
148
	 * @param   string  $key  The storage entry identifier.
149
	 *
150
	 * @return  boolean
151
	 *
152
	 * @since   1.0
153
	 */
154
	abstract public function hasItem($key);
155
156
	/**
157
	 * Sets a cache item to be persisted later.
158
	 *
159
	 * @param   CacheItemInterface  $item  The cache item to save.
160
	 *
161
	 * @return  static  The invoked object.
162
	 */
163
	public function saveDeferred(CacheItemInterface $item)
164
	{
165
		$this->deferred[$item->getKey()] = $item;
166
167
		return $this;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this; (Joomla\Cache\Cache) is incompatible with the return type declared by the interface Psr\Cache\CacheItemPoolInterface::saveDeferred of type boolean.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
168
	}
169
170
	/**
171
	 * Persists any deferred cache items.
172
	 *
173
	 * @return  bool  TRUE if all not-yet-saved items were successfully saved. FALSE otherwise.
174
	 */
175
	public function commit()
176
	{
177
		$result = true;
178
179
		foreach ($this->deferred as $key => $deferred)
180
		{
181
			$saveResult = $this->save($deferred);
182
183
			if (true === $saveResult)
184
			{
185
				unset($this->deferred[$key]);
186
			}
187
188
			$result = $result && $saveResult;
189
		}
190
191
		return $result;
192
	}
193
194
	/**
195
	 * Converts the DateTime object from the cache item to the expiry time in seconds from the present
196
	 *
197
	 * @param   HasExpirationDateInterface  $item  The cache item
198
	 *
199
	 * @return  int  The time in seconds until expiry
200
	 */
201
	protected function convertItemExpiryToSeconds(HasExpirationDateInterface $item)
202
	{
203
		$itemExpiry = $item->getExpiration();
204
		$itemTimezone = $itemExpiry->getTimezone();
205
		$now = new DateTime('now', $itemTimezone);
206
		$interval = $now->diff($itemExpiry);
207
208
		return (int) $interval->format('%s');
209
	}
210
}
211