Completed
Push — master ( 6c409f...23b86d )
by James
11s
created

SimpleCacheAdapter::setMultiple()   B

Complexity

Conditions 5
Paths 7

Size

Total Lines 20
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 5

Importance

Changes 0
Metric Value
dl 0
loc 20
ccs 10
cts 10
cp 1
rs 8.8571
c 0
b 0
f 0
cc 5
eloc 10
nc 7
nop 2
crap 5
1
<?php
2
declare(strict_types = 1);
3
4
namespace Roave\DoctrineSimpleCache;
5
6
use Doctrine\Common\Cache\Cache as DoctrineCache;
7
use Doctrine\Common\Cache\ClearableCache;
8
use Doctrine\Common\Cache\MultiGetCache;
9
use Doctrine\Common\Cache\MultiPutCache;
10
use Psr\SimpleCache\CacheInterface as PsrCache;
11
use Roave\DoctrineSimpleCache\Exception\InvalidArgumentException;
12
13
final class SimpleCacheAdapter implements PsrCache
14
{
15
    /**
16
     * @var DoctrineCache|ClearableCache|MultiGetCache|MultiPutCache
17
     */
18
    private $doctrineCache;
19
20
    /**
21
     * @param DoctrineCache $doctrineCache
22
     * @throws \Roave\DoctrineSimpleCache\Exception\CacheException
23
     */
24 38
    public function __construct(DoctrineCache $doctrineCache)
25
    {
26 38
        $this->doctrineCache = $doctrineCache;
27
28 38
        if (!$this->doctrineCache instanceof ClearableCache) {
29 1
            throw Exception\CacheException::fromNonClearableCache($this->doctrineCache);
30
        }
31 37
        if (!$this->doctrineCache instanceof MultiGetCache) {
32 1
            throw Exception\CacheException::fromNonMultiGetCache($this->doctrineCache);
33
        }
34 36
        if (!$this->doctrineCache instanceof MultiPutCache) {
35 1
            throw Exception\CacheException::fromNonMultiPutCache($this->doctrineCache);
36
        }
37 35
    }
38
39
    /**
40
     * {@inheritDoc}
41
     */
42 5
    public function get($key, $default = null)
43
    {
44 5
        $value = $this->doctrineCache->fetch($key);
0 ignored issues
show
Bug introduced by
The method fetch does only exist in Doctrine\Common\Cache\Cache, but not in Doctrine\Common\Cache\Cl...mon\Cache\MultiPutCache.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
45 5
        if ($value === false) {
46 3
            return $default;
47
        }
48
49 5
        return $value;
50
    }
51
52
    /**
53
     * {@inheritDoc}
54
     */
55 14
    public function set($key, $value, $ttl = null) : bool
56
    {
57 14
        if ($ttl === null) {
58 1
            return $this->doctrineCache->save($key, $value);
0 ignored issues
show
Bug introduced by
The method save does only exist in Doctrine\Common\Cache\Cache, but not in Doctrine\Common\Cache\Cl...mon\Cache\MultiPutCache.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
59
        }
60
61 13
        if ($ttl instanceof \DateInterval) {
62 1
            $ttl = $this->convertDateIntervalToInteger($ttl);
63
        }
64
65 13
        if (!is_integer($ttl)) {
66 10
            throw InvalidArgumentException::fromKeyAndInvalidTTL($key, $ttl);
67
        }
68
69 3
        if ($ttl <= 0) {
70 1
            return $this->delete($key);
71
        }
72
73 3
        return $this->doctrineCache->save($key, $value, $ttl);
74
    }
75
76
    /**
77
     * {@inheritDoc}
78
     */
79 5
    public function delete($key) : bool
80
    {
81 5
        return $this->doctrineCache->delete($key);
0 ignored issues
show
Bug introduced by
The method delete does only exist in Doctrine\Common\Cache\Cache, but not in Doctrine\Common\Cache\Cl...mon\Cache\MultiPutCache.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
82
    }
83
84
    /**
85
     * {@inheritDoc}
86
     */
87 1
    public function clear() : bool
88
    {
89 1
        return $this->doctrineCache->deleteAll();
0 ignored issues
show
Bug introduced by
The method deleteAll does only exist in Doctrine\Common\Cache\ClearableCache, but not in Doctrine\Common\Cache\Ca...mon\Cache\MultiPutCache.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
90
    }
91
92
    /**
93
     * {@inheritDoc}
94
     */
95 3
    public function getMultiple($keys, $default = null)
96
    {
97 3
        return array_merge(array_fill_keys($keys, $default), $this->doctrineCache->fetchMultiple($keys));
0 ignored issues
show
Bug introduced by
The method fetchMultiple does only exist in Doctrine\Common\Cache\MultiGetCache, but not in Doctrine\Common\Cache\Ca...mon\Cache\MultiPutCache.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
Bug Best Practice introduced by
The return type of return array_merge(array...>fetchMultiple($keys)); (array) is incompatible with the return type declared by the interface Psr\SimpleCache\CacheInterface::getMultiple of type Psr\SimpleCache\iterable.

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...
98
    }
99
100
    /**
101
     * {@inheritDoc}
102
     */
103 14
    public function setMultiple($values, $ttl = null) : bool
104
    {
105 14
        if ($ttl === null) {
106 3
            return $this->doctrineCache->saveMultiple($values);
0 ignored issues
show
Bug introduced by
The method saveMultiple does only exist in Doctrine\Common\Cache\MultiPutCache, but not in Doctrine\Common\Cache\Ca...mon\Cache\MultiGetCache.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
107
        }
108
109 12
        if ($ttl instanceof \DateInterval) {
110 1
            $ttl = self::convertDateIntervalToInteger($ttl);
111
        }
112
113 12
        if (!is_integer($ttl)) {
114 10
            throw InvalidArgumentException::fromKeyAndInvalidTTL(key($values), $ttl);
115
        }
116
117 2
        if ($ttl <= 0) {
118 1
            return $this->deleteMultiple(array_keys($values));
0 ignored issues
show
Documentation introduced by
array_keys($values) is of type array, but the function expects a object<Psr\SimpleCache\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
119
        }
120
121 1
        return $this->doctrineCache->saveMultiple($values, $ttl);
122
    }
123
124
    /**
125
     * {@inheritDoc}
126
     */
127 3
    public function deleteMultiple($keys) : bool
128
    {
129 3
        $success = true;
130
131 3
        foreach ($keys as $key) {
132 3
            if (!$this->delete($key)) {
133 3
                $success = false;
134
            }
135
        }
136
137 3
        return $success;
138
    }
139
140
    /**
141
     * {@inheritDoc}
142
     */
143 1
    public function has($key) : bool
144
    {
145 1
        return $this->doctrineCache->contains($key);
0 ignored issues
show
Bug introduced by
The method contains does only exist in Doctrine\Common\Cache\Cache, but not in Doctrine\Common\Cache\Cl...mon\Cache\MultiPutCache.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
146
    }
147
148 2
    private function convertDateIntervalToInteger(\DateInterval $ttl) : int
149
    {
150
        // Timestamp has 2038 year limitation, but it's unlikely to set TTL that long.
151 2
        return (new \DateTime())
152 2
            ->setTimestamp(0)
153 2
            ->add($ttl)
154 2
            ->getTimestamp();
155
    }
156
}
157