Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
4d57797
Bump doctrine/.github from 8.0.0 to 10.1.0
dependabot[bot] Oct 12, 2025
927b569
Merge pull request #2099 from doctrine/dependabot/github_actions/doct…
greg0ire Oct 12, 2025
026694f
Address PHPUnit notices
greg0ire Oct 13, 2025
1b3ffb3
Merge pull request #2109 from greg0ire/address-phpunit-notices
greg0ire Oct 14, 2025
5df4d43
Update validate_xml_mapping info
greg0ire Oct 14, 2025
3c68255
Merge pull request #2112 from greg0ire/validate-xml-mapping-docs
greg0ire Oct 14, 2025
d088386
Bump doctrine/.github from 10.1.0 to 12.0.0
dependabot[bot] Oct 20, 2025
862f667
Bump doctrine/.github from 12.0.0 to 12.1.0
dependabot[bot] Oct 27, 2025
f9ab2d7
Revert "Scan file where DI functions are defined"
greg0ire Nov 1, 2025
ec96d28
Configure new kernel parameters
greg0ire Nov 1, 2025
17b0380
Merge pull request #2125 from greg0ire/fix-build
greg0ire Nov 1, 2025
0da556b
Bump actions/download-artifact from 5 to 6
dependabot[bot] Nov 2, 2025
011ec6b
Bump actions/upload-artifact from 4 to 5
dependabot[bot] Nov 2, 2025
984070d
Merge pull request #2122 from doctrine/dependabot/github_actions/2.18…
greg0ire Nov 2, 2025
44c203b
Merge pull request #2123 from doctrine/dependabot/github_actions/2.18…
greg0ire Nov 2, 2025
17b0d1a
Fix detectMappingType if the entity contain a package attribute
jtattevin Oct 16, 2025
f3f3141
Fix regex to match php allowed char in namespace
jtattevin Oct 16, 2025
f4a9935
Add tests and comments on the regex
jtattevin Oct 20, 2025
126ec9e
Remove prefix/suffix detection ; Adjust comments
jtattevin Oct 20, 2025
6a620f9
Bump doctrine/.github from 12.1.0 to 12.2.0
dependabot[bot] Nov 3, 2025
b769877
Merge pull request #2115 from jtattevin/fix-2111-detect-mapping-type-…
greg0ire Nov 5, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/coding-standards.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@ on:
jobs:
coding-standards:
name: "Coding Standards"
uses: "doctrine/.github/.github/workflows/coding-standards.yml@8.0.0"
uses: "doctrine/.github/.github/workflows/coding-standards.yml@v12.2.0"
with:
composer-options: "--prefer-dist --prefer-stable"
2 changes: 1 addition & 1 deletion .github/workflows/composer-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ on:
jobs:
composer-lint:
name: "Composer Lint"
uses: "doctrine/.github/.github/workflows/composer-lint.yml@8.0.0"
uses: "doctrine/.github/.github/workflows/composer-lint.yml@v12.2.0"
4 changes: 2 additions & 2 deletions .github/workflows/continuous-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ jobs:
run: "vendor/bin/phpunit --coverage-clover=coverage.xml"

- name: "Upload coverage file"
uses: "actions/upload-artifact@v4"
uses: "actions/upload-artifact@v5"
with:
name: "phpunit-${{ matrix.php-version }}-${{ matrix.dependencies }}-${{ hashFiles('composer.lock') }}.coverage"
path: "coverage.xml"
Expand All @@ -135,7 +135,7 @@ jobs:
fetch-depth: 2

