mirror of
https://github.com/doctrine/orm.git
synced 2026-03-26 07:52:11 +01:00
Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4af1aa3177 | ||
|
|
f4d5283f70 | ||
|
|
976fe5bc0d | ||
|
|
582b222b00 | ||
|
|
1ffb9152f7 | ||
|
|
51faa6ddb7 | ||
|
|
692c3e1b45 | ||
|
|
e410180c6e | ||
|
|
4476b05d59 | ||
|
|
343b0ae576 | ||
|
|
de69f60c6a | ||
|
|
2a653b05a0 | ||
|
|
c6831c6b07 | ||
|
|
33da4d84eb | ||
|
|
c1b373b931 | ||
|
|
b6cff1aa1c | ||
|
|
d2206152bb | ||
|
|
a34dc0a0e3 | ||
|
|
881a7b3b69 | ||
|
|
82bbb1dc4a |
@@ -37,8 +37,7 @@ will have to run a composer installation in the project:
|
||||
```sh
|
||||
git clone git@github.com:doctrine/orm.git
|
||||
cd orm
|
||||
curl -sS https://getcomposer.org/installer | php --
|
||||
./composer.phar install
|
||||
composer install
|
||||
```
|
||||
|
||||
To run the testsuite against another database, copy the ``phpunit.xml.dist``
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
| [![Build status][3.0 image]][3.0] | [![Build status][2.12 image]][2.12] | [![Build status][2.11 image]][2.11] |
|
||||
| [![Coverage Status][3.0 coverage image]][3.0 coverage]| [![Coverage Status][2.12 coverage image]][2.12 coverage] | [![Coverage Status][2.11 coverage image]][2.11 coverage] |
|
||||
|
||||
[<h1 align="center">🇺🇦 UKRAINE NEEDS YOUR HELP NOW!</h1>](https://www.doctrine-project.org/stop-war.html)
|
||||
|
||||
Doctrine 2 is an object-relational mapper (ORM) for PHP 7.1+ that provides transparent persistence
|
||||
for PHP objects. It sits on top of a powerful database abstraction layer (DBAL). One of its key features
|
||||
is the option to write database queries in a proprietary object oriented SQL dialect called Doctrine Query Language (DQL),
|
||||
@@ -13,7 +15,7 @@ without requiring unnecessary code duplication.
|
||||
## More resources:
|
||||
|
||||
* [Website](http://www.doctrine-project.org)
|
||||
* [Documentation](https://www.doctrine-project.org/projects/doctrine-orm/en/latest/index.html)
|
||||
* [Documentation](https://www.doctrine-project.org/projects/doctrine-orm/en/stable/index.html)
|
||||
|
||||
|
||||
[3.0 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=3.0.x
|
||||
|
||||
@@ -10,8 +10,8 @@ we cannot protect you from SQL injection.
|
||||
Please read the documentation chapter on Security in Doctrine DBAL and ORM to
|
||||
understand the assumptions we make.
|
||||
|
||||
- [DBAL Security Page](https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/security.html)
|
||||
- [ORM Security Page](https://www.doctrine-project.org/projects/doctrine-orm/en/latest/reference/security.html)
|
||||
- [DBAL Security Page](https://www.doctrine-project.org/projects/doctrine-dbal/en/stable/reference/security.html)
|
||||
- [ORM Security Page](https://www.doctrine-project.org/projects/doctrine-orm/en/stable/reference/security.html)
|
||||
|
||||
If you find a Security bug in Doctrine, please report it on Jira and change the
|
||||
Security Level to "Security Issues". It will be visible to Doctrine Core
|
||||
|
||||
@@ -289,8 +289,8 @@ If you would still like to perform batching operations over small `UnitOfWork`
|
||||
instances, it is suggested to follow these paths instead:
|
||||
|
||||
* eagerly use `EntityManager#clear()` in conjunction with a specific second level
|
||||
cache configuration (see http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/second-level-cache.html)
|
||||
* use an explicit change tracking policy (see http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/change-tracking-policies.html)
|
||||
cache configuration (see http://docs.doctrine-project.org/projects/doctrine-orm/en/stable/reference/second-level-cache.html)
|
||||
* use an explicit change tracking policy (see http://docs.doctrine-project.org/projects/doctrine-orm/en/stable/reference/change-tracking-policies.html)
|
||||
|
||||
## Deprecated `YAML` mapping drivers.
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
"doctrine/annotations": "^1.13",
|
||||
"doctrine/coding-standard": "^9.0",
|
||||
"phpbench/phpbench": "^0.16.10 || ^1.0",
|
||||
"phpstan/phpstan": "1.4.6",
|
||||
"phpstan/phpstan": "~1.4.10 || 1.5.0",
|
||||
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.4",
|
||||
"squizlabs/php_codesniffer": "3.6.2",
|
||||
"symfony/cache": "^4.4 || ^5.4 || ^6.0",
|
||||
|
||||
201
docs/en/conf.py
201
docs/en/conf.py
@@ -1,201 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Doctrine 2 ORM documentation build configuration file, created by
|
||||
# sphinx-quickstart on Fri Dec 3 18:10:24 2010.
|
||||
#
|
||||
# This file is execfile()d with the current directory set to its containing dir.
|
||||
#
|
||||
# Note that not all possible configuration values are present in this
|
||||
# autogenerated file.
|
||||
#
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
import sys, os, datetime
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
sys.path.append(os.path.abspath('_exts'))
|
||||
|
||||
# -- General configuration -----------------------------------------------------
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be extensions
|
||||
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||
extensions = ['configurationblock']
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# The suffix of source filenames.
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The encoding of source files.
|
||||
#source_encoding = 'utf-8'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'Doctrine 2 ORM'
|
||||
copyright = u'2010-%y, Doctrine Project Team'.format(datetime.date.today)
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '2'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '2'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
language = 'en'
|
||||
|
||||
# There are two options for replacing |today|: either, you set today to some
|
||||
# non-false value, then it is used:
|
||||
#today = ''
|
||||
# Else, today_fmt is used as the format for a strftime call.
|
||||
#today_fmt = '%B %d, %Y'
|
||||
|
||||
# List of documents that shouldn't be included in the build.
|
||||
#unused_docs = []
|
||||
|
||||
# List of directories, relative to source directory, that shouldn't be searched
|
||||
# for source files.
|
||||
exclude_trees = ['_build']
|
||||
|
||||
# The reST default role (used for this markup: `text`) to use for all documents.
|
||||
#default_role = None
|
||||
|
||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||
#add_function_parentheses = True
|
||||
|
||||
# If true, the current module name will be prepended to all description
|
||||
# unit titles (such as .. function::).
|
||||
#add_module_names = True
|
||||
|
||||
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||
# output. They are ignored by default.
|
||||
show_authors = True
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# A list of ignored prefixes for module index sorting.
|
||||
#modindex_common_prefix = []
|
||||
|
||||
|
||||
# -- Options for HTML output ---------------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. Major themes that come with
|
||||
# Sphinx are currently 'default' and 'sphinxdoc'.
|
||||
html_theme = 'doctrine'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#html_theme_options = {}
|
||||
|
||||
# Add any paths that contain custom themes here, relative to this directory.
|
||||
html_theme_path = ['_theme']
|
||||
|
||||
# The name for this set of Sphinx documents. If None, it defaults to
|
||||
# "<project> v<release> documentation".
|
||||
#html_title = None
|
||||
|
||||
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||
#html_short_title = None
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top
|
||||
# of the sidebar.
|
||||
#html_logo = None
|
||||
|
||||
# The name of an image file (within the static path) to use as favicon of the
|
||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||
# pixels large.
|
||||
#html_favicon = None
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||
# using the given strftime format.
|
||||
#html_last_updated_fmt = '%b %d, %Y'
|
||||
|
||||
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||
# typographically correct entities.
|
||||
#html_use_smartypants = True
|
||||
|
||||
# Custom sidebar templates, maps document names to template names.
|
||||
#html_sidebars = {}
|
||||
|
||||
# Additional templates that should be rendered to pages, maps page names to
|
||||
# template names.
|
||||
#html_additional_pages = {}
|
||||
|
||||
# If false, no module index is generated.
|
||||
#html_use_modindex = True
|
||||
|
||||
# If false, no index is generated.
|
||||
#html_use_index = True
|
||||
|
||||
# If true, the index is split into individual pages for each letter.
|
||||
#html_split_index = False
|
||||
|
||||
# If true, links to the reST sources are added to the pages.
|
||||
#html_show_sourcelink = True
|
||||
|
||||
# If true, an OpenSearch description file will be output, and all pages will
|
||||
# contain a <link> tag referring to it. The value of this option must be the
|
||||
# base URL from which the finished HTML is served.
|
||||
#html_use_opensearch = ''
|
||||
|
||||
# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
|
||||
#html_file_suffix = ''
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'Doctrine2ORMdoc'
|
||||
|
||||
|
||||
# -- Options for LaTeX output --------------------------------------------------
|
||||
|
||||
# The paper size ('letter' or 'a4').
|
||||
#latex_paper_size = 'letter'
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#latex_font_size = '10pt'
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title, author, documentclass [howto/manual]).
|
||||
latex_documents = [
|
||||
('index', 'Doctrine2ORM.tex', u'Doctrine 2 ORM Documentation',
|
||||
u'Doctrine Project Team', 'manual'),
|
||||
]
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top of
|
||||
# the title page.
|
||||
#latex_logo = None
|
||||
|
||||
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||
# not chapters.
|
||||
#latex_use_parts = False
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#latex_preamble = ''
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#latex_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#latex_use_modindex = True
|
||||
|
||||
primary_domain = "dcorm"
|
||||
|
||||
def linkcode_resolve(domain, info):
|
||||
if domain == 'dcorm':
|
||||
return 'http://'
|
||||
return None
|
||||
@@ -131,8 +131,8 @@ generation of a DateDiff FunctionNode somewhere in the AST of the
|
||||
dql statement.
|
||||
|
||||
The ``ArithmeticPrimary`` method call is the most common
|
||||
denominator of valid EBNF tokens taken from the
|
||||
`DQL EBNF grammar <https://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/dql-doctrine-query-language.html#ebnf>`_
|
||||
denominator of valid EBNF tokens taken from the :ref:`DQL EBNF grammar
|
||||
<dql_ebnf_grammar>`
|
||||
that matches our requirements for valid input into the DateDiff Dql
|
||||
function. Picking the right tokens for your methods is a tricky
|
||||
business, but the EBNF grammar is pretty helpful finding it, as is
|
||||
|
||||
@@ -3,8 +3,8 @@ Implementing Wakeup or Clone
|
||||
|
||||
.. sectionauthor:: Roman Borschel (roman@code-factory.org)
|
||||
|
||||
As explained in the
|
||||
`restrictions for entity classes in the manual <https://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/architecture.html#entities>`_,
|
||||
As explained in the :ref:`restrictions for entity classes in the manual
|
||||
<terminology_entities>`,
|
||||
it is usually not allowed for an entity to implement ``__wakeup``
|
||||
or ``__clone``, because Doctrine makes special use of them.
|
||||
However, it is quite easy to make use of these methods in a safe
|
||||
|
||||
@@ -66,6 +66,8 @@ The root namespace of the ORM package is ``Doctrine\ORM``.
|
||||
Terminology
|
||||
-----------
|
||||
|
||||
.. _terminology_entities:
|
||||
|
||||
Entities
|
||||
~~~~~~~~
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ If you want to configure Doctrine in more detail, take a look at the :doc:`Advan
|
||||
.. note::
|
||||
|
||||
You can learn more about the database connection configuration in the
|
||||
`Doctrine DBAL connection configuration reference <https://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html>`_.
|
||||
`Doctrine DBAL connection configuration reference <https://docs.doctrine-project.org/projects/doctrine-dbal/en/stable/reference/configuration.html>`_.
|
||||
|
||||
Setting up the Commandline Tool
|
||||
-------------------------------
|
||||
|
||||
@@ -1531,6 +1531,8 @@ Given that there are 10 users and corresponding addresses in the database the ex
|
||||
a one-by-one basis once they are accessed.
|
||||
|
||||
|
||||
.. _dql_ebnf_grammar:
|
||||
|
||||
EBNF
|
||||
----
|
||||
|
||||
|
||||
@@ -142,33 +142,33 @@ Events Overview
|
||||
| Event | Dispatched by | Lifecycle | Passed |
|
||||
| | | Callback | Argument |
|
||||
+=================================================================+=======================+===========+=====================================+
|
||||
| :ref:`preRemove<reference-events-pre-remove>` | ``$em->remove()`` | Yes | `_LifecycleEventArgs`_ |
|
||||
| :ref:`preRemove<reference-events-pre-remove>` | ``$em->remove()`` | Yes | `LifecycleEventArgs`_ |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`postRemove<reference-events-post-update-remove-persist>` | ``$em->flush()`` | Yes | `_LifecycleEventArgs`_ |
|
||||
| :ref:`postRemove<reference-events-post-update-remove-persist>` | ``$em->flush()`` | Yes | `LifecycleEventArgs`_ |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`prePersist<reference-events-pre-persist>` | ``$em->persist()`` | Yes | `_LifecycleEventArgs`_ |
|
||||
| :ref:`prePersist<reference-events-pre-persist>` | ``$em->persist()`` | Yes | `LifecycleEventArgs`_ |
|
||||
| | on *initial* persist | | |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`postPersist<reference-events-post-update-remove-persist>` | ``$em->flush()`` | Yes | `_LifecycleEventArgs`_ |
|
||||
| :ref:`postPersist<reference-events-post-update-remove-persist>` | ``$em->flush()`` | Yes | `LifecycleEventArgs`_ |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`preUpdate<reference-events-pre-update>` | ``$em->flush()`` | Yes | `_PreUpdateEventArgs`_ |
|
||||
| :ref:`preUpdate<reference-events-pre-update>` | ``$em->flush()`` | Yes | `PreUpdateEventArgs`_ |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`postUpdate<reference-events-post-update-remove-persist>` | ``$em->flush()`` | Yes | `_LifecycleEventArgs`_ |
|
||||
| :ref:`postUpdate<reference-events-post-update-remove-persist>` | ``$em->flush()`` | Yes | `LifecycleEventArgs`_ |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`postLoad<reference-events-post-load>` | Loading from database | Yes | `_LifecycleEventArgs`_ |
|
||||
| :ref:`postLoad<reference-events-post-load>` | Loading from database | Yes | `LifecycleEventArgs`_ |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`loadClassMetadata<reference-events-load-class-metadata>` | Loading of mapping | No | `_LoadClassMetadataEventArgs` |
|
||||
| :ref:`loadClassMetadata<reference-events-load-class-metadata>` | Loading of mapping | No | `LoadClassMetadataEventArgs`_ |
|
||||
| | metadata | | |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| ``onClassMetadataNotFound`` | ``MappingException`` | No | `_OnClassMetadataNotFoundEventArgs` |
|
||||
| ``onClassMetadataNotFound`` | ``MappingException`` | No | `OnClassMetadataNotFoundEventArgs`_ |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`preFlush<reference-events-pre-flush>` | ``$em->flush()`` | Yes | `_PreFlushEventArgs`_ |
|
||||
| :ref:`preFlush<reference-events-pre-flush>` | ``$em->flush()`` | Yes | `PreFlushEventArgs`_ |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`onFlush<reference-events-on-flush>` | ``$em->flush()`` | No | `_OnFlushEventArgs` |
|
||||
| :ref:`onFlush<reference-events-on-flush>` | ``$em->flush()`` | No | `OnFlushEventArgs`_ |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`postFlush<reference-events-post-flush>` | ``$em->flush()`` | No | `_PostFlushEventArgs` |
|
||||
| :ref:`postFlush<reference-events-post-flush>` | ``$em->flush()`` | No | `PostFlushEventArgs`_ |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`onClear<reference-events-on-clear>` | ``$em->clear()`` | No | `_OnClearEventArgs` |
|
||||
| :ref:`onClear<reference-events-on-clear>` | ``$em->clear()`` | No | `OnClearEventArgs`_ |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
|
||||
Naming convention
|
||||
|
||||
@@ -17,6 +17,7 @@ use Doctrine\ORM\Exception\InvalidHydrationMode;
|
||||
use Doctrine\ORM\Exception\MismatchedEventManager;
|
||||
use Doctrine\ORM\Exception\MissingIdentifierField;
|
||||
use Doctrine\ORM\Exception\MissingMappingDriverImplementation;
|
||||
use Doctrine\ORM\Exception\ORMException;
|
||||
use Doctrine\ORM\Exception\UnrecognizedIdentifierFields;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Mapping\ClassMetadataFactory;
|
||||
@@ -59,7 +60,7 @@ use function sprintf;
|
||||
* $entityManager = EntityManager::create($dbParams, $config);
|
||||
*
|
||||
* For more information see
|
||||
* {@link http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/configuration.html}
|
||||
* {@link http://docs.doctrine-project.org/projects/doctrine-orm/en/stable/reference/configuration.html}
|
||||
*
|
||||
* You should never attempt to inherit from the EntityManager: Inheritance
|
||||
* is not a valid extension point for the EntityManager. Instead you
|
||||
@@ -778,7 +779,7 @@ use function sprintf;
|
||||
* @return ObjectRepository|EntityRepository The repository class.
|
||||
* @psalm-return EntityRepository<T>
|
||||
*
|
||||
* @template T
|
||||
* @template T of object
|
||||
*/
|
||||
public function getRepository($entityName)
|
||||
{
|
||||
|
||||
@@ -9,6 +9,7 @@ use DateTimeInterface;
|
||||
use Doctrine\Common\EventManager;
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\DBAL\LockMode;
|
||||
use Doctrine\ORM\Exception\ORMException;
|
||||
use Doctrine\ORM\Internal\Hydration\AbstractHydrator;
|
||||
use Doctrine\ORM\Proxy\ProxyFactory;
|
||||
use Doctrine\ORM\Query\Expr;
|
||||
@@ -31,7 +32,7 @@ interface EntityManagerInterface extends ObjectManager
|
||||
*
|
||||
* @psalm-return EntityRepository<T>
|
||||
*
|
||||
* @template T
|
||||
* @template T of object
|
||||
*/
|
||||
public function getRepository($className);
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ use function substr;
|
||||
* This class is designed for inheritance and users can subclass this class to
|
||||
* write their own repositories with business-specific methods to locate entities.
|
||||
*
|
||||
* @template T
|
||||
* @template T of object
|
||||
* @template-implements Selectable<int,T>
|
||||
* @template-implements ObjectRepository<T>
|
||||
*/
|
||||
|
||||
@@ -7,6 +7,7 @@ namespace Doctrine\ORM\Internal\Hydration;
|
||||
use Doctrine\DBAL\Driver\Exception;
|
||||
use Doctrine\ORM\Exception\MultipleSelectorsFoundException;
|
||||
|
||||
use function array_column;
|
||||
use function count;
|
||||
|
||||
/**
|
||||
@@ -26,12 +27,8 @@ final class ScalarColumnHydrator extends AbstractHydrator
|
||||
throw MultipleSelectorsFoundException::create($this->resultSetMapping()->fieldMappings);
|
||||
}
|
||||
|
||||
$result = [];
|
||||
$result = $this->statement()->fetchAllNumeric();
|
||||
|
||||
while ($row = $this->statement()->fetchOne()) {
|
||||
$result[] = $row;
|
||||
}
|
||||
|
||||
return $result;
|
||||
return array_column($result, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,11 +4,6 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* Description of AggregateExpression.
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class AggregateExpression extends Node
|
||||
{
|
||||
/** @var string */
|
||||
|
||||
@@ -10,11 +10,6 @@ use function is_numeric;
|
||||
use function strlen;
|
||||
use function substr;
|
||||
|
||||
/**
|
||||
* Description of InputParameter.
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class InputParameter extends Node
|
||||
{
|
||||
/** @var bool */
|
||||
|
||||
@@ -8,11 +8,6 @@ use Doctrine\ORM\Exception\ORMException;
|
||||
use Doctrine\ORM\Query\AST\PathExpression;
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Description of QueryException.
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class QueryException extends ORMException
|
||||
{
|
||||
/**
|
||||
|
||||
@@ -73,7 +73,7 @@ class XmlExporter extends AbstractExporter
|
||||
$discriminatorColumnXml->addAttribute('type', $metadata->discriminatorColumn['type']);
|
||||
|
||||
if (isset($metadata->discriminatorColumn['length'])) {
|
||||
$discriminatorColumnXml->addAttribute('length', $metadata->discriminatorColumn['length']);
|
||||
$discriminatorColumnXml->addAttribute('length', (string) $metadata->discriminatorColumn['length']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -339,7 +339,7 @@ class XmlExporter extends AbstractExporter
|
||||
}
|
||||
|
||||
if (isset($inverseJoinColumn['nullable'])) {
|
||||
$inverseJoinColumnXml->addAttribute('nullable', $inverseJoinColumn['nullable']);
|
||||
$inverseJoinColumnXml->addAttribute('nullable', $inverseJoinColumn['nullable'] ? 'true' : 'false');
|
||||
}
|
||||
|
||||
if (isset($inverseJoinColumn['orderBy'])) {
|
||||
@@ -365,7 +365,7 @@ class XmlExporter extends AbstractExporter
|
||||
}
|
||||
|
||||
if (isset($joinColumn['nullable'])) {
|
||||
$joinColumnXml->addAttribute('nullable', $joinColumn['nullable']);
|
||||
$joinColumnXml->addAttribute('nullable', $joinColumn['nullable'] ? 'true' : 'false');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ use Doctrine\ORM\Event\OnFlushEventArgs;
|
||||
use Doctrine\ORM\Event\PostFlushEventArgs;
|
||||
use Doctrine\ORM\Event\PreFlushEventArgs;
|
||||
use Doctrine\ORM\Event\PreUpdateEventArgs;
|
||||
use Doctrine\ORM\Exception\ORMException;
|
||||
use Doctrine\ORM\Exception\UnexpectedAssociationValue;
|
||||
use Doctrine\ORM\Id\AssignedGenerator;
|
||||
use Doctrine\ORM\Internal\CommitOrderCalculator;
|
||||
@@ -103,7 +104,7 @@ class UnitOfWork implements PropertyChangedListener
|
||||
* Hint used to collect all primary keys of associated entities during hydration
|
||||
* and execute it in a dedicated query afterwards
|
||||
*
|
||||
* @see https://www.doctrine-project.org/projects/doctrine-orm/en/latest/reference/dql-doctrine-query-language.html#temporarily-change-fetch-mode-in-dql
|
||||
* @see https://www.doctrine-project.org/projects/doctrine-orm/en/stable/reference/dql-doctrine-query-language.html#temporarily-change-fetch-mode-in-dql
|
||||
*/
|
||||
public const HINT_DEFEREAGERLOAD = 'deferEagerLoad';
|
||||
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
parameters:
|
||||
ignoreErrors:
|
||||
-
|
||||
message: "#^Method Doctrine\\\\ORM\\\\AbstractQuery\\:\\:processParameterValue\\(\\) should return array\\|bool\\|float\\|int\\|string but returns mixed\\.$#"
|
||||
count: 1
|
||||
path: lib/Doctrine/ORM/AbstractQuery.php
|
||||
|
||||
-
|
||||
message: "#^Call to an undefined method Doctrine\\\\ORM\\\\Persisters\\\\Entity\\\\EntityPersister\\:\\:getCacheRegion\\(\\)\\.$#"
|
||||
count: 1
|
||||
|
||||
@@ -1459,6 +1459,14 @@
|
||||
<ImplementedReturnTypeMismatch occurrences="1">
|
||||
<code>int|null</code>
|
||||
</ImplementedReturnTypeMismatch>
|
||||
<InvalidReturnStatement occurrences="2">
|
||||
<code>$numDeleted</code>
|
||||
<code>$this->conn->executeStatement($statement, $parameters)</code>
|
||||
</InvalidReturnStatement>
|
||||
<InvalidReturnType occurrences="2">
|
||||
<code>int</code>
|
||||
<code>int</code>
|
||||
</InvalidReturnType>
|
||||
<PossiblyNullArgument occurrences="14">
|
||||
<code>$collection->getOwner()</code>
|
||||
<code>$collection->getOwner()</code>
|
||||
@@ -2199,6 +2207,12 @@
|
||||
</PossiblyNullPropertyAssignmentValue>
|
||||
</file>
|
||||
<file src="lib/Doctrine/ORM/Query/Exec/MultiTableDeleteExecutor.php">
|
||||
<InvalidReturnStatement occurrences="1">
|
||||
<code>$numDeleted</code>
|
||||
</InvalidReturnStatement>
|
||||
<InvalidReturnType occurrences="1">
|
||||
<code>int</code>
|
||||
</InvalidReturnType>
|
||||
<PossiblyInvalidIterator occurrences="1">
|
||||
<code>$this->_sqlStatements</code>
|
||||
</PossiblyInvalidIterator>
|
||||
@@ -2211,6 +2225,12 @@
|
||||
</UninitializedProperty>
|
||||
</file>
|
||||
<file src="lib/Doctrine/ORM/Query/Exec/MultiTableUpdateExecutor.php">
|
||||
<InvalidReturnStatement occurrences="1">
|
||||
<code>$numUpdated</code>
|
||||
</InvalidReturnStatement>
|
||||
<InvalidReturnType occurrences="1">
|
||||
<code>int</code>
|
||||
</InvalidReturnType>
|
||||
<PossiblyInvalidIterator occurrences="1">
|
||||
<code>$this->_sqlStatements</code>
|
||||
</PossiblyInvalidIterator>
|
||||
@@ -2227,6 +2247,12 @@
|
||||
</PropertyNotSetInConstructor>
|
||||
</file>
|
||||
<file src="lib/Doctrine/ORM/Query/Exec/SingleTableDeleteUpdateExecutor.php">
|
||||
<InvalidReturnStatement occurrences="1">
|
||||
<code>$conn->executeStatement($this->_sqlStatements, $params, $types)</code>
|
||||
</InvalidReturnStatement>
|
||||
<InvalidReturnType occurrences="1">
|
||||
<code>int</code>
|
||||
</InvalidReturnType>
|
||||
<PossiblyInvalidArgument occurrences="1">
|
||||
<code>$this->_sqlStatements</code>
|
||||
</PossiblyInvalidArgument>
|
||||
|
||||
@@ -30,6 +30,8 @@
|
||||
<referencedClass name="Doctrine\ORM\Tools\Console\Command\EnsureProductionSettingsCommand"/>
|
||||
<referencedClass name="Doctrine\ORM\Tools\Console\Command\GenerateEntitiesCommand"/>
|
||||
<referencedClass name="Doctrine\ORM\Tools\Console\Command\GenerateRepositoriesCommand"/>
|
||||
<!-- Remove on 2.12.x -->
|
||||
<referencedClass name="Doctrine\Persistence\Mapping\Driver\AnnotationDriver"/>
|
||||
</errorLevel>
|
||||
</DeprecatedClass>
|
||||
<DeprecatedMethod>
|
||||
|
||||
@@ -64,7 +64,12 @@ class DriverResultMock implements Result, ResultStatement
|
||||
|
||||
public function fetchAllNumeric(): array
|
||||
{
|
||||
throw new BadMethodCallException('Not implemented');
|
||||
$values = [];
|
||||
while (($row = $this->fetchNumeric()) !== false) {
|
||||
$values[] = $row;
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
public function fetchAllAssociative(): array
|
||||
|
||||
173
tests/Doctrine/Tests/ORM/Functional/Ticket/GH9230Test.php
Normal file
173
tests/Doctrine/Tests/ORM/Functional/Ticket/GH9230Test.php
Normal file
@@ -0,0 +1,173 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
use Doctrine\ORM\Mapping\Column;
|
||||
use Doctrine\ORM\Mapping\Entity;
|
||||
use Doctrine\ORM\Mapping\GeneratedValue;
|
||||
use Doctrine\ORM\Mapping\Id;
|
||||
use Doctrine\Tests\OrmFunctionalTestCase;
|
||||
|
||||
/**
|
||||
* @group GH-9230
|
||||
*/
|
||||
class GH9230Test extends OrmFunctionalTestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
// ensure entity table exists
|
||||
$this->setUpEntitySchema([GH9230Entity::class]);
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
parent::tearDown();
|
||||
|
||||
$connection = static::$sharedConn;
|
||||
if ($connection === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// remove persisted entities
|
||||
$connection->executeStatement('DELETE FROM GH9230Entity');
|
||||
}
|
||||
|
||||
/**
|
||||
* This does not work before the fix in PR#9663, but is does work after the fix is applied
|
||||
*/
|
||||
public function failingValuesBeforeFix(): array
|
||||
{
|
||||
return [
|
||||
'string=""' => ['name', '', 'test name'],
|
||||
'string="0"' => ['name', '0', 'test name'],
|
||||
'string=null' => ['name', null, 'test name'],
|
||||
|
||||
'int=0' => ['counter', 0, 1],
|
||||
'int=null' => ['counter', null, 1],
|
||||
|
||||
'bool=false' => ['enabled', false, true],
|
||||
'bool=null' => ['enabled', null, true],
|
||||
|
||||
'float=0.0' => ['price', 0.0, 1.1],
|
||||
'float=-0.0' => ['price', -0.0, 1.1],
|
||||
'float=null' => ['price', null, 1.1],
|
||||
|
||||
'json=[]' => ['extra', [], 1],
|
||||
'json=0' => ['extra', 0, 1],
|
||||
'json=0.0' => ['extra', 0.0, 1],
|
||||
'json=false' => ['extra', false, 1],
|
||||
'json=""' => ['extra', '', 1, ['""', '1']],
|
||||
'json=null' => ['enabled', null, 1],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* This already works before the fix in PR#9663 is applied because none of these are falsy values in php
|
||||
*/
|
||||
public function succeedingValuesBeforeFix(): array
|
||||
{
|
||||
return [
|
||||
'string="test"' => ['name', 'test', 'test2'],
|
||||
'int=1' => ['counter', 1, 1],
|
||||
'bool=true' => ['enabled', true, 1],
|
||||
'json=[null]' => ['extra', [null], 1],
|
||||
'json=1' => ['extra', 1, 1],
|
||||
'json=1.1' => ['extra', 1.1, 1],
|
||||
'json=true' => ['extra', true, 1],
|
||||
'json="test"' => ['extra', 'test', 'test'],
|
||||
'json="1"' => ['extra', '1', 1],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider failingValuesBeforeFix
|
||||
* @dataProvider succeedingValuesBeforeFix
|
||||
*/
|
||||
public function testIssue(string $property, $falsyValue, $truthyValue): void
|
||||
{
|
||||
$counter1 = new GH9230Entity();
|
||||
$counter1->$property = $falsyValue;
|
||||
|
||||
$counter2 = new GH9230Entity();
|
||||
$counter2->$property = $truthyValue;
|
||||
|
||||
$this->_em->persist($counter1);
|
||||
$this->_em->persist($counter2);
|
||||
$this->_em->flush();
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
$persistedCounter1 = $this->_em->find(GH9230Entity::class, $counter1->id);
|
||||
$persistedCounter2 = $this->_em->find(GH9230Entity::class, $counter2->id);
|
||||
|
||||
// Assert entities were persisted
|
||||
self::assertInstanceOf(GH9230Entity::class, $persistedCounter1);
|
||||
self::assertInstanceOf(GH9230Entity::class, $persistedCounter2);
|
||||
self::assertEquals($falsyValue, $persistedCounter1->$property);
|
||||
self::assertEquals($truthyValue, $persistedCounter2->$property);
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
$counterRepository = $this->_em->getRepository(GH9230Entity::class);
|
||||
|
||||
$query = $counterRepository->createQueryBuilder('counter')
|
||||
->select('counter.' . $property)
|
||||
->getQuery();
|
||||
|
||||
$values = $query->getSingleColumnResult();
|
||||
|
||||
// Assert that there are 2 values returned.
|
||||
// This fails when there is a falsy value in the array,
|
||||
// because the first falsy value halts the hydration process (before the fix is applied).
|
||||
self::assertCount(2, $values);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class GH9230Entity
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
* @Column(name="id", type="integer")
|
||||
* @Id
|
||||
* @GeneratedValue(strategy="AUTO")
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* @var ?string
|
||||
* @Column(name="name", type="string", nullable=true)
|
||||
*/
|
||||
public $name;
|
||||
|
||||
/**
|
||||
* @var ?int
|
||||
* @Column(name="counter", type="integer", nullable=true)
|
||||
*/
|
||||
public $counter;
|
||||
|
||||
/**
|
||||
* @var ?bool
|
||||
* @Column(name="enabled", type="boolean", nullable=true)
|
||||
*/
|
||||
public $enabled;
|
||||
|
||||
/**
|
||||
* @var ?float
|
||||
* @Column(name="price", type="decimal", scale=1, precision=2, nullable=true)
|
||||
*/
|
||||
public $price;
|
||||
|
||||
/**
|
||||
* @var mixed[]
|
||||
* @Column(name="extra", type="json", nullable=true)
|
||||
*/
|
||||
public $extra;
|
||||
}
|
||||
Reference in New Issue
Block a user