Skip to content

Commit

Permalink
Merge pull request #60 from jorisdugue/v3
Browse files Browse the repository at this point in the history
Ensure Compatibility with Doctrine ORM 3 While Retaining Support for ORM 2
  • Loading branch information
jorisdugue authored Dec 5, 2024
2 parents 17fd413 + fe90047 commit b54df49
Show file tree
Hide file tree
Showing 8 changed files with 182 additions and 17 deletions.
2 changes: 1 addition & 1 deletion Entity/LibrariesHubCache.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity()]
#[ORM\Entity]
#[ORM\Table('h5p_libraries_hub_cache')]
class LibrariesHubCache
{
Expand Down
20 changes: 15 additions & 5 deletions Entity/LibrariesLanguagesRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\ORM\NoResultException;
use Doctrine\Persistence\ManagerRegistry;
use Studit\H5PBundle\Service\DoctrineParser;

/**
* LibrariesLanguagesRepository
*/
class LibrariesLanguagesRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
public function __construct(ManagerRegistry $registry, private readonly DoctrineParser $parser)
{
parent::__construct($registry, LibrariesLanguages::class);
}
Expand All @@ -22,10 +23,15 @@ public function findForLibrary($machineName, $majorVersion, $minorVersion, $lang
->select('ll.languageJson')
->join('ll.library', 'l', 'WITH', 'l.machineName = :machineName and l.majorVersion = :majorVersion and l.minorVersion = :minorVersion')
->where('ll.languageCode = :languageCode')
->setParameters(['majorVersion' => $majorVersion, 'machineName' => $machineName, 'minorVersion' => $minorVersion, 'languageCode' => $languageCode]);
->setParameters($this->parser->buildParams([
'majorVersion' => $majorVersion,
'machineName' => $machineName,
'minorVersion' => $minorVersion,
'languageCode' => $languageCode
]));
try {
$result = $qb->getQuery()->getSingleResult();
} catch (NoResultException $e) {
} catch (NoResultException) {
return null;
}
return $result['languageJson'] ? $result['languageJson'] : null;
Expand All @@ -35,10 +41,14 @@ public function findForLibraryAllLanguages($machineName, $majorVersion, $minorVe
$qb = $this->createQueryBuilder('ll')
->select('ll.languageCode')
->join('ll.library', 'l', 'WITH', 'l.machineName = :machineName and l.majorVersion = :majorVersion and l.minorVersion = :minorVersion')
->setParameters(['majorVersion' => $majorVersion, 'machineName' => $machineName, 'minorVersion' => $minorVersion]);
->setParameters($this->parser->buildParams([
'majorVersion' => $majorVersion,
'machineName' => $machineName,
'minorVersion' => $minorVersion
]));
try {
$results = $qb->getQuery()->getArrayResult();
} catch (NoResultException $e) {
} catch (NoResultException) {
return null;
}
$codes = array('en'); // Semantics is 'en' by default.
Expand Down
2 changes: 1 addition & 1 deletion Entity/Library.php
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ class Library

#[ORM\OneToMany(targetEntity: ContentLibraries::class, mappedBy: "library")]
/**
* @var ArrayCollection|Collection
* @var ArrayCollection|Collection $contentLibraries
*/
private ArrayCollection|Collection $contentLibraries;
/**
Expand Down
23 changes: 14 additions & 9 deletions Entity/LibraryRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@
use Doctrine\ORM\AbstractQuery;
use Doctrine\ORM\NoResultException;
use Doctrine\Persistence\ManagerRegistry;
use Studit\H5PBundle\Service\DoctrineParser;

/**
* LibraryRepository
*
* This class was generated by the PhpStorm "Php Annotations" Plugin. Add your own custom
* repository methods below.
*/

class LibraryRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
public function __construct(ManagerRegistry $registry, private readonly DoctrineParser $parser)
{
parent::__construct($registry, Library::class);
}
Expand Down Expand Up @@ -90,23 +90,25 @@ public function findLatestLibraryVersions(): array
}
return $libraryVersions;
}

public function findHasSemantics($machineName, $majorVersion, $minorVersion)
{
$qb = $this->createQueryBuilder('l')
->select('l')
->where('l.machineName = :machineName and l.majorVersion = :majorVersion and l.minorVersion = :minorVersion and l.semantics is not null')
->setParameters([
->setParameters($this->parser->buildParams([
'machineName' => $machineName,
'majorVersion' => $majorVersion,
'minorVersion' => $minorVersion
]);
]));
try {
$library = $qb->getQuery()->getSingleResult();
} catch (NoResultException $e) {
return null;
}
return (object)$library;
}

public function findAllRunnableWithSemantics()
{
$qb = $this->createQueryBuilder('l')
Expand All @@ -119,40 +121,43 @@ public function findAllRunnableWithSemantics()
}
return $libraries;
}