- name: "Download coverage files"
uses: "actions/download-artifact@v5"
uses: "actions/download-artifact@v6"
with:
path: "reports"

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/documentation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ on:
jobs:
documentation:
name: "Documentation"
uses: "doctrine/.github/.github/workflows/documentation.yml@8.0.0"
uses: "doctrine/.github/.github/workflows/documentation.yml@v12.2.0"
2 changes: 1 addition & 1 deletion .github/workflows/release-on-milestone-closed.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ on:
jobs:
release:
name: "Git tag, release & create merge-up PR"
uses: "doctrine/.github/.github/workflows/release-on-milestone-closed.yml@8.0.0"
uses: "doctrine/.github/.github/workflows/release-on-milestone-closed.yml@v12.2.0"
secrets:
GIT_AUTHOR_EMAIL: ${{ secrets.GIT_AUTHOR_EMAIL }}
GIT_AUTHOR_NAME: ${{ secrets.GIT_AUTHOR_NAME }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/static-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,4 @@ on:
jobs:
static-analysis:
name: "Static Analysis"
uses: "doctrine/.github/.github/workflows/phpstan.yml@8.0.0"
uses: "doctrine/.github/.github/workflows/phpstan.yml@v12.2.0"
2 changes: 1 addition & 1 deletion .github/workflows/website-schema.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ on:
jobs:
json-validate:
name: "Validate JSON schema"
uses: "doctrine/.github/.github/workflows/website-schema.yml@8.0.0"
uses: "doctrine/.github/.github/workflows/website-schema.yml@v12.2.0"
8 changes: 8 additions & 0 deletions docs/composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"require-dev": {
"doctrine/docs-builder": "^1.0"
},
"config": {
"sort-packages": true
}
}
3 changes: 1 addition & 2 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ parameters:
- config
- src
- tests
scanFiles:
- vendor/symfony/dependency-injection/Loader/Configurator/functions.php

excludePaths:
- src/Command/Proxy/ConvertMappingDoctrineCommand.php
- src/Command/Proxy/EnsureProductionSettingsDoctrineCommand.php
Expand Down
2 changes: 1 addition & 1 deletion src/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -714,7 +714,7 @@ private function getOrmEntityManagersNode(): ArrayNodeDefinition
->thenInvalid('The setting "report_fields_where_declared" cannot be disabled for ORM 3.')
->end()
->end()
->booleanNode('validate_xml_mapping')->defaultFalse()->info('Set to "true" to opt-in to the new mapping driver mode that was added in Doctrine ORM 2.14 and will be mandatory in ORM 3.0. See https://github.com/doctrine/orm/pull/6728.')->end()
->booleanNode('validate_xml_mapping')->defaultFalse()->info('Set to "true" to opt-in to the new mapping driver mode that was added in Doctrine ORM 2.14. See https://github.com/doctrine/orm/pull/6728.')->end()
->end()
->children()
->arrayNode('second_level_cache')
Expand Down
19 changes: 17 additions & 2 deletions src/DependencyInjection/DoctrineExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -427,8 +427,8 @@ private function detectMappingType(string $directory, ContainerBuilder $containe
}

