Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extracted content ID by content type fetching as a strategy #330

5 changes: 0 additions & 5 deletions phpstan-baseline-7.4.neon
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,6 @@ parameters:
count: 1
path: src/bundle/Core/Command/CleanupVersionsCommand.php

-
message: "#^Parameter \\#1 \\$var of function count expects array\\|Countable, iterable\\<Ibexa\\\\Contracts\\\\Core\\\\Repository\\\\Values\\\\Content\\\\Content\\>&Traversable given\\.$#"
count: 1
path: src/bundle/Core/Command/ExpireUserPasswordsCommand.php

-
message: "#^Parameter \\#1 \\$fp of function fclose expects resource, resource\\|false given\\.$#"
count: 1
Expand Down
5 changes: 0 additions & 5 deletions phpstan-baseline-8.0.neon
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,6 @@ parameters:
count: 1
path: src/bundle/Core/Command/CleanupVersionsCommand.php

-
message: "#^Parameter \\#1 \\$value of function count expects array\\|Countable, iterable\\<Ibexa\\\\Contracts\\\\Core\\\\Repository\\\\Values\\\\Content\\\\Content\\>&Traversable given\\.$#"
count: 1
path: src/bundle/Core/Command/ExpireUserPasswordsCommand.php

-
message: "#^Parameter \\#1 \\$stream of function fclose expects resource, resource\\|false given\\.$#"
count: 1
Expand Down
51 changes: 1 addition & 50 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -255,11 +255,6 @@ parameters:
count: 1
path: src/bundle/Core/Command/RegenerateUrlAliasesCommand.php

-
message: "#^Access to an undefined property Ibexa\\\\Contracts\\\\Core\\\\Persistence\\\\Content\\\\Location\\\\Handler\\:\\:\\$pathString\\.$#"
count: 2
path: src/bundle/Core/Command/ReindexCommand.php

-
message: "#^Call to an undefined method Ibexa\\\\Core\\\\Search\\\\Common\\\\Indexer\\:\\:purge\\(\\)\\.$#"
count: 1
Expand All @@ -270,11 +265,6 @@ parameters:
count: 2
path: src/bundle/Core/Command/ReindexCommand.php

-
message: "#^Method Ibexa\\\\Bundle\\\\Core\\\\Command\\\\ReindexCommand\\:\\:__construct\\(\\) has parameter \\$searchIndexer with no type specified\\.$#"
count: 1
path: src/bundle/Core/Command/ReindexCommand.php

-
message: "#^Method Ibexa\\\\Bundle\\\\Core\\\\Command\\\\ReindexCommand\\:\\:configure\\(\\) has no return type specified\\.$#"
count: 1
Expand Down Expand Up @@ -319,6 +309,7 @@ parameters:
message: "#^Property Ibexa\\\\Bundle\\\\Core\\\\Command\\\\ReindexCommand\\:\\:\\$phpPath \\(string\\) does not accept string\\|null\\.$#"
count: 1
path: src/bundle/Core/Command/ReindexCommand.php

-
message: "#^Access to an undefined property Ibexa\\\\Contracts\\\\Core\\\\Repository\\\\Values\\\\ValueObject\\:\\:\\$fields\\.$#"
count: 1
Expand Down Expand Up @@ -6929,11 +6920,6 @@ parameters:
count: 1
path: src/contracts/Repository/Iterator/BatchIteratorAdapter/ContentFilteringAdapter.php

-
message: "#^Method Ibexa\\\\Contracts\\\\Core\\\\Repository\\\\Iterator\\\\BatchIteratorAdapter\\\\ContentFilteringAdapter\\:\\:fetch\\(\\) should return Iterator but returns iterable\\<Ibexa\\\\Contracts\\\\Core\\\\Repository\\\\Values\\\\Content\\\\Content\\>&Traversable\\.$#"
count: 1
path: src/contracts/Repository/Iterator/BatchIteratorAdapter/ContentFilteringAdapter.php

-
message: "#^Method Ibexa\\\\Contracts\\\\Core\\\\Repository\\\\Iterator\\\\BatchIteratorAdapter\\\\LocationFilteringAdapter\\:\\:__construct\\(\\) has parameter \\$languages with no value type specified in iterable type array\\.$#"
count: 1
Expand Down Expand Up @@ -7084,11 +7070,6 @@ parameters:
count: 1
path: src/contracts/Repository/Values/Content/ContentList.php

