Completed
Pull Request — master (#13)
by Hyunwoo
08:12 queued 02:24
created

SimpleCacheAdapter::has()   A

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
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
crap 1
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
12
final class SimpleCacheAdapter implements PsrCache
13
{
14
    /**
15
     * @var DoctrineCache|ClearableCache|MultiGetCache|MultiPutCache
16
     */
17
    private $doctrineCache;
18
19
    /**
20
     * @param DoctrineCache $doctrineCache
21
     * @throws \Roave\DoctrineSimpleCache\Exception\CacheException
22
     */
23 14
    public function __construct(DoctrineCache $doctrineCache)
24
    {
25 14
        $this->doctrineCache = $doctrineCache;
26
27 14
        if (!$this->doctrineCache instanceof ClearableCache) {
28 1
            throw Exception\CacheException::fromNonClearableCache($this->doctrineCache);
29
        }
30 13
        if (!$this->doctrineCache instanceof MultiGetCache) {
31 1
            throw Exception\CacheException::fromNonMultiGetCache($this->doctrineCache);
32
        }
33 12
        if (!$this->doctrineCache instanceof MultiPutCache) {
34 1
            throw Exception\CacheException::fromNonMultiPutCache($this->doctrineCache);
35
        }
36 11
    }
37
38
    /**
39
     * {@inheritDoc}
40
     */
41 2
    public function get($key, $default = null)
42
    {
43 2
        $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...
44 2
        if ($value === false) {
45 1
            return $default;
46
        }
47
48 2
        return $value;
49
    }
50
51
    /**
52
     * {@inheritDoc}
53
     */
54 2
    public function set($key, $value, $ttl = null) : bool
55
    {
56 2
        if ($ttl === null) {
57 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...
58
        }
59
60 1
        if ($ttl instanceof \DateInterval) {
61
            $ttl = self::convertDateIntervalToInteger($ttl);
62
        }
63
64 1
        if (!is_integer($ttl)) {
65
            throw InvalidArgumentException::fromKeyAndInvalidTTL($key, $ttl);
66
        }
67
68 1
        if ($ttl <= 0) {
69
            return $this->delete($key);
70
        }
71
72 1
        return $this->doctrineCache->save($key, $value, $ttl);
73
    }
74
75
    /**
76
     * {@inheritDoc}
77
     */
78 3
    public function delete($key) : bool
79
    {
80 3
        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...
81
    }
82
83
    /**
84
     * {@inheritDoc}
85
     */
86 1
    public function clear() : bool
87
    {
88 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...
89
    }
90
91
    /**
92
     * {@inheritDoc}
93
     */
94 2
    public function getMultiple($keys, $default = null)
95
    {
96 2
        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...
97
    }
98
99
    /**
100
     * {@inheritDoc}
101
     */
102 2
    public function setMultiple($values, $ttl = null) : bool
103
    {
104 2
        if ($ttl === null) {
105 2
            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...
106
        }
107
108
        if ($ttl instanceof \DateInterval) {
109
            $ttl = self::convertDateIntervalToInteger($ttl);
110
        }
111
112
        if (!is_integer($ttl)) {
113
            throw InvalidArgumentException::fromKeyAndInvalidTTL(key($values), $ttl);
114
        }
115
116
        if ($ttl <= 0) {
117
            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...
118
        }
119
120
        return $this->doctrineCache->saveMultiple($values, $ttl);
121
    }
122
123
    /**
124
     * {@inheritDoc}
125
     */
126 2
    public function deleteMultiple($keys) : bool
127
    {
128 2
        $success = true;
129
130 2
        foreach ($keys as $key) {
131 2
            if (!$this->delete($key)) {
132 2
                $success = false;
133
            }
134
        }
135
136 2
        return $success;
137
    }
138
139
    /**
140
     * {@inheritDoc}
141
     */
142 1
    public function has($key) : bool
143
    {
144 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...
145
    }
146
147
    private static function convertDateIntervalToInteger(\DateInterval $ttl) : int
148
    {
149
        // Timestamp has 2038 year limitation, but it's unlikely to set TTL that long.
150
        return (new \DateTime())
151
            ->setTimestamp(0)
152
            ->add($ttl)
153
            ->getTimestamp();
154
    }
155
}
156