mirror of
https://github.com/doctrine/orm.git
synced 2026-04-23 06:28:08 +02:00
Compare commits
50 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 445796af0e | |||
| ab93285284 | |||
| a692670469 | |||
| 58677c29b4 | |||
| 9a0fcb5a86 | |||
| 8104c65d6c | |||
| a64d254d07 | |||
| fdad48278b | |||
| fc94127d7f | |||
| dea3e5df44 | |||
| 5d7d3e99a0 | |||
| 3bc1096fd0 | |||
| a2f01f7ccc | |||
| 401db453a2 | |||
| 6e59ec8f16 | |||
| 87e491465a | |||
| 8b588eceb2 | |||
| edce36598f | |||
| 20c46035d1 | |||
| 324aacfb54 | |||
| 1edfcabead | |||
| 2785cde792 | |||
| d67e3e8b1b | |||
| d629c4e487 | |||
| 4a4226213f | |||
| 0ce1440884 | |||
| 9aa28b4e33 | |||
| 5c2b6870bf | |||
| 4389b2c188 | |||
| e481d9880b | |||
| 85528f28e2 | |||
| 5873242fb5 | |||
| c9e41d0aa7 | |||
| f37c12834d | |||
| 041404e8b3 | |||
| bfc68b3aba | |||
| 1e628370c4 | |||
| ae2b9b1921 | |||
| 419df77a09 | |||
| d6f6b2e97c | |||
| 75d5adf599 | |||
| cfd6fadf9c | |||
| 2bf7916c52 | |||
| 253fd10cc0 | |||
| 2c956d55f2 | |||
| 3db992e953 | |||
| 6fc9b3ab16 | |||
| 2d833a5e86 | |||
| a416a9a8b2 | |||
| 3a32c00dcf |
+4
-5
@@ -6,8 +6,7 @@ php:
|
||||
- 7.1
|
||||
- 7.2
|
||||
- 7.3
|
||||
- 7.4snapshot
|
||||
- nightly
|
||||
- 7.4
|
||||
|
||||
env:
|
||||
- DB=sqlite
|
||||
@@ -55,7 +54,7 @@ jobs:
|
||||
- stage: Test
|
||||
dist: xenial
|
||||
env: DB=mysql MYSQL_VERSION=5.7
|
||||
php: 7.4snapshot
|
||||
php: 7.4
|
||||
services:
|
||||
- mysql
|
||||
before_script:
|
||||
@@ -87,6 +86,7 @@ jobs:
|
||||
|
||||
- stage: Code Quality
|
||||
env: DB=none STATIC_ANALYSIS
|
||||
php: 7.4
|
||||
install: travis_retry composer install --prefer-dist
|
||||
before_script:
|
||||
- echo "extension=memcached.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
|
||||
@@ -102,7 +102,7 @@ jobs:
|
||||
- stage: Code Quality
|
||||
if: NOT type = pull_request
|
||||
env: DB=none CODING_STANDARDS
|
||||
php: 7.4snapshot
|
||||
php: 7.4
|
||||
install: travis_retry composer install --prefer-dist
|
||||
script:
|
||||
- ./vendor/bin/phpcs
|
||||
@@ -123,7 +123,6 @@ jobs:
|
||||
- php git-phpcs.phar origin/$TRAVIS_BRANCH...$TRAVIS_PULL_REQUEST_SHA
|
||||
|
||||
allow_failures:
|
||||
- php: nightly
|
||||
- stage: Code Quality
|
||||
env: DB=none CODING_STANDARDS
|
||||
|
||||
|
||||
@@ -10,6 +10,12 @@ Method `Doctrine\ORM\AbstractQuery#useResultCache()` which could be used for bot
|
||||
To optimize DB interaction, `Doctrine\ORM\Tools\Pagination\Paginator` no longer fetches identifiers to be able to
|
||||
perform the pagination with join collections when max results isn't set in the query.
|
||||
|
||||
## Minor BC BREAK: tables filtered with `schema_filter` are no longer created
|
||||
|
||||
When generating schema diffs, if a source table is filtered out by a `schema_filter` expression, then a `CREATE TABLE` was
|
||||
always generated, even if the table already existed. This has been changed in this release and the table will no longer
|
||||
be created.
|
||||
|
||||
## Deprecated number unaware `Doctrine\ORM\Mapping\UnderscoreNamingStrategy`
|
||||
|
||||
In the last patch of the `v2.6.x` series, we fixed a bug that was not converting names properly when they had numbers
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
# Version class and file
|
||||
project.version_class = Doctrine\\ORM\\Version
|
||||
project.version_file = lib/Doctrine/ORM/Version.php
|
||||
@@ -1,16 +0,0 @@
|
||||
version=2.0.0BETA2
|
||||
dependencies.common=2.0.0BETA4
|
||||
dependencies.dbal=2.0.0BETA4
|
||||
stability=beta
|
||||
build.dir=build
|
||||
dist.dir=dist
|
||||
report.dir=reports
|
||||
log.archive.dir=logs
|
||||
project.pirum_dir=
|
||||
project.download_dir=
|
||||
project.xsd_dir=
|
||||
test.phpunit_configuration_file=
|
||||
test.phpunit_generate_coverage=0
|
||||
test.pmd_reports=0
|
||||
test.pdepend_exec=
|
||||
test.phpmd_exec=
|
||||
@@ -1,101 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<project name="DoctrineORM" default="build" basedir=".">
|
||||
<property file="build.properties" />
|
||||
|
||||
<target name="php">
|
||||
<exec executable="which" outputproperty="php_executable">
|
||||
<arg value="php" />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="prepare">
|
||||
<mkdir dir="build" />
|
||||
</target>
|
||||
|
||||
<target name="build" depends="check-git-checkout-clean,prepare,php,composer">
|
||||
<exec executable="${php_executable}">
|
||||
<arg value="build/composer.phar" />
|
||||
<arg value="archive" />
|
||||
<arg value="--dir=build" />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="composer" depends="php,composer-check,composer-download">
|
||||
<exec executable="${php_executable}">
|
||||
<arg value="build/composer.phar" />
|
||||
<arg value="install" />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="composer-check" depends="prepare">
|
||||
<available file="build/composer.phar" property="composer.present"/>
|
||||
</target>
|
||||
|
||||
<target name="composer-download" unless="composer.present">
|
||||
<exec executable="wget">
|
||||
<arg value="-Obuild/composer.phar" />
|
||||
<arg value="http://getcomposer.org/composer.phar" />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="make-release" depends="check-git-checkout-clean,prepare,php">
|
||||
<replace file="${project.version_file}" token="-DEV" value="" failOnNoReplacements="true" />
|
||||
<exec executable="${php_executable}" outputproperty="doctrine.current_version" failonerror="true">
|
||||
<arg value="-r" />
|
||||
<arg value="require_once '${project.version_file}';echo ${project.version_class}::VERSION;" />
|
||||
</exec>
|
||||
<exec executable="${php_executable}" outputproperty="doctrine.next_version" failonerror="true">
|
||||
<arg value="-r" />
|
||||
<arg value="$parts = explode('.', str_ireplace(array('-DEV', '-ALPHA', '-BETA'), '', '${doctrine.current_version}'));
|
||||
if (count($parts) != 3) {
|
||||
throw new \InvalidArgumentException('Version is assumed in format x.y.z, ${doctrine.current_version} given');
|
||||
}
|
||||
$parts[2]++;
|
||||
echo implode('.', $parts);
|
||||
" />
|
||||
</exec>
|
||||
|
||||
<git-commit file="${project.version_file}" message="Release ${doctrine.current_version}" />
|
||||
<git-tag version="${doctrine.current_version}" />
|
||||
<replace file="${project.version_file}" token="${doctrine.current_version}" value="${doctrine.next_version}-DEV" />
|
||||
<git-commit file="${project.version_file}" message="Bump version to ${doctrine.next_version}" />
|
||||
</target>
|
||||
|
||||
<target name="check-git-checkout-clean">
|
||||
<exec executable="git" failonerror="true">
|
||||
<arg value="diff-index" />
|
||||
<arg value="--quiet" />
|
||||
<arg value="HEAD" />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<macrodef name="git-commit">
|
||||
<attribute name="file" default="NOT SET"/>
|
||||
<attribute name="message" default="NOT SET"/>
|
||||
|
||||
<sequential>
|
||||
<exec executable="git">
|
||||
<arg value="add" />
|
||||
<arg value="@{file}" />
|
||||
</exec>
|
||||
<exec executable="git">
|
||||
<arg value="commit" />
|
||||
<arg value="-m" />
|
||||
<arg value="@{message}" />
|
||||
</exec>
|
||||
</sequential>
|
||||
</macrodef>
|
||||
|
||||
<macrodef name="git-tag">
|
||||
<attribute name="version" default="NOT SET" />
|
||||
|
||||
<sequential>
|
||||
<exec executable="git">
|
||||
<arg value="tag" />
|
||||
<arg value="-m" />
|
||||
<arg value="v@{version}" />
|
||||
<arg value="v@{version}" />
|
||||
</exec>
|
||||
</sequential>
|
||||
</macrodef>
|
||||
</project>
|
||||
@@ -26,6 +26,7 @@
|
||||
"doctrine/event-manager": "^1.1",
|
||||
"doctrine/instantiator": "^1.3",
|
||||
"doctrine/persistence": "^1.2",
|
||||
"ocramius/package-versions": "^1.2",
|
||||
"symfony/console": "^3.0|^4.0|^5.0"
|
||||
},
|
||||
"require-dev": {
|
||||
|
||||
Generated
+51
-2
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "4e24e01f599825550170acce0dda0b49",
|
||||
"content-hash": "22be7b4b42da2931c1033f8818a0caa9",
|
||||
"packages": [
|
||||
{
|
||||
"name": "doctrine/annotations",
|
||||
@@ -805,6 +805,55 @@
|
||||
],
|
||||
"time": "2018-06-14T14:45:07+00:00"
|
||||
},
|
||||
{
|
||||
"name": "ocramius/package-versions",
|
||||
"version": "1.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Ocramius/PackageVersions.git",
|
||||
"reference": "ad8a245decad4897cc6b432743913dad0d69753c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Ocramius/PackageVersions/zipball/ad8a245decad4897cc6b432743913dad0d69753c",
|
||||
"reference": "ad8a245decad4897cc6b432743913dad0d69753c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"composer-plugin-api": "^1.0",
|
||||
"php": "~7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"composer/composer": "^1.3",
|
||||
"ext-zip": "*",
|
||||
"humbug/humbug": "dev-master",
|
||||
"phpunit/phpunit": "^6.4"
|
||||
},
|
||||
"type": "composer-plugin",
|
||||
"extra": {
|
||||
"class": "PackageVersions\\Installer",
|
||||
"branch-alias": {
|
||||
"dev-master": "2.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"PackageVersions\\": "src/PackageVersions"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Marco Pivetta",
|
||||
"email": "ocramius@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)",
|
||||
"time": "2017-11-24T11:07:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/log",
|
||||
"version": "1.1.2",
|
||||
@@ -2735,7 +2784,7 @@
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": [],
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"prefer-lowest": true,
|
||||
"platform": {
|
||||
"php": "^7.1",
|
||||
"ext-pdo": "*"
|
||||
|
||||
@@ -99,7 +99,7 @@ Optional attributes:
|
||||
|
||||
- **length**: Used by the "string" type to determine its maximum
|
||||
length in the database. Doctrine does not validate the length of a
|
||||
string values for you.
|
||||
string value for you.
|
||||
|
||||
- **precision**: The precision for a decimal (exact numeric) column
|
||||
(applies only for decimal column), which is the maximum number of
|
||||
|
||||
@@ -45,41 +45,29 @@ This documentation does not cover every single cache driver included
|
||||
with Doctrine. For an up-to-date-list, see the
|
||||
`cache directory on GitHub <https://github.com/doctrine/cache/tree/master/lib/Doctrine/Common/Cache>`_.
|
||||
|
||||
APC
|
||||
~~~
|
||||
PhpFileCache
|
||||
~~~~~~~~~~~~
|
||||
|
||||
In order to use the APC cache driver you must have it compiled and
|
||||
enabled in your php.ini. You can read about APC
|
||||
`in the PHP Documentation <http://us2.php.net/apc>`_. It will give
|
||||
you a little background information about what it is and how you
|
||||
can use it as well as how to install it.
|
||||
The preferred cache driver for metadata and query caches is ``PhpFileCache``.
|
||||
This driver serializes cache items and writes them to a file. This allows for
|
||||
opcode caching to be used and provides high performance in most scenarios.
|
||||
|
||||
Below is a simple example of how you could use the APC cache driver
|
||||
by itself.
|
||||
In order to use the ``PhpFileCache`` driver it must be able to write to
|
||||
a directory.
|
||||
|
||||
Below is an example of how to use the ``PhpFileCache`` driver by itself.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$cacheDriver = new \Doctrine\Common\Cache\ApcCache();
|
||||
$cacheDriver = new \Doctrine\Common\Cache\PhpFileCache(
|
||||
'/path/to/writable/directory'
|
||||
);
|
||||
$cacheDriver->save('cache_id', 'my_data');
|
||||
|
||||
APCu
|
||||
~~~~
|
||||
|
||||
In order to use the APCu cache driver you must have it compiled and
|
||||
enabled in your php.ini. You can read about APCu
|
||||
`in the PHP Documentation <http://us2.php.net/apcu>`_. It will give
|
||||
you a little background information about what it is and how you
|
||||
can use it as well as how to install it.
|
||||
|
||||
Below is a simple example of how you could use the APCu cache driver
|
||||
by itself.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$cacheDriver = new \Doctrine\Common\Cache\ApcuCache();
|
||||
$cacheDriver->save('cache_id', 'my_data');
|
||||
The PhpFileCache is not distributed across multiple machines if you are running
|
||||
your application in a distributed setup. This is ok for the metadata and query
|
||||
cache but is not a good approach for the result cache.
|
||||
|
||||
Memcache
|
||||
~~~~~~~~
|
||||
@@ -128,24 +116,6 @@ driver by itself.
|
||||
$cacheDriver->setMemcached($memcached);
|
||||
$cacheDriver->save('cache_id', 'my_data');
|
||||
|
||||
Xcache
|
||||
~~~~~~
|
||||
|
||||
In order to use the Xcache cache driver you must have it compiled
|
||||
and enabled in your php.ini. You can read about Xcache
|
||||
`here <http://xcache.lighttpd.net/>`_. It will give you a little
|
||||
background information about what it is and how you can use it as
|
||||
well as how to install it.
|
||||
|
||||
Below is a simple example of how you could use the Xcache cache
|
||||
driver by itself.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$cacheDriver = new \Doctrine\Common\Cache\XcacheCache();
|
||||
$cacheDriver->save('cache_id', 'my_data');
|
||||
|
||||
Redis
|
||||
~~~~~
|
||||
|
||||
@@ -306,8 +276,11 @@ use on your ORM configuration.
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$cacheDriver = new \Doctrine\Common\Cache\PhpFileCache(
|
||||
'/path/to/writable/directory'
|
||||
);
|
||||
$config = new \Doctrine\ORM\Configuration();
|
||||
$config->setQueryCacheImpl(new \Doctrine\Common\Cache\ApcuCache());
|
||||
$config->setQueryCacheImpl($cacheDriver);
|
||||
|
||||
Result Cache
|
||||
~~~~~~~~~~~~
|
||||
@@ -320,7 +293,11 @@ cache implementation.
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$config->setResultCacheImpl(new \Doctrine\Common\Cache\ApcuCache());
|
||||
$cacheDriver = new \Doctrine\Common\Cache\PhpFileCache(
|
||||
'/path/to/writable/directory'
|
||||
);
|
||||
$config = new \Doctrine\ORM\Configuration();
|
||||
$config->setResultCacheImpl($cacheDriver);
|
||||
|
||||
Now when you're executing DQL queries you can configure them to use
|
||||
the result cache.
|
||||
@@ -337,7 +314,11 @@ result cache driver.
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$query->setResultCacheDriver(new \Doctrine\Common\Cache\ApcuCache());
|
||||
$cacheDriver = new \Doctrine\Common\Cache\PhpFileCache(
|
||||
'/path/to/writable/directory'
|
||||
);
|
||||
$config = new \Doctrine\ORM\Configuration();
|
||||
$query->setResultCacheDriver($cacheDriver);
|
||||
|
||||
.. note::
|
||||
|
||||
@@ -389,7 +370,11 @@ first.
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$config->setMetadataCacheImpl(new \Doctrine\Common\Cache\ApcuCache());
|
||||
$cacheDriver = new \Doctrine\Common\Cache\PhpFileCache(
|
||||
'/path/to/writable/directory'
|
||||
);
|
||||
$config = new \Doctrine\ORM\Configuration();
|
||||
$config->setMetadataCacheImpl($cacheDriver);
|
||||
|
||||
Now the metadata information will only be parsed once and stored in
|
||||
the cache driver.
|
||||
@@ -425,6 +410,12 @@ To clear the result cache use the ``orm:clear-cache:result`` task.
|
||||
All these tasks accept a ``--flush`` option to flush the entire
|
||||
contents of the cache instead of invalidating the entries.
|
||||
|
||||
.. note::
|
||||
|
||||
None of these tasks will work with APC, APCu, or XCache drivers
|
||||
because the memory that the cache is stored in is only accessible
|
||||
to the webserver.
|
||||
|
||||
Cache Chaining
|
||||
--------------
|
||||
|
||||
|
||||
@@ -35,6 +35,15 @@ With extra lazy collections you can now not only add entities to large collectio
|
||||
easily using a combination of ``count`` and ``slice``.
|
||||
|
||||
|
||||
.. warning::
|
||||
|
||||
``removeElement`` directly issued DELETE queries to the database from
|
||||
version 2.4.0 to 2.7.0. This circumvents the flush operation and might run
|
||||
outside a transactional boundary if you don't create one yourself. We
|
||||
consider this a critical bug in the assumptio of how the ORM works and
|
||||
reverted ``removeElement`` EXTRA_LAZY behavior in 2.7.1.
|
||||
|
||||
|
||||
Enabling Extra-Lazy Associations
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
@@ -243,20 +243,6 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
return $this->persister->get($collection, $index);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function removeElement(PersistentCollection $collection, $element)
|
||||
{
|
||||
if ($persisterResult = $this->persister->removeElement($collection, $element)) {
|
||||
$this->evictCollectionCache($collection);
|
||||
$this->evictElementCache($this->sourceEntity->rootEntityName, $collection->getOwner());
|
||||
$this->evictElementCache($this->targetEntity->rootEntityName, $element);
|
||||
}
|
||||
|
||||
return $persisterResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
||||
@@ -22,6 +22,7 @@ namespace Doctrine\ORM\Internal\Hydration;
|
||||
use PDO;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Query;
|
||||
use function in_array;
|
||||
|
||||
class SimpleObjectHydrator extends AbstractHydrator
|
||||
{
|
||||
@@ -78,8 +79,9 @@ class SimpleObjectHydrator extends AbstractHydrator
|
||||
*/
|
||||
protected function hydrateRowData(array $sqlResult, array &$result)
|
||||
{
|
||||
$entityName = $this->class->name;
|
||||
$data = [];
|
||||
$entityName = $this->class->name;
|
||||
$data = [];
|
||||
$discrColumnValue = null;
|
||||
|
||||
// We need to find the correct entity class name if we have inheritance in resultset
|
||||
if ($this->class->inheritanceType !== ClassMetadata::INHERITANCE_TYPE_NONE) {
|
||||
@@ -104,7 +106,8 @@ class SimpleObjectHydrator extends AbstractHydrator
|
||||
throw HydrationException::invalidDiscriminatorValue($sqlResult[$discrColumnName], array_keys($discrMap));
|
||||
}
|
||||
|
||||
$entityName = $discrMap[$sqlResult[$discrColumnName]];
|
||||
$entityName = $discrMap[$sqlResult[$discrColumnName]];
|
||||
$discrColumnValue = $sqlResult[$discrColumnName];
|
||||
|
||||
unset($sqlResult[$discrColumnName]);
|
||||
}
|
||||
@@ -134,6 +137,11 @@ class SimpleObjectHydrator extends AbstractHydrator
|
||||
|
||||
// Prevent overwrite in case of inherit classes using same property name (See AbstractHydrator)
|
||||
if ( ! isset($data[$fieldName]) || ! $valueIsNull) {
|
||||
// If we have inheritance in resultset, make sure the field belongs to the correct class
|
||||
if (isset($cacheKeyInfo['discriminatorValues']) && ! in_array($discrColumnValue, $cacheKeyInfo['discriminatorValues'], true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$data[$fieldName] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ class AnnotationDriver extends AbstractAnnotationDriver
|
||||
protected $entityAnnotationClasses = [
|
||||
Mapping\Entity::class => 1,
|
||||
Mapping\MappedSuperclass::class => 2,
|
||||
Mapping\Embeddable::class => 3,
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
@@ -367,16 +367,6 @@ final class PersistentCollection extends AbstractLazyCollection implements Selec
|
||||
*/
|
||||
public function removeElement($element)
|
||||
{
|
||||
if ( ! $this->initialized && $this->association['fetch'] === ClassMetadata::FETCH_EXTRA_LAZY) {
|
||||
if ($this->collection->contains($element)) {
|
||||
return $this->collection->removeElement($element);
|
||||
}
|
||||
|
||||
$persister = $this->em->getUnitOfWork()->getCollectionPersister($this->association);
|
||||
|
||||
return $persister->removeElement($this, $element);
|
||||
}
|
||||
|
||||
$removed = parent::removeElement($element);
|
||||
|
||||
if ( ! $removed) {
|
||||
|
||||
@@ -90,16 +90,6 @@ interface CollectionPersister
|
||||
*/
|
||||
public function containsKey(PersistentCollection $collection, $key);
|
||||
|
||||
/**
|
||||
* Removes an element.
|
||||
*
|
||||
* @param \Doctrine\ORM\PersistentCollection $collection
|
||||
* @param object $element
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function removeElement(PersistentCollection $collection, $element);
|
||||
|
||||
/**
|
||||
* Gets an element by key.
|
||||
*
|
||||
|
||||
@@ -211,22 +211,6 @@ class ManyToManyPersister extends AbstractCollectionPersister
|
||||
return (bool) $this->conn->fetchColumn($sql, $params, 0, $types);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function removeElement(PersistentCollection $collection, $element)
|
||||
{
|
||||
if ( ! $this->isValidEntityState($element)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
list($quotedJoinTable, $whereClauses, $params, $types) = $this->getJoinTableRestrictions($collection, $element, false);
|
||||
|
||||
$sql = 'DELETE FROM ' . $quotedJoinTable . ' WHERE ' . implode(' AND ', $whereClauses);
|
||||
|
||||
return (bool) $this->conn->executeUpdate($sql, $params, $types);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
|
||||
@@ -166,28 +166,6 @@ class OneToManyPersister extends AbstractCollectionPersister
|
||||
return $persister->exists($element, $criteria);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function removeElement(PersistentCollection $collection, $element)
|
||||
{
|
||||
$mapping = $collection->getMapping();
|
||||
|
||||
if ( ! $mapping['orphanRemoval']) {
|
||||
// no-op: this is not the owning side, therefore no operations should be applied
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! $this->isValidEntityState($element)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this
|
||||
->uow
|
||||
->getEntityPersister($mapping['targetEntity'])
|
||||
->delete($element);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
||||
@@ -133,7 +133,7 @@ final class Query extends AbstractQuery
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
private $_state = self::STATE_CLEAN;
|
||||
private $_state = self::STATE_DIRTY;
|
||||
|
||||
/**
|
||||
* A snapshot of the parameter types the query was parsed with.
|
||||
|
||||
@@ -189,7 +189,7 @@ class Parser
|
||||
{
|
||||
$this->query = $query;
|
||||
$this->em = $query->getEntityManager();
|
||||
$this->lexer = new Lexer($query->getDQL());
|
||||
$this->lexer = new Lexer((string) $query->getDQL());
|
||||
$this->parserResult = new ParserResult();
|
||||
}
|
||||
|
||||
@@ -302,7 +302,7 @@ class Parser
|
||||
*/
|
||||
public function match($token)
|
||||
{
|
||||
$lookaheadType = $this->lexer->lookahead['type'];
|
||||
$lookaheadType = $this->lexer->lookahead['type'] ?? null;
|
||||
|
||||
// Short-circuit on first condition, usually types match
|
||||
if ($lookaheadType === $token) {
|
||||
|
||||
@@ -22,7 +22,8 @@ namespace Doctrine\ORM\Tools\Console;
|
||||
use Doctrine\DBAL\Tools\Console as DBALConsole;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper;
|
||||
use Doctrine\ORM\Version;
|
||||
use OutOfBoundsException;
|
||||
use PackageVersions\Versions;
|
||||
use Symfony\Component\Console\Application;
|
||||
use Symfony\Component\Console\Helper\HelperSet;
|
||||
|
||||
@@ -70,10 +71,11 @@ final class ConsoleRunner
|
||||
* @param array $commands
|
||||
*
|
||||
* @return \Symfony\Component\Console\Application
|
||||
* @throws OutOfBoundsException
|
||||
*/
|
||||
public static function createApplication(HelperSet $helperSet, array $commands = []) : Application
|
||||
{
|
||||
$cli = new Application('Doctrine Command Line Interface', Version::VERSION);
|
||||
$cli = new Application('Doctrine Command Line Interface', Versions::getVersion('doctrine/orm'));
|
||||
$cli->setCatchExceptions(true);
|
||||
$cli->setHelperSet($helperSet);
|
||||
self::addCommands($cli);
|
||||
|
||||
@@ -26,6 +26,7 @@ use Doctrine\ORM\Mapping\ClassMetadataInfo;
|
||||
use const E_USER_DEPRECATED;
|
||||
use function str_replace;
|
||||
use function trigger_error;
|
||||
use function var_export;
|
||||
|
||||
/**
|
||||
* Generic class used to generate PHP5 entity classes from ClassMetadataInfo instances.
|
||||
@@ -1328,9 +1329,17 @@ public function __construct(<params>)
|
||||
continue;
|
||||
}
|
||||
|
||||
$defaultValue = '';
|
||||
if (isset($fieldMapping['options']['default'])) {
|
||||
if ($fieldMapping['type'] === 'boolean' && $fieldMapping['options']['default'] === '1') {
|
||||
$defaultValue = ' = true';
|
||||
} else {
|
||||
$defaultValue = ' = ' . var_export($fieldMapping['options']['default'], true);
|
||||
}
|
||||
}
|
||||
|
||||
$lines[] = $this->generateFieldMappingPropertyDocBlock($fieldMapping, $metadata);
|
||||
$lines[] = $this->spaces . $this->fieldVisibility . ' $' . $fieldMapping['fieldName']
|
||||
. (isset($fieldMapping['options']['default']) ? ' = ' . var_export($fieldMapping['options']['default'], true) : null) . ";\n";
|
||||
$lines[] = $this->spaces . $this->fieldVisibility . ' $' . $fieldMapping['fieldName'] . $defaultValue . ";\n";
|
||||
}
|
||||
|
||||
return implode("\n", $lines);
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
namespace Doctrine\ORM\Tools;
|
||||
|
||||
use Doctrine\ORM\ORMException;
|
||||
use Doctrine\DBAL\Schema\AbstractAsset;
|
||||
use Doctrine\DBAL\Schema\Comparator;
|
||||
use Doctrine\DBAL\Schema\Index;
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
@@ -28,6 +28,7 @@ use Doctrine\DBAL\Schema\Visitor\DropSchemaSqlCollector;
|
||||
use Doctrine\DBAL\Schema\Visitor\RemoveNamespacedAssets;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\ORMException;
|
||||
use Doctrine\ORM\Tools\Event\GenerateSchemaTableEventArgs;
|
||||
use Doctrine\ORM\Tools\Event\GenerateSchemaEventArgs;
|
||||
|
||||
@@ -709,11 +710,6 @@ class SchemaTool
|
||||
}
|
||||
|
||||
$compositeName = $theJoinTable->getName().'.'.implode('', $localColumns);
|
||||
|
||||
if (! $this->platform->supportsForeignKeyConstraints()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($addedFks[$compositeName])
|
||||
&& ($foreignTableName != $addedFks[$compositeName]['foreignTableName']
|
||||
|| 0 < count(array_diff($foreignColumns, $addedFks[$compositeName]['foreignColumns'])))
|
||||
@@ -896,10 +892,8 @@ class SchemaTool
|
||||
*/
|
||||
public function getUpdateSchemaSql(array $classes, $saveMode = false)
|
||||
{
|
||||
$sm = $this->em->getConnection()->getSchemaManager();
|
||||
|
||||
$fromSchema = $sm->createSchema();
|
||||
$toSchema = $this->getSchemaFromMetadata($classes);
|
||||
$fromSchema = $this->createSchemaForComparison($toSchema);
|
||||
|
||||
$comparator = new Comparator();
|
||||
$schemaDiff = $comparator->compare($fromSchema, $toSchema);
|
||||
@@ -910,4 +904,35 @@ class SchemaTool
|
||||
|
||||
return $schemaDiff->toSql($this->platform);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the schema from the database, ensuring tables from the target schema are whitelisted for comparison.
|
||||
*/
|
||||
private function createSchemaForComparison(Schema $toSchema) : Schema
|
||||
{
|
||||
$connection = $this->em->getConnection();
|
||||
$schemaManager = $connection->getSchemaManager();
|
||||
|
||||
// backup schema assets filter
|
||||
$config = $connection->getConfiguration();
|
||||
$previousFilter = $config->getSchemaAssetsFilter();
|
||||
|
||||
if ($previousFilter === null) {
|
||||
return $schemaManager->createSchema();
|
||||
}
|
||||
|
||||
// whitelist assets we already know about in $toSchema, use the existing filter otherwise
|
||||
$config->setSchemaAssetsFilter(static function ($asset) use ($previousFilter, $toSchema) : bool {
|
||||
$assetName = $asset instanceof AbstractAsset ? $asset->getName() : $asset;
|
||||
|
||||
return $toSchema->hasTable($assetName) || $toSchema->hasSequence($assetName) || $previousFilter($asset);
|
||||
});
|
||||
|
||||
try {
|
||||
return $schemaManager->createSchema();
|
||||
} finally {
|
||||
// restore schema assets filter
|
||||
$config->setSchemaAssetsFilter($previousFilter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ class Version
|
||||
/**
|
||||
* Current Doctrine Version
|
||||
*/
|
||||
const VERSION = '2.7.0';
|
||||
const VERSION = '2.7.1-DEV';
|
||||
|
||||
/**
|
||||
* Compares a Doctrine version with the current one.
|
||||
|
||||
-17
@@ -227,23 +227,6 @@ abstract class AbstractCollectionPersisterTest extends OrmTestCase
|
||||
$this->assertFalse($persister->containsKey($collection, 0));
|
||||
}
|
||||
|
||||
public function testInvokeRemoveElement()
|
||||
{
|
||||
$entity = new State("Foo");
|
||||
$element = new State("Bar");
|
||||
$persister = $this->createPersisterDefault();
|
||||
$collection = $this->createCollection($entity);
|
||||
|
||||
$this->em->getUnitOfWork()->registerManaged($entity, ['id'=>1], ['id'=>1, 'name'=>'Foo']);
|
||||
|
||||
$this->collectionPersister->expects($this->once())
|
||||
->method('removeElement')
|
||||
->with($this->equalTo($collection), $this->equalTo($element))
|
||||
->will($this->returnValue(false));
|
||||
|
||||
$this->assertFalse($persister->removeElement($collection, $element));
|
||||
}
|
||||
|
||||
public function testInvokeGet()
|
||||
{
|
||||
$entity = new State("Foo");
|
||||
|
||||
@@ -28,6 +28,12 @@ class EntityManagerDecoratorTest extends TestCase
|
||||
*/
|
||||
private $wrapped;
|
||||
|
||||
/** @before */
|
||||
public function ignoreDeprecationMessagesFromDoctrinePersistence() : void
|
||||
{
|
||||
$this->ignoreDeprecationMessage('The Doctrine\Common\Persistence\ObjectManagerDecorator class is deprecated since doctrine/persistence 1.3 and will be removed in 2.0. Use \Doctrine\Persistence\ObjectManagerDecorator instead.');
|
||||
}
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->wrapped = $this->createMock(EntityManagerInterface::class);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -14,9 +14,6 @@ class DDC2138Test extends OrmFunctionalTestCase
|
||||
public function testForeignKeyOnSTIWithMultipleMapping()
|
||||
{
|
||||
$em = $this->_em;
|
||||
if (! $em->getConnection()->getDatabasePlatform()->supportsForeignKeyConstraints()) {
|
||||
$this->markTestSkipped('Platform does not support foreign keys.');
|
||||
}
|
||||
$schemaTool = new SchemaTool($em);
|
||||
|
||||
$classes = [
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
use Doctrine\Tests\OrmFunctionalTestCase;
|
||||
|
||||
/**
|
||||
* @group GH7505
|
||||
*/
|
||||
final class GH7505Test extends OrmFunctionalTestCase
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function setUp() : void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->setUpEntitySchema([
|
||||
GH7505AbstractResponse::class,
|
||||
GH7505ArrayResponse::class,
|
||||
GH7505TextResponse::class,
|
||||
]);
|
||||
}
|
||||
|
||||
public function testSimpleArrayTypeHydratedCorrectly() : void
|
||||
{
|
||||
$arrayResponse = new GH7505ArrayResponse();
|
||||
$this->_em->persist($arrayResponse);
|
||||
|
||||
$textResponse = new GH7505TextResponse();
|
||||
$this->_em->persist($textResponse);
|
||||
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$repository = $this->_em->getRepository(GH7505AbstractResponse::class);
|
||||
|
||||
/** @var GH7505ArrayResponse $arrayResponse */
|
||||
$arrayResponse = $repository->find($arrayResponse->id);
|
||||
self::assertSame([], $arrayResponse->value);
|
||||
|
||||
/** @var GH7505TextResponse $textResponse */
|
||||
$textResponse = $repository->find($textResponse->id);
|
||||
self::assertNull($textResponse->value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity()
|
||||
* @Table(name="gh7505_responses")
|
||||
* @InheritanceType("SINGLE_TABLE")
|
||||
* @DiscriminatorColumn(name="discr", type="string")
|
||||
* @DiscriminatorMap({
|
||||
* "array" = GH7505ArrayResponse::class,
|
||||
* "text" = GH7505TextResponse::class,
|
||||
* })
|
||||
*/
|
||||
abstract class GH7505AbstractResponse
|
||||
{
|
||||
/**
|
||||
* @Id @GeneratedValue
|
||||
* @Column(type="integer")
|
||||
*/
|
||||
public $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity()
|
||||
*/
|
||||
class GH7505ArrayResponse extends GH7505AbstractResponse
|
||||
{
|
||||
/**
|
||||
* @Column(name="value_array", type="simple_array")
|
||||
* @var array
|
||||
*/
|
||||
public $value = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity()
|
||||
*/
|
||||
class GH7505TextResponse extends GH7505AbstractResponse
|
||||
{
|
||||
/**
|
||||
* @Column(name="value_string", type="string")
|
||||
* @var string|null
|
||||
*/
|
||||
public $value;
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Tests\OrmFunctionalTestCase;
|
||||
|
||||
/**
|
||||
* @group GH7841
|
||||
*/
|
||||
class GH7841Test extends OrmFunctionalTestCase
|
||||
{
|
||||
public function testForeignKeysNotCompare() : void
|
||||
{
|
||||
if ($this->_em->getConnection()->getDatabasePlatform()->supportsForeignKeyConstraints()) {
|
||||
$this->markTestSkipped('Test for platforms without foreign keys support');
|
||||
}
|
||||
$class = $this->_em->getClassMetadata(GH7841Child::class);
|
||||
$this->_schemaTool->updateSchema([$class], true);
|
||||
$diff = $this->_schemaTool->getUpdateSchemaSql([$class], true);
|
||||
|
||||
self::assertEmpty($diff);
|
||||
|
||||
$this->_schemaTool->dropSchema([$class]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class GH7841Parent
|
||||
{
|
||||
/** @Id @Column(type="integer") @GeneratedValue */
|
||||
public $id;
|
||||
|
||||
/** @OneToMany(targetEntity=GH7841Child::class, mappedBy="parent") */
|
||||
public $children;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->children = new ArrayCollection();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class GH7841Child
|
||||
{
|
||||
/** @Id @Column(type="integer") @GeneratedValue */
|
||||
public $id;
|
||||
|
||||
/** @ManyToOne(targetEntity=GH7841Parent::class) */
|
||||
public $parent;
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Tests\OrmFunctionalTestCase;
|
||||
use function array_values;
|
||||
|
||||
/**
|
||||
* @group gh7864
|
||||
*/
|
||||
class GH7864Test extends OrmFunctionalTestCase
|
||||
{
|
||||
protected function setUp() : void
|
||||
{
|
||||
parent::setup();
|
||||
|
||||
$this->setUpEntitySchema(
|
||||
[
|
||||
GH7864User::class,
|
||||
GH7864Tweet::class,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function testExtraLazyRemoveElement()
|
||||
{
|
||||
$user = new GH7864User();
|
||||
$user->name = 'test';
|
||||
|
||||
$tweet1 = new GH7864Tweet();
|
||||
$tweet1->content = 'Hello World!';
|
||||
$user->addTweet($tweet1);
|
||||
|
||||
$tweet2 = new GH7864Tweet();
|
||||
$tweet2->content = 'Goodbye, and thanks for all the fish';
|
||||
$user->addTweet($tweet2);
|
||||
|
||||
$this->_em->persist($user);
|
||||
$this->_em->persist($tweet1);
|
||||
$this->_em->persist($tweet2);
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$user = $this->_em->find(GH7864User::class, $user->id);
|
||||
$tweet = $this->_em->find(GH7864Tweet::class, $tweet1->id);
|
||||
|
||||
$user->tweets->removeElement($tweet);
|
||||
|
||||
$tweets = $user->tweets->map(static function (GH7864Tweet $tweet) {
|
||||
return $tweet->content;
|
||||
});
|
||||
|
||||
$this->assertEquals(['Goodbye, and thanks for all the fish'], array_values($tweets->toArray()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class GH7864User
|
||||
{
|
||||
/** @Id @Column(type="integer") @GeneratedValue */
|
||||
public $id;
|
||||
|
||||
/** @Column(type="string") */
|
||||
public $name;
|
||||
|
||||
/** @OneToMany(targetEntity="GH7864Tweet", mappedBy="user", fetch="EXTRA_LAZY") */
|
||||
public $tweets;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->tweets = new ArrayCollection();
|
||||
}
|
||||
|
||||
public function addTweet(GH7864Tweet $tweet)
|
||||
{
|
||||
$tweet->user = $this;
|
||||
$this->tweets->add($tweet);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class GH7864Tweet
|
||||
{
|
||||
/** @Id @Column(type="integer") @GeneratedValue */
|
||||
public $id;
|
||||
|
||||
/** @Column(type="string") */
|
||||
public $content;
|
||||
|
||||
/** @ManyToOne(targetEntity="GH7864User", inversedBy="tweets") */
|
||||
public $user;
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
use Doctrine\DBAL\Configuration;
|
||||
use Doctrine\DBAL\Platforms\PostgreSqlPlatform;
|
||||
use Doctrine\ORM\Tools\SchemaTool;
|
||||
use Doctrine\Tests\OrmFunctionalTestCase;
|
||||
use function array_filter;
|
||||
use function current;
|
||||
use function method_exists;
|
||||
use function sprintf;
|
||||
use function strpos;
|
||||
|
||||
/** @group GH7875 */
|
||||
final class GH7875Test extends OrmFunctionalTestCase
|
||||
{
|
||||
/** @after */
|
||||
public function cleanUpSchema() : void
|
||||
{
|
||||
$connection = $this->_em->getConnection();
|
||||
|
||||
$connection->exec('DROP TABLE IF EXISTS gh7875_my_entity');
|
||||
$connection->exec('DROP TABLE IF EXISTS gh7875_my_other_entity');
|
||||
|
||||
if ($connection->getDatabasePlatform() instanceof PostgreSqlPlatform) {
|
||||
$connection->exec('DROP SEQUENCE IF EXISTS gh7875_my_entity_id_seq');
|
||||
$connection->exec('DROP SEQUENCE IF EXISTS gh7875_my_other_entity_id_seq');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $sqls
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
private function filterCreateTable(array $sqls, string $tableName) : array
|
||||
{
|
||||
return array_filter($sqls, static function (string $sql) use ($tableName) : bool {
|
||||
return strpos($sql, sprintf('CREATE TABLE %s (', $tableName)) === 0;
|
||||
});
|
||||
}
|
||||
|
||||
public function testUpdateSchemaSql() : void
|
||||
{
|
||||
$classes = [$this->_em->getClassMetadata(GH7875MyEntity::class)];
|
||||
|
||||
$tool = new SchemaTool($this->_em);
|
||||
$sqls = $this->filterCreateTable($tool->getUpdateSchemaSql($classes), 'gh7875_my_entity');
|
||||
|
||||
self::assertCount(1, $sqls);
|
||||
|
||||
$this->_em->getConnection()->exec(current($sqls));
|
||||
|
||||
$sqls = array_filter($tool->getUpdateSchemaSql($classes), static function (string $sql) : bool {
|
||||
return strpos($sql, ' gh7875_my_entity ') !== false;
|
||||
});
|
||||
|
||||
self::assertSame([], $sqls);
|
||||
|
||||
$classes[] = $this->_em->getClassMetadata(GH7875MyOtherEntity::class);
|
||||
|
||||
$sqls = $tool->getUpdateSchemaSql($classes);
|
||||
|
||||
self::assertCount(0, $this->filterCreateTable($sqls, 'gh7875_my_entity'));
|
||||
self::assertCount(1, $this->filterCreateTable($sqls, 'gh7875_my_other_entity'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<array<string|callable|null>>
|
||||
*/
|
||||
public function provideUpdateSchemaSqlWithSchemaAssetFilter() : array
|
||||
{
|
||||
return [
|
||||
['/^(?!my_enti)/', null],
|
||||
[
|
||||
null,
|
||||
static function ($assetName) : bool {
|
||||
return $assetName !== 'gh7875_my_entity';
|
||||
},
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/** @dataProvider provideUpdateSchemaSqlWithSchemaAssetFilter */
|
||||
public function testUpdateSchemaSqlWithSchemaAssetFilter(?string $filterRegex, ?callable $filterCallback) : void
|
||||
{
|
||||
if ($filterRegex && ! method_exists(Configuration::class, 'setFilterSchemaAssetsExpression')) {
|
||||
self::markTestSkipped(sprintf('Test require %s::setFilterSchemaAssetsExpression method', Configuration::class));
|
||||
}
|
||||
|
||||
$classes = [$this->_em->getClassMetadata(GH7875MyEntity::class)];
|
||||
|
||||
$tool = new SchemaTool($this->_em);
|
||||
$tool->createSchema($classes);
|
||||
|
||||
$config = $this->_em->getConnection()->getConfiguration();
|
||||
if ($filterRegex) {
|
||||
$config->setFilterSchemaAssetsExpression($filterRegex);
|
||||
} else {
|
||||
$config->setSchemaAssetsFilter($filterCallback);
|
||||
}
|
||||
|
||||
$previousFilter = $config->getSchemaAssetsFilter();
|
||||
|
||||
$sqls = $tool->getUpdateSchemaSql($classes);
|
||||
$sqls = array_filter($sqls, static function (string $sql) : bool {
|
||||
return strpos($sql, ' gh7875_my_entity ') !== false;
|
||||
});
|
||||
|
||||
self::assertCount(0, $sqls);
|
||||
self::assertSame($previousFilter, $config->getSchemaAssetsFilter());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
* @Table(name="gh7875_my_entity")
|
||||
*/
|
||||
class GH7875MyEntity
|
||||
{
|
||||
/** @Id @Column(type="integer") @GeneratedValue(strategy="AUTO") */
|
||||
public $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
* @Table(name="gh7875_my_other_entity")
|
||||
*/
|
||||
class GH7875MyOtherEntity
|
||||
{
|
||||
/** @Id @Column(type="integer") @GeneratedValue(strategy="AUTO") */
|
||||
public $id;
|
||||
}
|
||||
@@ -328,6 +328,11 @@ class ValueObjectsTest extends OrmFunctionalTestCase
|
||||
['DDCNestingEmbeddable1', 'DDCNestingEmbeddable4'],
|
||||
];
|
||||
}
|
||||
|
||||
public function testEmbeddableIsNotTransient()
|
||||
{
|
||||
$this->assertFalse($this->_em->getMetadataFactory()->isTransient(DDC93Address::class));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -134,6 +134,8 @@ class LanguageRecognitionTest extends OrmTestCase
|
||||
['SELECT \'foo\' AS foo\\\\bar FROM Doctrine\Tests\Models\CMS\CmsUser u'],
|
||||
['SELECT \'foo\' AS foo: FROM Doctrine\Tests\Models\CMS\CmsUser u'],
|
||||
['SELECT \'foo\' AS foo:bar FROM Doctrine\Tests\Models\CMS\CmsUser u'],
|
||||
|
||||
['0'],
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -134,6 +134,24 @@ class ParserTest extends OrmTestCase
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* PHP 7.4 would fail with Notice: Trying to access array offset on value of type null.
|
||||
*
|
||||
* @see https://github.com/doctrine/orm/pull/7934
|
||||
*
|
||||
* @group GH7934
|
||||
*/
|
||||
public function testNullLookahead() : void
|
||||
{
|
||||
$query = new Query($this->_getTestEntityManager());
|
||||
$query->setDQL('SELECT CURRENT_TIMESTAMP()');
|
||||
|
||||
$parser = new Parser($query);
|
||||
|
||||
$this->expectException(QueryException::class);
|
||||
$parser->match(Lexer::T_SELECT);
|
||||
}
|
||||
|
||||
private function createParser($dql)
|
||||
{
|
||||
$query = new Query($this->_getTestEntityManager());
|
||||
|
||||
@@ -420,4 +420,13 @@ class QueryTest extends OrmTestCase
|
||||
|
||||
self::assertEmpty($query->getResult());
|
||||
}
|
||||
|
||||
/** @group 7982 */
|
||||
public function testNonExistentExecutor()
|
||||
{
|
||||
$this->expectException(QueryException::class);
|
||||
$this->expectExceptionMessage('[Syntax Error] line 0, col -1: Error: Expected SELECT, UPDATE or DELETE, got end of string.');
|
||||
|
||||
$query = $this->_em->createQuery('0')->execute();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
namespace Doctrine\Tests\ORM\Tools\Console;
|
||||
|
||||
use Doctrine\ORM\Tools\Console\ConsoleRunner;
|
||||
use Doctrine\ORM\Version;
|
||||
use Doctrine\Tests\DoctrineTestCase;
|
||||
use PackageVersions\Versions;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Helper\HelperSet;
|
||||
|
||||
@@ -21,7 +21,7 @@ final class ConsoleRunnerTest extends DoctrineTestCase
|
||||
$app = ConsoleRunner::createApplication($helperSet);
|
||||
|
||||
self::assertSame($helperSet, $app->getHelperSet());
|
||||
self::assertEquals(Version::VERSION, $app->getVersion());
|
||||
self::assertSame(Versions::getVersion('doctrine/orm'), $app->getVersion());
|
||||
|
||||
self::assertTrue($app->has('dbal:import'));
|
||||
self::assertTrue($app->has('dbal:reserved-words'));
|
||||
|
||||
@@ -13,6 +13,7 @@ use Doctrine\Tests\Models\DDC2372\DDC2372Admin;
|
||||
use Doctrine\Tests\Models\DDC2372\DDC2372User;
|
||||
use Doctrine\Tests\OrmTestCase;
|
||||
use Doctrine\Tests\VerifyDeprecations;
|
||||
use ReflectionClass;
|
||||
|
||||
class EntityGeneratorTest extends OrmTestCase
|
||||
{
|
||||
@@ -327,6 +328,25 @@ class EntityGeneratorTest extends OrmTestCase
|
||||
$this->assertEquals($isbnMetadata->name, $reflParameters[0]->getClass()->name);
|
||||
}
|
||||
|
||||
public function testBooleanDefaultValue()
|
||||
{
|
||||
$metadata = $this->generateBookEntityFixture(['isbn' => $this->generateIsbnEmbeddableFixture()]);
|
||||
|
||||
$metadata->mapField(['fieldName' => 'foo', 'type' => 'boolean', 'options' => ['default' => '1']]);
|
||||
|
||||
$testEmbeddableMetadata = $this->generateTestEmbeddableFixture();
|
||||
$this->mapEmbedded('testEmbedded', $metadata, $testEmbeddableMetadata);
|
||||
|
||||
$this->_generator->writeEntityClass($metadata, $this->_tmpDir);
|
||||
|
||||
$this->assertFileExists($this->_tmpDir . '/' . $this->_namespace . '/EntityGeneratorBook.php~');
|
||||
|
||||
$book = $this->newInstance($metadata);
|
||||
$reflClass = new ReflectionClass($metadata->name);
|
||||
|
||||
$this->assertTrue($book->getfoo());
|
||||
}
|
||||
|
||||
public function testEntityUpdatingWorks()
|
||||
{
|
||||
$metadata = $this->generateBookEntityFixture(['isbn' => $this->generateIsbnEmbeddableFixture()]);
|
||||
|
||||
@@ -9,7 +9,6 @@ use Doctrine\ORM\Mapping\Driver\AnnotationDriver;
|
||||
use Doctrine\ORM\Mapping\Driver\XmlDriver;
|
||||
use Doctrine\ORM\Mapping\Driver\YamlDriver;
|
||||
use Doctrine\ORM\Tools\Setup;
|
||||
use Doctrine\ORM\Version;
|
||||
use Doctrine\Tests\OrmTestCase;
|
||||
use Doctrine\Tests\VerifyDeprecations;
|
||||
|
||||
@@ -22,10 +21,6 @@ class SetupTest extends OrmTestCase
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
if (strpos(Version::VERSION, "DEV") === false) {
|
||||
$this->markTestSkipped("Test only runs in a dev-installation from Github");
|
||||
}
|
||||
|
||||
$this->originalAutoloaderCount = count(spl_autoload_functions());
|
||||
$this->originalIncludePath = get_include_path();
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests;
|
||||
|
||||
use function set_error_handler;
|
||||
use const E_USER_DEPRECATED;
|
||||
use function in_array;
|
||||
use function set_error_handler;
|
||||
|
||||
trait VerifyDeprecations
|
||||
{
|
||||
@@ -14,6 +16,9 @@ trait VerifyDeprecations
|
||||
/** @var string[] */
|
||||
private $actualDeprecations = [];
|
||||
|
||||
/** @var string[] */
|
||||
private $ignoredDeprecations = [];
|
||||
|
||||
/** @var callable|null */
|
||||
private $originalHandler;
|
||||
|
||||
@@ -22,9 +27,14 @@ trait VerifyDeprecations
|
||||
{
|
||||
$this->actualDeprecations = [];
|
||||
$this->expectedDeprecations = [];
|
||||
$this->ignoredDeprecations = [];
|
||||
|
||||
$this->originalHandler = set_error_handler(
|
||||
function (int $errorNumber, string $errorMessage) : void {
|
||||
if (in_array($errorMessage, $this->ignoredDeprecations, true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->actualDeprecations[] = $errorMessage;
|
||||
},
|
||||
E_USER_DEPRECATED
|
||||
@@ -52,6 +62,11 @@ trait VerifyDeprecations
|
||||
);
|
||||
}
|
||||
|
||||
protected function ignoreDeprecationMessage(string $message) : void
|
||||
{
|
||||
$this->ignoredDeprecations[] = $message;
|
||||
}
|
||||
|
||||
protected function expectDeprecationMessage(string $message) : void
|
||||
{
|
||||
$this->expectedDeprecations[] = $message;
|
||||
|
||||
Reference in New Issue
Block a user