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

[FIX] Garbage collector does not get configuration #4218

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
176 changes: 144 additions & 32 deletions Classes/ConnectionManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@
use ApacheSolrForTypo3\Solr\Domain\Site\SiteRepository;
use ApacheSolrForTypo3\Solr\Exception\InvalidArgumentException;
use ApacheSolrForTypo3\Solr\Exception\InvalidConnectionException;
use ApacheSolrForTypo3\Solr\System\Configuration\TypoScriptConfiguration;
use ApacheSolrForTypo3\Solr\System\Records\Pages\PagesRepository as PagesRepositoryAtExtSolr;
use ApacheSolrForTypo3\Solr\System\Solr\SolrConnection;
use ApacheSolrForTypo3\Solr\System\Util\SiteUtility;
use Doctrine\DBAL\Exception as DBALException;
use Solarium\Core\Client\Endpoint;
use Throwable;
use TYPO3\CMS\Core\Exception\SiteNotFoundException;
use TYPO3\CMS\Core\SingletonInterface;
use TYPO3\CMS\Core\Site\Entity\Site as Typo3Site;

Expand All @@ -50,7 +52,7 @@ class ConnectionManager implements SingletonInterface

public function __construct(
PagesRepositoryAtExtSolr $pagesRepositoryAtExtSolr = null,
SiteRepository $siteRepository = null
SiteRepository $siteRepository = null,
) {
$this->siteRepository = $siteRepository ?? GeneralUtility::makeInstance(SiteRepository::class);
$this->pagesRepositoryAtExtSolr = $pagesRepositoryAtExtSolr ?? GeneralUtility::makeInstance(PagesRepositoryAtExtSolr::class);
Expand All @@ -59,10 +61,40 @@ public function __construct(
/**
* Creates a Solr connection for read and write endpoints
*
* @throw InvalidConnectionException
* See: {@link Endpoint}
*
* @param array{
* 'scheme': string,
* 'host': string,
* 'port': int,
* 'path': string,
* 'context'?: string,
* 'collection'?: string,
* 'core': ?string,
* 'leader'?: bool,
* 'username'?: string,
* 'password'?: string
* } $readEndpointConfiguration
* @param array{
* 'scheme': string,
* 'host': string,
* 'port': int,
* 'path': string,
* 'context'?: string,
* 'collection'?: string,
* 'core': ?string,
* 'leader'?: bool,
* 'username'?: string,
* 'password'?: string
* } $writeEndpointConfiguration
*
* @throws InvalidConnectionException
*/
public function getSolrConnectionForEndpoints(array $readEndpointConfiguration, array $writeEndpointConfiguration): SolrConnection
{
public function getSolrConnectionForEndpoints(
array $readEndpointConfiguration,
array $writeEndpointConfiguration,
TypoScriptConfiguration $typoScriptConfiguration,
): SolrConnection {
$connectionHash = md5(json_encode($readEndpointConfiguration) . json_encode($writeEndpointConfiguration));
if (!isset(self::$connections[$connectionHash])) {
$readEndpoint = new Endpoint($readEndpointConfiguration);
Expand All @@ -75,7 +107,12 @@ public function getSolrConnectionForEndpoints(array $readEndpointConfiguration,
throw new InvalidConnectionException('Invalid write endpoint');
}

self::$connections[$connectionHash] = GeneralUtility::makeInstance(SolrConnection::class, $readEndpoint, $writeEndpoint);
self::$connections[$connectionHash] = GeneralUtility::makeInstance(
SolrConnection::class,
$readEndpoint,
$writeEndpoint,
$typoScriptConfiguration,
);
}

return self::$connections[$connectionHash];
Expand All @@ -95,27 +132,71 @@ protected function isValidEndpoint(Endpoint $endpoint): bool

/**
* Creates a solr configuration from the configuration array and returns it.
*
* @param array{
* 'read': array{
* 'scheme': string,
* 'host': string,
* 'port': int,
* 'path': string,
* 'context'?: string,
* 'collection'?: string,
* 'core': ?string,
* 'leader'?: bool,
* 'username'?: string,
* 'password'?: string
* },
* 'write': array{
* 'scheme': string,
* 'host': string,
* 'port': int,
* 'path': string,
* 'context'?: string,
* 'collection'?: string,
* 'core': ?string,
* 'leader'?: bool,
* 'username'?: string,
* 'password'?: string
* }
* } $solrConfiguration
*
* @throws InvalidConnectionException
*/
public function getConnectionFromConfiguration(array $solrConfiguration): SolrConnection
{
return $this->getSolrConnectionForEndpoints($solrConfiguration['read'], $solrConfiguration['write']);
public function getConnectionFromConfiguration(
array $solrConfiguration,
TypoScriptConfiguration $typoScriptConfiguration,
): SolrConnection {
return $this->getSolrConnectionForEndpoints(
$solrConfiguration['read'],
$solrConfiguration['write'],
$typoScriptConfiguration
);
}

/**
* Gets a Solr connection for a page ID.
*
* @throws DBALException
* @throws NoSolrConnectionFoundException
*/
public function getConnectionByPageId(int $pageId, int $language = 0, string $mountPointParametersList = ''): SolrConnection
{
try {
$site = $this->siteRepository->getSiteByPageId($pageId, $mountPointParametersList);
$this->throwExceptionOnInvalidSite($site, 'No site for pageId ' . $pageId);
$this->throwExceptionOnInvalidSite(
$site,
'No site for pageId ' . $pageId,
);
$config = $site->getSolrConnectionConfiguration($language);
return $this->getConnectionFromConfiguration($config);
} catch (InvalidArgumentException) {
throw $this->buildNoConnectionExceptionForPageAndLanguage($pageId, $language);
return $this->getConnectionFromConfiguration(
$config,
$site->getSolrConfiguration(),
);
} catch (Throwable $unexpectedError) {
throw $this->buildNoConnectionExceptionForPageAndLanguage(
$pageId,
$language,
$unexpectedError,
);
}
}

Expand All @@ -135,28 +216,36 @@ public function getConnectionByTypo3Site(Typo3Site $typo3Site, int $languageUid
}

try {
return $this->getConnectionFromConfiguration($config);
} catch (InvalidArgumentException) {
return $this->getConnectionFromConfiguration(
$config,
$this->siteRepository->getSiteByRootPageId($typo3Site->getRootPageId())->getSolrConfiguration(),
);
} catch (Throwable $unexpectedError) {
throw $this->buildNoConnectionExceptionForPageAndLanguage(
$typo3Site->getRootPageId(),
$languageUid
$languageUid,
$unexpectedError,
);
}
}

/**
* Gets a Solr connection for a root page ID.
*
* @throws DBALException
* @throws InvalidConnectionException
* @throws NoSolrConnectionFoundException
* @throws SiteNotFoundException
*/
public function getConnectionByRootPageId(int $pageId, ?int $language = 0): SolrConnection
{
try {
$site = $this->siteRepository->getSiteByRootPageId($pageId);
$this->throwExceptionOnInvalidSite($site, 'No site for pageId ' . $pageId);
$config = $site->getSolrConnectionConfiguration($language ?? 0);
return $this->getConnectionFromConfiguration($config);
return $this->getConnectionFromConfiguration(
$config,
$site->getSolrConfiguration(),
);
} catch (InvalidArgumentException) {
throw $this->buildNoConnectionExceptionForPageAndLanguage($pageId, $language);
}
Expand All @@ -167,14 +256,18 @@ public function getConnectionByRootPageId(int $pageId, ?int $language = 0): Solr
*
* @return SolrConnection[] An array of initialized {@link SolrConnection} connections
*
* @throws InvalidConnectionException
* @throws UnexpectedTYPO3SiteInitializationException
*/
public function getAllConnections(): array
{
$solrConnections = [];
foreach ($this->siteRepository->getAvailableSites() as $site) {
foreach ($site->getAllSolrConnectionConfigurations() as $solrConfiguration) {
$solrConnections[] = $this->getConnectionFromConfiguration($solrConfiguration);
$solrConnections[] = $this->getConnectionFromConfiguration(
$solrConfiguration,
$site->getSolrConfiguration(),
);
}
}

Expand All @@ -185,13 +278,18 @@ public function getAllConnections(): array
* Gets all connections configured for a given site.
*
* @return SolrConnection[] An array of Solr connection objects {@link SolrConnection}
*
* @throws InvalidConnectionException
*/
public function getConnectionsBySite(Site $site): array
{
$connections = [];

foreach ($site->getAllSolrConnectionConfigurations() as $languageId => $solrConnectionConfiguration) {
$connections[$languageId] = $this->getConnectionFromConfiguration($solrConnectionConfiguration);
$connections[$languageId] = $this->getConnectionFromConfiguration(
$solrConnectionConfiguration,
$site->getSolrConfiguration(),
);
}

return $connections;
Expand All @@ -200,10 +298,16 @@ public function getConnectionsBySite(Site $site): array
/**
* Builds and returns the exception instance of {@link NoSolrConnectionFoundException}
*/
protected function buildNoConnectionExceptionForPageAndLanguage(int $pageId, int $language): NoSolrConnectionFoundException
{
protected function buildNoConnectionExceptionForPageAndLanguage(
int $pageId,
int $language,
?Throwable $previous = null,
): NoSolrConnectionFoundException {
$message = 'Could not find a Solr connection for page [' . $pageId . '] and language [' . $language . '].';
$noSolrConnectionException = $this->buildNoConnectionException($message);
$noSolrConnectionException = $this->buildNoConnectionException(
$message,
$previous,
);

$noSolrConnectionException->setLanguageId($language);
return $noSolrConnectionException;
Expand All @@ -214,24 +318,32 @@ protected function buildNoConnectionExceptionForPageAndLanguage(int $pageId, int
*
* @throws NoSolrConnectionFoundException
*/
protected function throwExceptionOnInvalidSite(?Site $site, string $message): void
{
protected function throwExceptionOnInvalidSite(
?Site $site,
string $message,
?Throwable $previous = null,
): void {
if (!is_null($site)) {
return;
}

throw $this->buildNoConnectionException($message);
throw $this->buildNoConnectionException(
$message,
$previous
);
}

/**
* Build a NoSolrConnectionFoundException with the passed message.
*/
protected function buildNoConnectionException(string $message): NoSolrConnectionFoundException
{
return GeneralUtility::makeInstance(
NoSolrConnectionFoundException::class,
protected function buildNoConnectionException(
string $message,
?Throwable $previous = null,
): NoSolrConnectionFoundException {
return new NoSolrConnectionFoundException(
$message,
1575396474
1575396474,
$previous
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
use ApacheSolrForTypo3\Solr\System\Configuration\ExtensionConfiguration;
use ApacheSolrForTypo3\Solr\System\Page\Rootline;
use ApacheSolrForTypo3\Solr\System\Util\SiteUtility;
use Doctrine\DBAL\Exception as DBALException;
use RuntimeException;
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Core\SingletonInterface;
Expand Down Expand Up @@ -58,8 +59,11 @@ public function __construct(
* if the pid is references in another site with additionalPageIds and returning those rootPageIds as well.
* The result is cached by the caching framework.
*
* @return int[]
*
* @throws UnexpectedTYPO3SiteInitializationException
* @throws RootPageRecordNotFoundException
* @throws DBALException
*/
public function getResponsibleRootPageIds(string $table, int $uid): array
{
Expand Down Expand Up @@ -118,6 +122,12 @@ public function getIsRootPageId(int $pageId): bool

/**
* Returns record of page for given conditions or empty array if nothing found.
*
* @return array{
* 'uid'?: int,
* 'pid'?: int,
* 'is_siteroot'?: int
* }
*/
protected function getPageRecordByPageId(int $pageId, string $fieldList = 'is_siteroot'): array
{
Expand All @@ -126,6 +136,8 @@ protected function getPageRecordByPageId(int $pageId, string $fieldList = 'is_si

/**
* Determines the root page ID for a given page.
*
* @throws DBALException
*/
public function getRootPageId(
int $pageId = 0,
Expand Down Expand Up @@ -163,8 +175,11 @@ public function getRootPageId(
* This method determines the responsible site roots for a record by getting the rootPage of the record and checking
* if the pid is references in another site with additionalPageIds and returning those rootPageIds as well.
*
* @return int[]
*
* @throws UnexpectedTYPO3SiteInitializationException
* @throws RootPageRecordNotFoundException
* @throws DBALException
*/
protected function buildResponsibleRootPageIds(string $table, int $uid): array
{
Expand All @@ -188,6 +203,8 @@ protected function buildResponsibleRootPageIds(string $table, int $uid): array
/**
* This method checks if the record is a pages record or another one and determines the rootPageId from the records
* rootline.
*
* @throws DBALException
*/
protected function getRootPageIdByTableAndUid(string $table, int $uid): int
{
Expand Down Expand Up @@ -215,6 +232,8 @@ protected function getRecordPageId(string $table, int $uid): int
* configuration of another site, if so we return the rootPageId of this site.
* The result is cached by the caching framework.
*
* @return int[]
*
* @throws UnexpectedTYPO3SiteInitializationException
*/
public function getAlternativeSiteRootPagesIds(string $table, int $uid, int $recordPageId): array
Expand All @@ -230,6 +249,8 @@ public function getAlternativeSiteRootPagesIds(string $table, int $uid, int $rec
/**
* Retrieves an optimized array structure with the monitored pageId as key and the relevant site rootIds as value.
*
* @return array<int, int[]>
*
* @throws UnexpectedTYPO3SiteInitializationException
*/
protected function getSiteRootsByObservedPageIds(string $table, int $uid): array
Expand All @@ -250,6 +271,8 @@ protected function getSiteRootsByObservedPageIds(string $table, int $uid): array
* This method builds an array with observer page id as key and rootPageIds as values to determine which root pages
* are responsible for this record by referencing the pageId in additionalPageIds configuration.
*
* @return array<int, int[]>
*
* @throws UnexpectedTYPO3SiteInitializationException
*/
protected function buildSiteRootsByObservedPageIds(string $table, int $uid): array
Expand Down
Loading