-
message: "#^Method Ibexa\\\\Contracts\\\\Core\\\\Repository\\\\Values\\\\Content\\\\ContentList\\:\\:__construct\\(\\) has parameter \\$contentItems with no value type specified in iterable type array\\.$#"
count: 1
path: src/contracts/Repository/Values/Content/ContentList.php

-
message: "#^Method Ibexa\\\\Contracts\\\\Core\\\\Repository\\\\Values\\\\Content\\\\DraftList\\\\Item\\\\UnauthorizedContentDraftListItem\\:\\:__construct\\(\\) has parameter \\$payload with no value type specified in iterable type array\\.$#"
count: 1
Expand Down Expand Up @@ -34344,11 +34325,6 @@ parameters:
count: 1
path: tests/integration/Core/Repository/Filtering/ContentFilteringTest.php

-
message: "#^Cannot access offset 0 on iterable\\<Ibexa\\\\Contracts\\\\Core\\\\Repository\\\\Values\\\\Content\\\\Content\\>&Traversable\\.$#"
count: 1
path: tests/integration/Core/Repository/Filtering/ContentFilteringTest.php

-
message: "#^Cannot use array destructuring on iterable\\<Ibexa\\\\Contracts\\\\Core\\\\Repository\\\\Values\\\\Content\\\\Location\\>\\.$#"
count: 1
Expand Down Expand Up @@ -34734,11 +34710,6 @@ parameters:
count: 4
path: tests/integration/Core/Repository/LocationServiceTest.php

-
message: "#^Cannot call method fetchColumn\\(\\) on Doctrine\\\\DBAL\\\\ForwardCompatibility\\\\Result\\|int\\|string\\.$#"
count: 1
path: tests/integration/Core/Repository/LocationServiceTest.php

-
message: "#^Cannot call method getContentInfo\\(\\) on Ibexa\\\\Contracts\\\\Core\\\\Repository\\\\Values\\\\Content\\\\Location\\|null\\.$#"
count: 2
Expand Down Expand Up @@ -44689,11 +44660,6 @@ parameters:
count: 1
path: tests/lib/FieldType/Url/Gateway/DoctrineStorageTest.php

-
message: "#^Cannot call method fetchAllAssociative\\(\\) on Doctrine\\\\DBAL\\\\ForwardCompatibility\\\\Result\\|int\\|string\\.$#"
count: 4
path: tests/lib/FieldType/Url/Gateway/DoctrineStorageTest.php

-
message: "#^Method Ibexa\\\\Tests\\\\Core\\\\FieldType\\\\Url\\\\Gateway\\\\DoctrineStorageTest\\:\\:testGetIdUrlMap\\(\\) has no return type specified\\.$#"
count: 1
Expand Down Expand Up @@ -51549,11 +51515,6 @@ parameters:
count: 1
path: tests/lib/Persistence/Legacy/Content/FieldValueConverterRegistryTest.php

-
message: "#^Cannot call method fetchColumn\\(\\) on Doctrine\\\\DBAL\\\\ForwardCompatibility\\\\Result\\|int\\|string\\.$#"
count: 5
path: tests/lib/Persistence/Legacy/Content/Gateway/DoctrineDatabaseTest.php

-
message: "#^Method Ibexa\\\\Tests\\\\Core\\\\Persistence\\\\Legacy\\\\Content\\\\Gateway\\\\DoctrineDatabaseTest\\:\\:assertContentVersionAttributesLanguages\\(\\) has parameter \\$expectation with no value type specified in iterable type array\\.$#"
count: 1
Expand Down Expand Up @@ -52159,11 +52120,6 @@ parameters:
count: 1
path: tests/lib/Persistence/Legacy/Content/Location/Gateway/DoctrineDatabaseTest.php

-
message: "#^Cannot call method fetchColumn\\(\\) on Doctrine\\\\DBAL\\\\ForwardCompatibility\\\\Result\\|int\\|string\\.$#"
count: 1
path: tests/lib/Persistence/Legacy/Content/Location/Gateway/DoctrineDatabaseTest.php

-
message: "#^Method Ibexa\\\\Tests\\\\Core\\\\Persistence\\\\Legacy\\\\Content\\\\Location\\\\Gateway\\\\DoctrineDatabaseTest\\:\\:assertLoadLocationProperties\\(\\) has parameter \\$locationData with no value type specified in iterable type array\\.$#"
count: 1
Expand Down Expand Up @@ -54579,11 +54535,6 @@ parameters:
count: 4
path: tests/lib/Persistence/Legacy/Content/UrlAlias/UrlAliasHandlerTest.php

