Completed
Pull Request — master (#2)
by Kevin
01:34
created

DBALObjectRepository::count()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 4
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 2
1
<?php
2
3
namespace Zenstruck\Porpaginas\Doctrine\Repository;
4
5
use Doctrine\DBAL\Connection;
6
use Doctrine\DBAL\Query\QueryBuilder;
7
use Zenstruck\Porpaginas\Doctrine\DBALQueryBuilderResult;
8
use Zenstruck\Porpaginas\Factory\FactoryResult;
9
use Zenstruck\Porpaginas\Repository;
10
use Zenstruck\Porpaginas\Result;
11
12
/**
13
 * @author Kevin Bond <[email protected]>
14
 */
15
abstract class DBALObjectRepository implements Repository
16
{
17
    public function getIterator(): Result
18
    {
19
        return self::createResult($this->qb());
20
    }
21
22
    public function count(): int
23
    {
24
        return $this->getIterator()->count();
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Traversable as the method count() does only exist in the following implementations of said interface: ArrayIterator, ArrayObject, CachingIterator, Doctrine\Common\Collections\AbstractLazyCollection, Doctrine\Common\Collections\ArrayCollection, Doctrine\ORM\LazyCriteriaCollection, Doctrine\ORM\PersistentCollection, Doctrine\ORM\Tools\Console\MetadataFilter, Doctrine\ORM\Tools\Pagination\Paginator, GlobIterator, HttpMessage, HttpRequestPool, Issue523, MongoCursor, MongoGridFSCursor, PHPUnit\Framework\DataProviderTestSuite, PHPUnit\Framework\TestSuite, PHP_Token_Stream, Pagerfanta\Pagerfanta, Phar, PharData, PharIo\Manifest\AuthorCollection, PharIo\Manifest\BundledComponentCollection, PharIo\Manifest\RequirementCollection, RecursiveArrayIterator, RecursiveCachingIterator, SQLiteResult, SebastianBergmann\CodeCoverage\Node\Directory, SimpleXMLElement, SimpleXMLIterator, SplDoublyLinkedList, SplFixedArray, SplHeap, SplMaxHeap, SplMinHeap, SplObjectStorage, SplPriorityQueue, SplQueue, SplStack, TheSeer\Tokenizer\TokenCollection, Zenstruck\Porpaginas\Doc...ry\DBALObjectRepository, Zenstruck\Porpaginas\Pager.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
25
    }
26
27
    abstract protected static function createObject(array $data): object;
28
29
    abstract protected static function tableName(): string;
30
31
    abstract protected function getConnection(): Connection;
32
33
    final protected static function createResult(QueryBuilder $qb): Result
34
    {
35
        return new FactoryResult(
36
            static function (array $data) {
37
                return static::createObject($data);
38
            },
39
            self::createDBALQueryBuilderResult($qb)
40
        );
41
    }
42
43
    protected static function createDBALQueryBuilderResult(QueryBuilder $qb): DBALQueryBuilderResult
44
    {
45
        return new DBALQueryBuilderResult($qb);
46
    }
47
48
    protected function qb(): QueryBuilder
49
    {
50
        return $this->getConnection()->createQueryBuilder()->select('*')->from(static::tableName());
51
    }
52
}
53