Completed
Push — 2.0-dev ( 7b1246...f2dca7 )
by George
02:26
created

Cache::deleteItem()

Size

Total Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 1
ccs 0
cts 0
cp 0
nc 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 12
	public function __construct($options = array())
49
	{
50 12
		if (! ($options instanceof \ArrayAccess || is_array($options)))
51 12
		{
52 4
			throw new InvalidArgumentException(sprintf('%s requires an options array or an object that implements \\ArrayAccess', __CLASS__));
53
		}
54
55 12
		$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 12
	}
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  array  An associative array of 'key' => result, elements. Each array row has the key being deleted
110
	 *                 and the result of that operation. The result will be a boolean of true or false
111
	 *                 representing if the cache item was removed or not
112
	 *
113
	 * @since   1.0
114
	 */
115 5
	public function deleteItems(array $keys)
116
	{
117 5
		$result = array();
118
119 5
		foreach ($keys as $key)
120
		{
121 5
			$result[$key] = $this->deleteItem($key);
122 5
		}
123
124 5
		return $result;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $result; (array) is incompatible with the return type declared by the interface Psr\Cache\CacheItemPoolInterface::deleteItems 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...
125
	}
126
127
	/**
128
	 * Set an option for the Cache instance.
129
	 *
130
	 * @param   string  $key    The name of the option to set.
131
	 * @param   mixed   $value  The option value to set.
132
	 *
133
	 * @return  Cache  This object for method chaining.
134
	 *
135
	 * @since   1.0
136
	 */
137 4
	public function setOption($key, $value)
138
	{
139 4
		$this->options[$key] = $value;
140
141 4
		return $this;
142
	}
143
144
	/**
145
	 * Method to determine whether a storage entry has been set for a key.
146
	 *
147
	 * @param   string  $key  The storage entry identifier.
148
	 *
149
	 * @return  boolean
150
	 *
151
	 * @since   1.0
152
	 */
153
	abstract public function hasItem($key);
154
155
	/**
156
	 * Sets a cache item to be persisted later.
157
	 *
158
	 * @param   CacheItemInterface  $item  The cache item to save.
159
	 *
160
	 * @return  static  The invoked object.
161
	 */
162
	public function saveDeferred(CacheItemInterface $item)
163
	{
164
		$this->deferred[$item->getKey()] = $item;
165
166
		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...
167
	}
168
169
	/**
170
	 * Persists any deferred cache items.
171
	 *
172
	 * @return  bool  TRUE if all not-yet-saved items were successfully saved. FALSE otherwise.
173
	 */
174
	public function commit()
175
	{
176
		$result = true;
177
178
		foreach ($this->deferred as $key => $deferred)
179
		{
180
			$saveResult = $this->save($deferred);
181
182
			if (true === $saveResult)
183
			{
184
				unset($this->deferred[$key]);
185
			}
186
187
			$result = $result && $saveResult;
188
		}
189
190
		return $result;
191
	}
192
193
	/**
194
	 * Converts the DateTime object from the cache item to the expiry time in seconds from the present
195
	 *
196
	 * @param   HasExpirationDateInterface  $item  The cache item
197
	 *
198
	 * @return  int  The time in seconds until expiry
199
	 */
200
	protected function convertItemExpiryToSeconds(HasExpirationDateInterface $item)
201
	{
202
		$itemExpiry = $item->getExpiration();
203
		$itemTimezone = $itemExpiry->getTimezone();
204
		$now = new DateTime('now', $itemTimezone);
205
		$interval = $now->diff($itemExpiry);
206
207
		return (int) $interval->format('%s');
208
	}
209
}
210