-
message: "#^Cannot call method fetchColumn\\(\\) on Doctrine\\\\DBAL\\\\ForwardCompatibility\\\\Result\\|int\\|string\\.$#"
count: 1
path: tests/lib/Persistence/Legacy/Content/UrlAlias/UrlAliasHandlerTest.php

-
message: "#^Method Ibexa\\\\Tests\\\\Core\\\\Persistence\\\\Legacy\\\\Content\\\\UrlAlias\\\\UrlAliasHandlerTest\\:\\:assertVirtualUrlAliasValid\\(\\) has no return type specified\\.$#"
count: 1
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<?php

/**
* @copyright Copyright (C) Ibexa AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
declare(strict_types=1);

namespace Ibexa\Bundle\Core\Command\Indexer\ContentIdList;

use Generator;
use Ibexa\Bundle\Core\Command\Indexer\ContentIdListGeneratorStrategyInterface;
use Ibexa\Contracts\Core\Repository\ContentService;
use Ibexa\Contracts\Core\Repository\Values\Content\ContentList;
use Ibexa\Contracts\Core\Repository\Values\Content\Query;
use Ibexa\Contracts\Core\Repository\Values\Filter\Filter;
use Symfony\Component\Console\Input\InputInterface;

/**
* @internal
*/
final class ContentTypeInputGeneratorStrategy implements ContentIdListGeneratorStrategyInterface
{
private ContentService $contentService;

/** @var array<string, \Ibexa\Contracts\Core\Repository\Values\Content\ContentList> */
private static array $inMemoryContentListCache = [];

public function __construct(ContentService $contentService)
{
$this->contentService = $contentService;
}

/**
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\BadStateException
*/
public function getGenerator(InputInterface $input, int $iterationCount): Generator
{
$contentList = $this->getContentList($input->getOption('content-type'));
$contentListIterator = $contentList->getIterator();
do {
$contentIds = [];
for ($i = 0; $i < $iterationCount; ++$i) {
if (!$contentListIterator->valid()) {
break;
}
$contentIds[] = $contentListIterator->current()->getVersionInfo()->getContentInfo()->getId();
$contentListIterator->next();
}
if (empty($contentIds)) {
break;
}

yield $contentIds;
} while ($contentListIterator->valid());
}

public function shouldPurgeIndex(): bool
{
return false;
}

/**
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\BadStateException
*/
public function getCount(InputInterface $input): int
{
return $this->getContentList($input->getOption('content-type'))->getTotalCount();
}

/**
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\BadStateException
*/
private function getContentList(string $contentTypeIdentifier): ContentList
{
if (isset(self::$inMemoryContentListCache[$contentTypeIdentifier])) {
return self::$inMemoryContentListCache[$contentTypeIdentifier];
}

$filter = new Filter();
$filter
->withCriterion(
new Query\Criterion\ContentTypeIdentifier($contentTypeIdentifier)
)
;

self::$inMemoryContentListCache[$contentTypeIdentifier] = $this->contentService->find($filter);

return self::$inMemoryContentListCache[$contentTypeIdentifier];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

/**
* @copyright Copyright (C) Ibexa AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
declare(strict_types=1);

namespace Ibexa\Bundle\Core\Command\Indexer;

use Generator;
use Symfony\Component\Console\Input\InputInterface;

/**
* @internal
*/
interface ContentIdListGeneratorStrategyInterface
{
/**
* @return \Generator<int, int[]>
*/
public function getGenerator(InputInterface $input, int $iterationCount): Generator;

public function getCount(InputInterface $input): int;

public function shouldPurgeIndex(): bool;
}
48 changes: 10 additions & 38 deletions src/bundle/Core/Command/ReindexCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,8 @@
use DateTime;
use const DIRECTORY_SEPARATOR;
use Generator;
use Ibexa\Bundle\Core\Command\Indexer\ContentIdListGeneratorStrategyInterface;
use Ibexa\Contracts\Core\Persistence\Content\Location\Handler;
use Ibexa\Contracts\Core\Repository\ContentService as APIContentService;
use Ibexa\Contracts\Core\Repository\Values\Content\Content;
use Ibexa\Contracts\Core\Repository\Values\Content\ContentList;
use Ibexa\Contracts\Core\Repository\Values\Content\Query;
use Ibexa\Contracts\Core\Repository\Values\Filter\Filter;
use Ibexa\Contracts\Core\Search\Content\IndexerGateway;
use Ibexa\Core\Base\Exceptions\InvalidArgumentException;
use Ibexa\Core\Search\Common\IncrementalIndexer;
Expand Down Expand Up @@ -60,18 +56,18 @@ class ReindexCommand extends Command implements BackwardCompatibleCommand
/** @var \Ibexa\Contracts\Core\Persistence\Content\Location\Handler */
private $locationHandler;

private APIContentService $contentService;
private ContentIdListGeneratorStrategyInterface $contentIdListGeneratorStrategy;

public function __construct(
$searchIndexer,
Indexer $searchIndexer,
Handler $locationHandler,
IndexerGateway $gateway,
LoggerInterface $logger,
string $siteaccess,
string $env,
bool $isDebug,
string $projectDir,
APIContentService $contentService,
ContentIdListGeneratorStrategyInterface $contentIdListGeneratorStrategy,
string $phpPath = null
) {
$this->gateway = $gateway;
Expand All @@ -83,7 +79,7 @@ public function __construct(
$this->env = $env;
$this->isDebug = $isDebug;
$this->projectDir = $projectDir;
$this->contentService = $contentService;
$this->contentIdListGeneratorStrategy = $contentIdListGeneratorStrategy;

parent::__construct();
}
Expand Down Expand Up @@ -264,22 +260,14 @@ protected function indexIncrementally(
$generator = $this->gateway->getContentSince(new DateTime($since), $iterationCount);
$purge = false;
} elseif ($locationId = (int) $input->getOption('subtree')) {
/** @var \Ibexa\Contracts\Core\Persistence\Content\Location\Handler */
$location = $this->locationHandler->load($locationId);
$count = $this->gateway->countContentInSubtree($location->pathString);
$generator = $this->gateway->getContentInSubtree($location->pathString, $iterationCount);
$purge = false;
} elseif ($contentType = $input->getOption('content-type')) {
$filter = new Filter();
$filter
->withCriterion(
new Query\Criterion\ContentTypeIdentifier($contentType)
);

$contentList = $this->contentService->find($filter);
$count = $contentList->getTotalCount();
$generator = $this->fetchIterationFromContentList($contentList, $iterationCount);
$purge = false;
} elseif (!empty($input->getOption('content-type'))) {
$count = $this->contentIdListGeneratorStrategy->getCount($input);
$generator = $this->contentIdListGeneratorStrategy->getGenerator($input, $iterationCount);
$purge = $this->contentIdListGeneratorStrategy->shouldPurgeIndex();
} else {
$count = $this->gateway->countAllContent();
$generator = $this->gateway->getAllContent($iterationCount);
Expand Down Expand Up @@ -349,7 +337,7 @@ private function runParallelProcess(
int $processCount,
bool $commit
): void {
/** @var \Symfony\Component\Process\Process[]|null[] */
/** @var \Symfony\Component\Process\Process[]|null[] $processes */
$processes = array_fill(0, $processCount, null);
do {
/** @var \Symfony\Component\Process\Process $process */
Expand Down Expand Up @@ -478,22 +466,6 @@ public function getDeprecatedAliases(): array
{
return ['ezplatform:reindex'];
}

private function fetchIterationFromContentList(ContentList $contentList, int $iterationCount): Generator
{
/** @var \ArrayIterator<int, Content> $contentListIterator */
$contentListIterator = $contentList->getIterator();

while ($contentListIterator->valid()) {
$contentIds = [];
for ($i = 0; $i < $iterationCount; ++$i) {
$contentIds[] = $contentListIterator->current()->id;
$contentListIterator->next();
}

yield $contentIds;
}
}
}

class_alias(ReindexCommand::class, 'eZ\Bundle\EzPublishCoreBundle\Command\ReindexCommand');
6 changes: 5 additions & 1 deletion src/bundle/Core/Resources/config/commands.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ services:
$env: '%kernel.environment%'
$projectDir: '%kernel.project_dir%'
$isDebug: '%kernel.debug%'
$contentService: '@Ibexa\Contracts\Core\Repository\ContentService'
$contentIdListGeneratorStrategy: '@Ibexa\Bundle\Core\Command\Indexer\ContentIdList\ContentTypeInputGeneratorStrategy'
tags:
- { name: console.command }

Expand All @@ -65,3 +65,7 @@ services:
Ibexa\Bundle\Core\Command\ExpireUserPasswordsCommand:
autowire: true
autoconfigure: true

# Dedicated services for commands
Ibexa\Bundle\Core\Command\Indexer\ContentIdList\ContentTypeInputGeneratorStrategy:
autowire: true
Loading
Loading