-
Notifications
You must be signed in to change notification settings - Fork 2.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Avoid Connection error when calling ClassMetadataFactor::getAllMetadata() #1294
Avoid Connection error when calling ClassMetadataFactor::getAllMetadata() #1294
Conversation
… errors initialize() is called sometimes, even when the following code doesn't need the targetPlatform property. Specifically, in AbstractClassMetadataFactory::getAllMetadata(). But as of DBAL 2.5.0, calling Connection::getDatabasePlatform() will make a connection to the database, which means that sometimes it may fail (e.g. you haven't configured your database yet). As a result, calling a method like AbstractClassMetadataFactory::getAllMetadata() - which does not need the targetPlatform - will fail, because determining the targetPlatform requires a connection, which fails. This avoids that - we only get the targetPlatform *when* we need it, which are cases where we're doing things that do indeed need a connection.
Hello, thank you for creating this pull request. I have automatically opened an issue http://www.doctrine-project.org/jira/browse/DDC-3551 We use Jira to track the state of pull requests and the versions they got |
👍 |
|
||
private function getTargetPlatform() | ||
{ | ||
if ($this->targetPlatform === null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if ( ! $this->targetPlatform) {
This looks good to me, but it needs a test case to prevent regressions. The test should probably simply use a fake connection object that throws an exception or such... |
Another issue that arises from this is that mapping information is not independent from the platform: that may be a problem in future... |
@Ocramius well that is not particularly an issue with this PR, is it? And IMO never was independent before by asking the platform for its preferences like identity over sequence generator etc. I would even say it cannot be independent at all because of differences in supported features of each platform. Or am I on the wrong track here? |
@@ -753,4 +752,13 @@ protected function isEntity(ClassMetadataInterface $class) | |||
{ | |||
return isset($class->isMappedSuperclass) && $class->isMappedSuperclass === false; | |||
} | |||
|
|||
private function getTargetPlatform() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a simple DocBlock here with return type, please? Would help the IDE I suppose...
No, it is indeed out of the scope of this PR. I'm just seeing more flaws in the current implementation, and simply shouting them out for awareness. |
I think we have a general metadata problem here, as we are storing platform specific information in metadata that may be cached and reused across multiple connections. |
Thanks guys - I've updated the PR with one small change that was suggested and.... a test! I verified that the test fails as expected before this patch, then passes afterwards. Thanks for the attention! |
{ | ||
$driverMock = new DriverMock(); | ||
$config = new \Doctrine\ORM\Configuration(); | ||
$config->setProxyDir(__DIR__ . '/../../Proxies'); | ||
$config->setProxyNamespace('Doctrine\Tests\Proxies'); | ||
$eventManager = new EventManager(); | ||
$conn = new ConnectionMock(array(), $driverMock, $config, $eventManager); | ||
$mockDriver = new MetadataDriverMock(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This $mockDriver
was never actually used in this function. So while it's unrelated to my change, I removed it.
👍 |
Avoid Connection error when calling ClassMetadataFactor::getAllMetadata()
Thank you @guilhermeblanco! I don't know your process, so will/how can this be backported to 2.4? I know it won't patch cleanly (due to some refactoring inside this class), but in thought, the idea patches fine backwards. I can open a PR to the 2.4 branch if it saves someone time. Thanks! |
I'll backport it |
Merged back into 2.4 at e05930e |
Thank you! |
Hi guys!
When you pair the ORM with DBAL 2.5.0, then getting the
targetPlatform
means that a connection will be made to the database. For that reason, it's really important to not get thetargetPlatform
unless it's absolutely needed. Currently, if you callClassMetadataFactor::getAllMetadata()
, it will try to determinetargetPlatform
(ininitialize()
), which will make a connection. And if that connection fails (e.g. no db yet), it will blow up - even thoughgetAllMetadata()
doesn't need thetargetPlatform
.This fixes that, and in an absolutely BC way, since
targetPlatform
is private (yay!). This should fix a number of issues in userland, like symfony/symfony-standard#748 and symfony/symfony-standard#774.This is a PR to master (per the guidelines), but the real target is 2.4, since it's the latest stable. The patch won't apply cleanly, but it's simple: remove from initialize, then replace all references to the new private method.
Thanks in advance! More details are on the commit message.