public function findOneArrayBy($parameters)
{
$qb = $this->createQueryBuilder('l')
->where('l.machineName = :machineName and l.majorVersion = :majorVersion and l.minorVersion = :minorVersion')
->setParameters($parameters);
->setParameters($this->parser->buildParams($parameters));
return $qb->getQuery()->getOneOrNullResult(AbstractQuery::HYDRATE_ARRAY);
}

public function findIdBy($machineName, $majorVersion, $minorVersion)
{
$qb = $this->createQueryBuilder('l')
->select('l.id')
->where('l.machineName = :machineName and l.majorVersion = :majorVersion and l.minorVersion = :minorVersion and l.semantics is not null')
->setParameters([
->setParameters($this->parser->buildParams([
'machineName' => $machineName,
'majorVersion' => $majorVersion,
'minorVersion' => $minorVersion
]);
]));
try {
return $qb->getQuery()->getSingleScalarResult();
} catch (NoResultException $e) {
return null;
}
}

public function isPatched($library): bool
{
$qb = $this->createQueryBuilder('l')
->select('COUNT(l)')
->where('l.machineName = :machineName and l.majorVersion = :majorVersion and l.minorVersion = :minorVersion and l.patchVersion < :patchVersion')
->setParameters([
->setParameters($this->parser->buildParams([
'machineName' => $library['machineName'],
'majorVersion' => $library['majorVersion'],
'minorVersion' => $library['minorVersion'],
'patchVersion' => $library['patchVersion']
]);
]));
return $qb->getQuery()->getSingleScalarResult() > 0;
}
}
46 changes: 46 additions & 0 deletions Service/DoctrineParser.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

namespace Studit\H5PBundle\Service;

use Composer\InstalledVersions;
use Doctrine\Common\Collections\ArrayCollection;
use Studit\H5PBundle\Utils\VersionORM;

/**
* This class exists to prevent breaking changes when working with different versions of Doctrine ORM.
* For example, in Doctrine ORM v3.x, certain parameters require an ArrayCollection.
* @author Joris Dugué
*/
class DoctrineParser
{
private VersionORM $versionORM;

public function __construct(VersionORM $versionORM)
{
$this->versionORM = $versionORM;
}

/**
* This method converts parameters to an ArrayCollection for ORM v3.
* If using ORM v2, it simply returns the received parameters as is.
*
* @param array $params The input parameters to process.
* @return ArrayCollection|array Returns an ArrayCollection for ORM v3 or the original parameters for ORM v2.
*/
public function buildParams(array $params): ArrayCollection|array
{
$doctrineVersion = $this->versionORM->getDoctrineVersion();
if ($doctrineVersion !== null && str_starts_with($doctrineVersion, '3')) {
// For Doctrine ORM v3, ensure the parameters are returned as an ArrayCollection
$paramsCollection = [];

foreach ($params as $k => $val) {
$paramsCollection[] = new \Doctrine\ORM\Query\Parameter($k, $val);
}

return new ArrayCollection($paramsCollection);
}
// For Doctrine ORM v2, return the parameters as is
return $params;
}
}
78 changes: 78 additions & 0 deletions Tests/Service/DoctrineParserTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?php