if (
preg_match('/^(?: \*|\/\*\*) @.*' . $quotedMappingObjectName . '\b/m', $content)
|| preg_match('/^(?: \*|\/\*\*) @.*Embeddable\b/m', $content)
self::textContainsAnnotation($quotedMappingObjectName, $content)
|| self::textContainsAnnotation('Embeddable', $content)
) {
$type = 'annotation';
break;
Expand All @@ -438,6 +438,21 @@ private function detectMappingType(string $directory, ContainerBuilder $containe
return $type;
}

/**
* Check if the file content contains a class-like annotation
*
* @internal
*/
public static function textContainsAnnotation(string $quotedMappingObjectName, string $content): bool
{
return preg_match('/^(?:[ ]\*|\/\*\*)[ ]@ # Match phpdoc start or line with an at
\\\\? # Can start with antislash
([a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*\\\\)* # Match namespace components ending with antislash
' . $quotedMappingObjectName . ' # The target class
\b # Match word boundary
/mx', $content) === 1;
}

/**
* Returns a modified version of $managerConfigs.
*
Expand Down
2 changes: 2 additions & 0 deletions tests/CacheSchemaSubscriberTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,10 @@ public function testSchemaSubscriberWiring(): void
'kernel.build_dir' => sys_get_temp_dir(),
'kernel.environment' => 'test',
'kernel.runtime_environment' => '%%env(default:kernel.environment:APP_RUNTIME_ENV)%%',
'kernel.runtime_mode.web' => false,
'kernel.root_dir' => __DIR__ . '/../../../../', // src dir
'kernel.project_dir' => __DIR__ . '/../../../../', // src dir
'kernel.share_dir' => sys_get_temp_dir(),
'kernel.bundles_metadata' => [],
'kernel.charset' => 'UTF-8',
'kernel.container_class' => ContainerBuilder::class,
Expand Down
12 changes: 5 additions & 7 deletions tests/Command/CreateDatabaseDoctrineTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
use Doctrine\DBAL\DriverManager;
use Doctrine\DBAL\Schema\SchemaManagerFactory;
use Doctrine\Persistence\ManagerRegistry;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\MockObject\Stub;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Tester\CommandTester;
use Symfony\Component\DependencyInjection\Container;
Expand Down Expand Up @@ -59,25 +59,23 @@ public function testExecute(): void
* @param mixed[]|null $params Connection parameters
* @psalm-param Params $params
*
* @return MockObject&Container
* @return Stub&Container
*/
private function getMockContainer(string $connectionName, array|null $params = null): MockObject
private function getMockContainer(string $connectionName, array|null $params = null): Stub
{
// Mock the container and everything you'll need here
$mockDoctrine = $this->createStub(ManagerRegistry::class);

$mockDoctrine->method('getDefaultConnectionName')->willReturn($connectionName);

$config = (new Configuration())->setSchemaManagerFactory($this->createMock(SchemaManagerFactory::class));
$config = (new Configuration())->setSchemaManagerFactory($this->createStub(SchemaManagerFactory::class));

$mockConnection = $this->createStub(Connection::class);
$mockConnection->method('getConfiguration')->willReturn($config);
$mockConnection->method('getParams')->willReturn($params);
$mockDoctrine->method('getConnection')->willReturn($mockConnection);

$mockContainer = $this->getMockBuilder(Container::class)
->onlyMethods(['get'])
->getMock();
$mockContainer = $this->createStub(Container::class);

$mockContainer->method('get')->with('doctrine')->willReturn($mockDoctrine);

Expand Down
16 changes: 7 additions & 9 deletions tests/Command/DropDatabaseDoctrineTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
use Doctrine\Persistence\ManagerRegistry;
use Generator;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\MockObject\Stub;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Tester\CommandTester;
use Symfony\Component\DependencyInjection\Container;
Expand Down Expand Up @@ -137,9 +137,9 @@ public static function provideIncompatibleDriverOptions(): Generator
* @param list<mixed> $params Connection parameters
* @psalm-param Params $params
*
* @return MockObject&Container
* @return Stub&Container
*/
private function getMockContainer(string $connectionName, array $params): MockObject
private function getMockContainer(string $connectionName, array $params): Stub
{
// Mock the container and everything you'll need here
$mockDoctrine = $this->createStub(ManagerRegistry::class);
Expand All @@ -148,18 +148,16 @@ private function getMockContainer(string $connectionName, array $params): MockOb

$config = (new Configuration())->setSchemaManagerFactory(new DefaultSchemaManagerFactory());

$mockConnection = $this->createMock(Connection::class);
$mockConnection = $this->createStub(Connection::class);
$mockConnection->method('getConfiguration')->willReturn($config);
$mockConnection->method('getParams')->willReturn($params);
$mockDoctrine->method('getConnection')->willReturn($mockConnection);

$mockContainer = $this->getMockBuilder(Container::class)
->onlyMethods(['get'])
->getMock();
$mockContainer = $this->createStub(Container::class);

$mockContainer->method('get')
->with('doctrine')
->willReturn($mockDoctrine);
->with('doctrine')
->willReturn($mockDoctrine);

return $mockContainer;
}
Expand Down
10 changes: 5 additions & 5 deletions tests/DataCollector/DoctrineDataCollectorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ public function testCollectEntities(): void
$manager = $this->createStub(EntityManagerInterface::class);
$config = $this->createMock(Configuration::class);
$factory = $this->createMock(ClassMetadataFactory::class);
$collector = $this->createCollector(['default' => $manager], true, $this->createMock(DebugDataHolder::class));
$unitOfWork = $this->createMock(UnitOfWork::class);
$collector = $this->createCollector(['default' => $manager], true, $this->createStub(DebugDataHolder::class));
$unitOfWork = $this->createStub(UnitOfWork::class);

$manager->method('getMetadataFactory')->willReturn($factory);
$manager->method('getConfiguration')->willReturn($config);
Expand Down Expand Up @@ -74,8 +74,8 @@ public function testDoesNotCollectEntities(): void
}

$manager = $this->createMock(EntityManager::class);
$config = $this->createMock(Configuration::class);
$collector = $this->createCollector(['default' => $manager], false, $this->createMock(DebugDataHolder::class));
$config = $this->createStub(Configuration::class);
$collector = $this->createCollector(['default' => $manager], false, $this->createStub(DebugDataHolder::class));
$unitOfWork = $this->createStub(UnitOfWork::class);

$manager->expects($this->never())->method('getMetadataFactory');
Expand All @@ -91,7 +91,7 @@ public function testDoesNotCollectEntities(): void

public function testGetGroupedQueries(): void
{
$debugDataHolder = $this->createMock(DebugDataHolder::class);
$debugDataHolder = $this->createStub(DebugDataHolder::class);

$queries = [
'default' => [
Expand Down
2 changes: 2 additions & 0 deletions tests/DependencyInjection/Compiler/IdGeneratorPassTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,10 @@ public function testRepositoryServiceWiring(): void
'kernel.bundles' => $bundles,
'kernel.cache_dir' => sys_get_temp_dir(),
'kernel.build_dir' => sys_get_temp_dir(),
'kernel.share_dir' => sys_get_temp_dir(),
'kernel.environment' => 'test',
'kernel.runtime_environment' => '%%env(default:kernel.environment:APP_RUNTIME_ENV)%%',
'kernel.runtime_mode.web' => false,
'kernel.root_dir' => __DIR__ . '/../../../../', // src dir
'kernel.project_dir' => __DIR__ . '/../../../../', // src dir
'kernel.bundles_metadata' => [],
Expand Down
65 changes: 65 additions & 0 deletions tests/DependencyInjection/DoctrineExtensionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1507,6 +1507,71 @@ public function testControllerResolver(bool $simpleEntityManagerConfig): void
$this->assertEquals(new MapEntity(null, null, null, [], null, null, null, true, true), $container->get('controller_resolver_defaults'));
}

#[TestWith(['AnnotationsBundle', 'attribute', 'Vendor'], 'Bundle without anything')]
#[TestWith(['AttributesBundle', 'attribute'], 'Bundle with attributes')]
#[TestWith(['RepositoryServiceBundle', 'attribute'], 'Bundle with both')]
#[TestWith(['AnnotationsBundle', 'annotation'], 'Bundle with annotations')]
#[TestWith(['AttributesWithPackageBundle', 'attribute'], 'Bundle with attributes and @package')]
public function testDetectMappingType(string $bundle, string $expectedType, string $vendor = '')
{
if (! interface_exists(EntityManagerInterface::class)) {
self::markTestSkipped('This test requires ORM');
}

$container = $this->getContainer([$bundle], $vendor);
$extension = new DoctrineExtension();

$config = BundleConfigurationBuilder::createBuilder()
->addBaseConnection()
->addEntityManager([
'default_entity_manager' => 'default',
'entity_managers' => [
'default' => [
'mappings' => [
$bundle => [],
],
],
],
])
->build();

if (! class_exists(AnnotationDriver::class) && $expectedType === 'annotation') {
$this->expectException(LogicException::class);
$this->expectExceptionMessage('The annotation driver is only available in doctrine/orm v2.');
}

$extension->load([$config], $container);

$calls = $container->getDefinition('doctrine.orm.default_metadata_driver')->getMethodCalls();
$this->assertEquals(
sprintf('doctrine.orm.default_%s_metadata_driver', $expectedType),
(string) $calls[0][1][0],
);
}

#[TestWith([' * @Mapping\\Entity', true], 'Using the namespace without alias')]
#[TestWith([' * @ORM\\Entity', true], 'Using the namespace with alias')]
#[TestWith([' * @\\Doctrine\\ORM\\Mapping\\Entity', true], 'Complete namespace with starting slash')]
#[TestWith([' * @Doctrine\\ORM\\Mapping\\Entity', true], 'Complete namespace without starting slash')]
#[TestWith([' * @Entity', true], 'Use of the class')]
#[TestWith([' * @Entity()', true], 'With parentheses')]
#[TestWith(['/** @Entity */', true], 'Comment start')]
#[TestWith(["/**\n * @Entity\n */", true], 'Multiline phpdoc')]
#[TestWith([' * @orm\\Entity', true], 'namespace can start with lowercase')]
#[TestWith([' * @_ORM\\Entity', true], 'namespace can start with underscore')]
#[TestWith([" * @\x80ORM\\Entity", true], 'namespace can start with char from x80-Xff')]
#[TestWith([" * @orm0_\x80\\Entity", true], 'namespace can contain number, underscore and char from x80-Xff')]
#[TestWith([' * @ORMEntity', false], 'Use of the class with prefix')]
#[TestWith([' * @EntityORM', false], 'Use of the class with suffix')]
#[TestWith([' * @package testEntity', false], 'Annotation with Entity as value')]
#[TestWith([' * @entity', false], 'Lowercase use of the class')]
#[TestWith([' * @1ORMEntity', false], 'namespace can\'t start with number')]
#[TestWith([' * @extend<Entity>', false], 'The Entity is used inside < and >')]
public function testTextContainsAnnotation(string $input, bool $expected): void
{
self::assertEquals($expected, DoctrineExtension::textContainsAnnotation('Entity', $input));
}

/** @param list<string> $bundles */
private static function getContainer(array $bundles = ['XmlBundle'], string $vendor = ''): ContainerBuilder
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

declare(strict_types=1);

namespace Fixtures\Bundles\AnnotationsBundle;

use Symfony\Component\HttpKernel\Bundle\Bundle;

class AnnotationsBundle extends Bundle
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

declare(strict_types=1);

namespace Fixtures\Bundles\AnnotationsBundle\Entity;

/** @ORM\Entity() */
class TestAnnotationEntity
{
/**
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
* @ORM\Column(type="integer")
*/
public int|null $id = null;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

declare(strict_types=1);

namespace Fixtures\Bundles\AttributesWithPackageBundle;

use Symfony\Component\HttpKernel\Bundle\Bundle;

class AttributesWithPackageBundle extends Bundle
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

declare(strict_types=1);

namespace Fixtures\Bundles\AttributesWithPackageBundle\Entity;

/** @testUnrelatedAnnotation Fixtures\Bundles\AttributesWithPackageBundle\Entity */
interface TestInterface
{
}
2 changes: 2 additions & 0 deletions tests/LockStoreSchemaListenerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@ public function testLockStoreSchemaSubscriberWiring(array $config, int $expected
'kernel.bundles' => [],
'kernel.cache_dir' => sys_get_temp_dir(),
'kernel.build_dir' => sys_get_temp_dir(),
'kernel.share_dir' => sys_get_temp_dir(),
'kernel.environment' => 'test',
'kernel.runtime_environment' => '%%env(default:kernel.environment:APP_RUNTIME_ENV)%%',
'kernel.runtime_mode.web' => false,
'kernel.root_dir' => __DIR__ . '/../../../../', // src dir
'kernel.project_dir' => __DIR__ . '/../../../../', // src dir
'kernel.bundles_metadata' => [],
Expand Down
Loading