Failed Conditions
Pull Request — develop (#6719)
by Marco
64:55
created

testSkipAbstractClassesOnGeneration()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 10
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 5
nc 1
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\Tests\ORM\Proxy;
6
7
use Doctrine\ORM\EntityNotFoundException;
8
use Doctrine\ORM\Mapping\ClassMetadata;
9
use Doctrine\ORM\Mapping\ClassMetadataBuildingContext;
10
use Doctrine\ORM\Mapping\ClassMetadataFactory;
11
use Doctrine\ORM\Persisters\Entity\BasicEntityPersister;
12
use Doctrine\ORM\Proxy\Factory\StaticProxyFactory;
13
use Doctrine\ORM\Reflection\RuntimeReflectionService;
14
use Doctrine\Tests\Mocks\ConnectionMock;
15
use Doctrine\Tests\Mocks\DriverMock;
16
use Doctrine\Tests\Mocks\EntityManagerMock;
17
use Doctrine\Tests\Mocks\UnitOfWorkMock;
18
use Doctrine\Tests\Models\Company\CompanyEmployee;
19
use Doctrine\Tests\Models\ECommerce\ECommerceFeature;
20
use Doctrine\Tests\OrmTestCase;
21
use ProxyManager\Proxy\GhostObjectInterface;
22
23
/**
24
 * Test the proxy generator. Its work is generating on-the-fly subclasses of a given model, which implement the Proxy pattern.
25
 * @author Giorgio Sironi <[email protected]>
26
 */
27
class ProxyFactoryTest extends OrmTestCase
28
{
29
    /**
30
     * @var ConnectionMock
31
     */
32
    private $connectionMock;
33
34
    /**
35
     * @var UnitOfWorkMock
36
     */
37
    private $uowMock;
38
39
    /**
40
     * @var EntityManagerMock
41
     */
42
    private $emMock;
43
44
    /**
45
     * @var StaticProxyFactory
46
     */
47
    private $proxyFactory;
48
49
    /**
50
     * @var ClassMetadataBuildingContext
51
     */
52
    private $metadataBuildingContext;
53
54
    /**
55
     * {@inheritDoc}
56
     */
57
    protected function setUp()
58
    {
59
        parent::setUp();
60
61
        $this->metadataBuildingContext = new ClassMetadataBuildingContext(
62
            $this->createMock(ClassMetadataFactory::class),
63
            new RuntimeReflectionService()
64
        );
65
        $this->connectionMock          = new ConnectionMock([], new DriverMock());
66
        $this->emMock                  = EntityManagerMock::create($this->connectionMock);
67
        $this->uowMock                 = new UnitOfWorkMock($this->emMock);
68
69
        $this->emMock->setUnitOfWork($this->uowMock);
70
71
        $this->proxyFactory = new StaticProxyFactory(
72
            $this->emMock,
73
            $this->emMock->getConfiguration()->buildGhostObjectFactory()
74
        );
75
    }
76
77
    public function testReferenceProxyDelegatesLoadingToThePersister()
78
    {
79
        $identifier    = ['id' => 42];
80
        $classMetaData = $this->emMock->getClassMetadata(ECommerceFeature::class);
81
82
        $persister = $this
83
            ->getMockBuilder(BasicEntityPersister::class)
84
            ->setConstructorArgs([$this->emMock, $classMetaData])
85
            ->setMethods(['loadById'])
86
            ->getMock();
87
88
        $persister
89
            ->expects($this->atLeastOnce())
90
            ->method('loadById')
91
            ->with(
92
                $identifier,
93
                self::logicalAnd(
94
                    self::isInstanceOf(GhostObjectInterface::class),
95
                    self::isInstanceOf(ECommerceFeature::class)
96
                )
97
            )
98
            ->will($this->returnValue(new \stdClass()));
99
100
        $this->uowMock->setEntityPersister(ECommerceFeature::class, $persister);
101
102
        /* @var $proxy GhostObjectInterface|ECommerceFeature */
103
        $proxy = $this->proxyFactory->getProxy(ECommerceFeature::class, $identifier);
104
105
        $proxy->getDescription();
0 ignored issues
show
Bug introduced by
The method getDescription does only exist in Doctrine\Tests\Models\ECommerce\ECommerceFeature, but not in ProxyManager\Proxy\GhostObjectInterface.

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
    /**
109
     * @group DDC-1771
110
     */
111
    public function testSkipAbstractClassesOnGeneration()
112
    {
113
        $cm = new ClassMetadata(AbstractClass::class, $this->metadataBuildingContext);
114
115
        self::assertNotNull($cm->getReflectionClass());
116
117
        $num = $this->proxyFactory->generateProxyClasses([$cm]);
118
119
        self::assertEquals(0, $num, "No proxies generated.");
120
    }
121
122
    /**
123
     * @group DDC-2432
124
     */
125 View Code Duplication
    public function testFailedProxyLoadingDoesNotMarkTheProxyAsInitialized()
126
    {
127
        $classMetaData = $this->emMock->getClassMetadata(ECommerceFeature::class);
128
129
        $persister = $this
130
            ->getMockBuilder(BasicEntityPersister::class)
131
            ->setConstructorArgs([$this->emMock, $classMetaData])
132
            ->setMethods(['load'])
133
            ->getMock();
134
135
        $persister
136
            ->expects($this->atLeastOnce())
137
            ->method('load')
138
            ->will($this->returnValue(null));
139
140
        $this->uowMock->setEntityPersister(ECommerceFeature::class, $persister);
141
142
        /* @var $proxy GhostObjectInterface|ECommerceFeature */
143
        $proxy = $this->proxyFactory->getProxy(ECommerceFeature::class, ['id' => 42]);
144
145
        try {
146
            $proxy->getDescription();
0 ignored issues
show
Bug introduced by
The method getDescription does only exist in Doctrine\Tests\Models\ECommerce\ECommerceFeature, but not in ProxyManager\Proxy\GhostObjectInterface.

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...
147
            $this->fail('An exception was expected to be raised');
148
        } catch (EntityNotFoundException $exception) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
149
        }
150
151
        self::assertFalse($proxy->isProxyInitialized());
0 ignored issues
show
Bug introduced by
The method isProxyInitialized does only exist in ProxyManager\Proxy\GhostObjectInterface, but not in Doctrine\Tests\Models\ECommerce\ECommerceFeature.

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...
152
    }
153
154
    /**
155
     * @group DDC-2432
156
     */
157 View Code Duplication
    public function testFailedProxyCloningDoesNotMarkTheProxyAsInitialized()
158
    {
159
        $classMetaData = $this->emMock->getClassMetadata(ECommerceFeature::class);
160
161
        $persister = $this
162
            ->getMockBuilder(BasicEntityPersister::class)
163
            ->setConstructorArgs([$this->emMock, $classMetaData])
164
            ->setMethods(['load'])
165
            ->getMock();
166
167
        $persister
168
            ->expects($this->atLeastOnce())
169
            ->method('load')
170
            ->will($this->returnValue(null));
171
172
        $this->uowMock->setEntityPersister(ECommerceFeature::class, $persister);
173
174
        /* @var $proxy GhostObjectInterface|ECommerceFeature */
175
        $proxy = $this->proxyFactory->getProxy(ECommerceFeature::class, ['id' => 42]);
176
177
        try {
178
            $cloned = clone $proxy;
0 ignored issues
show
Unused Code introduced by
$cloned is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
179
            $this->fail('An exception was expected to be raised');
180
        } catch (EntityNotFoundException $exception) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
181
        }
182
183
        self::assertFalse($proxy->isProxyInitialized());
0 ignored issues
show
Bug introduced by
The method isProxyInitialized does only exist in ProxyManager\Proxy\GhostObjectInterface, but not in Doctrine\Tests\Models\ECommerce\ECommerceFeature.

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...
184
    }
185
186
    public function testProxyClonesParentFields()
187
    {
188
        $identifier    = ['id' => 42];
189
        $classMetaData = $this->emMock->getClassMetadata(CompanyEmployee::class);
190
191
        $persister = $this
192
            ->getMockBuilder(BasicEntityPersister::class)
193
            ->setConstructorArgs([$this->emMock, $classMetaData])
194
            ->setMethods(['loadById'])
195
            ->getMock();
196
197
        $persister
198
            ->expects(self::atLeastOnce())
199
            ->method('loadById')
200
            ->with(
201
                $identifier,
202
                self::logicalAnd(
203
                    self::isInstanceOf(GhostObjectInterface::class),
204
                    self::isInstanceOf(CompanyEmployee::class)
205
                )
206
            )
207
            ->willReturnCallback(function (array $id, CompanyEmployee $companyEmployee) {
208
                $companyEmployee->setSalary(1000); // A property on the CompanyEmployee
209
                $companyEmployee->setName('Bob'); // A property on the parent class, CompanyPerson
210
211
                return $companyEmployee;
212
            });
213
214
        $this->uowMock->setEntityPersister(CompanyEmployee::class, $persister);
215
216
        /* @var $proxy GhostObjectInterface|CompanyEmployee */
217
        $proxy = $this->proxyFactory->getProxy(CompanyEmployee::class, $identifier);
218
219
        $cloned = clone $proxy;
220
221
        self::assertSame(42, $cloned->getId(), 'Expected the Id to be cloned');
0 ignored issues
show
Bug introduced by
The method getId does only exist in Doctrine\Tests\Models\Company\CompanyEmployee, but not in ProxyManager\Proxy\GhostObjectInterface.

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...
222
        self::assertSame(1000, $cloned->getSalary(), 'Expect properties on the CompanyEmployee class to be cloned');
0 ignored issues
show
Bug introduced by
The method getSalary does only exist in Doctrine\Tests\Models\Company\CompanyEmployee, but not in ProxyManager\Proxy\GhostObjectInterface.

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...
223
        self::assertSame('Bob', $cloned->getName(), 'Expect properties on the CompanyPerson class to be cloned');
0 ignored issues
show
Bug introduced by
The method getName does only exist in Doctrine\Tests\Models\Company\CompanyEmployee, but not in ProxyManager\Proxy\GhostObjectInterface.

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...
224
    }
225
}
226
227
abstract class AbstractClass
228
{
229
230
}
231