namespace Studit\H5PBundle\Tests\Service;

use PHPUnit\Framework\MockObject\Exception;
use PHPUnit\Framework\TestCase;
use Studit\H5PBundle\Service\DoctrineParser;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Query\Parameter;
use Studit\H5PBundle\Utils\VersionORM;

class DoctrineParserTest extends TestCase
{
/**
* Test that buildParams returns an ArrayCollection for Doctrine ORM v3.
* @throws Exception
*/
public function testBuildParamsForDoctrineV3()
{
// Mock VersionProvider to simulate Doctrine v2 version
$mockVersionORM = $this->createMock(VersionORM::class);
$mockVersionORM->method('getDoctrineVersion')
->willReturn('3.1.0'); // Simulate Doctrine v2 version
// Inject the mocked version provider into DoctrineParser
$doctrineParser = new DoctrineParser($mockVersionORM);

// Define test parameters
$params = [
'param1' => 'value1',
'param2' => 'value2',
];

// Call the method under test
$result = $doctrineParser->buildParams($params);

// Assert that the result is an instance of ArrayCollection
$this->assertInstanceOf(ArrayCollection::class, $result);

// Assert that the ArrayCollection contains Parameter objects
foreach ($result as $param) {
$this->assertInstanceOf(Parameter::class, $param);
}

// Assert that the parameters inside the Parameter objects match the input parameters
$this->assertEquals('value1', $result[0]->getValue());
$this->assertEquals('value2', $result[1]->getValue());
}

/**
* Test that buildParams returns the original parameters as an array for Doctrine ORM v2.
* @throws Exception
*/
public function testBuildParamsForDoctrineV2()
{
// Mock VersionProvider to simulate Doctrine v2 version
$mockVersionORM = $this->createMock(VersionORM::class);
$mockVersionORM->method('getDoctrineVersion')
->willReturn('2.9.3'); // Simulate Doctrine v2 version

// Inject the mocked version provider into DoctrineParser
$doctrineParser = new DoctrineParser($mockVersionORM);

// Define test parameters
$params = [
'param1' => 'value1',
'param2' => 'value2',
];

// Call the method under test
$result = $doctrineParser->buildParams($params);

// Assert that the result is an array (not an ArrayCollection)
$this->assertIsArray($result);

// Assert that the returned array contains the same values as the input parameters
$this->assertSame($params, $result);
}
}
25 changes: 25 additions & 0 deletions Utils/VersionORM.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

namespace Studit\H5PBundle\Utils;

use Composer\InstalledVersions;

/**
* VersionProvider class provides a simple interface to retrieve the version of the Doctrine ORM package.
* It wraps the `InstalledVersions::getVersion` method, allowing easier testing and version checking.
*/
class VersionORM
{
/**
* Retrieves the installed version of the Doctrine ORM package.
*
* This method calls `InstalledVersions::getVersion('doctrine/orm')` and returns the version string
* for the Doctrine ORM package if available. If the package is not found, it returns null.
*
* @return string|null The version of Doctrine ORM if installed, null otherwise.
*/
public function getDoctrineVersion(): ?string
{
return InstalledVersions::getVersion('doctrine/orm');
}
}
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "jorisdugue/h5p-bundle",
"version": "3.0.1",
"version": "3.0.2",
"type": "symfony-bundle",
"description": "H5P Bundle for Symfony 5, 6 and Symfony 7",
"keywords": [
Expand Down Expand Up @@ -29,6 +29,7 @@
],
"require": {
"php": ">= 8.1",
"composer-runtime-api": "^2",
"doctrine/orm": "~2.0|~3.0",
"guzzlehttp/guzzle": "^7.9",
"h5p/h5p-core": "1.27",
Expand Down

0 comments on commit b54df49

Please sign in to comment.