Skip to content
Permalink
Browse files

EZP-26885: Refactor Field Types external storages to inject gateways …

…and connection handler via DI (#1985)

* EZP-26885: Added to SPI ext. storage GW base classes

* EZP-26885: Deprecated getting GW from StorageHandler context

* EZP-26885: [Keyword FT] Injected ext storage GW and connection via DI

* EZP-26885: [BinaryFile, Media FT] Injected ext storage GW and connection via DI

* EZP-26885: [Image FT] Injected ext storage GW and connection via DI

* EZP-26885: [MapLocation FT] Injected ext storage GW and connection via DI

* EZP-26885: [User FT] Injected ext storage GW and connection via DI

* EZP-26885: [Page FT] Injected ext storage GW connection via DI

* EZP-26885: [RichText FT] Injected ext storage GW and connection via DI

* EZP-26885: [Url FT] Injected ext storage GW and connection via DI

* EZP-26885: Added upgrade notes

* fixup! EZP-26885: Added upgrade notes
  • Loading branch information...
alongosz authored and andrerom committed Jun 21, 2017
1 parent 79eb48d commit 9f5f9b2d592f91a01f39ec654d023446dd5b3fa9
Showing with 560 additions and 540 deletions.
  1. +17 −0 doc/bc/changes-6.11.md
  2. +168 −0 doc/upgrade/6.11.md
  3. +22 −20 eZ/Publish/Core/FieldType/BinaryBase/BinaryBaseStorage.php
  4. +1 −1 eZ/Publish/Core/FieldType/BinaryBase/BinaryBaseStorage/Gateway.php
  5. +10 −32 eZ/Publish/Core/FieldType/BinaryBase/BinaryBaseStorage/Gateway/LegacyStorage.php
  6. +24 −0 eZ/Publish/Core/FieldType/GatewayBasedStorage.php
  7. +12 −11 eZ/Publish/Core/FieldType/Image/ImageStorage.php
  8. +4 −1 eZ/Publish/Core/FieldType/Image/ImageStorage/Gateway.php
  9. +6 −33 eZ/Publish/Core/FieldType/Image/ImageStorage/Gateway/LegacyStorage.php
  10. +16 −9 eZ/Publish/Core/FieldType/Keyword/KeywordStorage.php
  11. +4 −1 eZ/Publish/Core/FieldType/Keyword/KeywordStorage/Gateway.php
  12. +2 −26 eZ/Publish/Core/FieldType/Keyword/KeywordStorage/Gateway/LegacyStorage.php
  13. +17 −9 eZ/Publish/Core/FieldType/MapLocation/MapLocationStorage.php
  14. +4 −1 eZ/Publish/Core/FieldType/MapLocation/MapLocationStorage/Gateway.php
  15. +13 −36 eZ/Publish/Core/FieldType/MapLocation/MapLocationStorage/Gateway/LegacyStorage.php
  16. +1 −1 eZ/Publish/Core/FieldType/Page/PageStorage/Gateway.php
  17. +1 −24 eZ/Publish/Core/FieldType/Page/PageStorage/Gateway/LegacyStorage.php
  18. +16 −17 eZ/Publish/Core/FieldType/RichText/RichTextStorage.php
  19. +1 −1 eZ/Publish/Core/FieldType/RichText/RichTextStorage/Gateway.php
  20. +3 −25 eZ/Publish/Core/FieldType/RichText/RichTextStorage/Gateway/LegacyStorage.php
  21. +6 −7 eZ/Publish/Core/FieldType/StorageGateway.php
  22. +5 −1 eZ/Publish/Core/FieldType/Tests/Page/PageServiceTest.php
  23. +4 −22 eZ/Publish/Core/FieldType/Tests/RichText/Gateway/LegacyStorageTest.php
  24. +14 −35 eZ/Publish/Core/FieldType/Tests/RichText/RichTextStorageTest.php
  25. +1 −19 eZ/Publish/Core/FieldType/Tests/Url/Gateway/LegacyStorageTest.php
  26. +20 −59 eZ/Publish/Core/FieldType/Tests/Url/UrlStorageTest.php
  27. +20 −17 eZ/Publish/Core/FieldType/Url/UrlStorage.php
  28. +1 −1 eZ/Publish/Core/FieldType/Url/UrlStorage/Gateway.php
  29. +2 −27 eZ/Publish/Core/FieldType/Url/UrlStorage/Gateway/LegacyStorage.php
  30. +13 −34 eZ/Publish/Core/FieldType/User/UserStorage.php
  31. +1 −1 eZ/Publish/Core/FieldType/User/UserStorage/Gateway.php
  32. +8 −19 eZ/Publish/Core/FieldType/User/UserStorage/Gateway/LegacyStorage.php
  33. +8 −4 eZ/Publish/Core/settings/fieldtype_external_storages.yml
  34. +11 −19 eZ/Publish/Core/settings/storage_engines/legacy/external_storage_gateways.yml
  35. +52 −0 eZ/Publish/SPI/FieldType/GatewayBasedStorage.php
  36. +31 −0 eZ/Publish/SPI/FieldType/StorageGateway.php
  37. +2 −4 eZ/Publish/SPI/Tests/FieldType/BinaryFileIntegrationTest.php
  38. +3 −2 eZ/Publish/SPI/Tests/FieldType/ImageIntegrationTest.php
  39. +1 −3 eZ/Publish/SPI/Tests/FieldType/KeywordIntegrationTest.php
  40. +3 −3 eZ/Publish/SPI/Tests/FieldType/MapLocationIntegrationTest.php
  41. +2 −4 eZ/Publish/SPI/Tests/FieldType/MediaIntegrationTest.php
  42. +6 −3 eZ/Publish/SPI/Tests/FieldType/RichTextIntegrationTest.php
  43. +2 −4 eZ/Publish/SPI/Tests/FieldType/UrlIntegrationTest.php
  44. +2 −4 eZ/Publish/SPI/Tests/FieldType/UserIntegrationTest.php
@@ -0,0 +1,17 @@
# Backwards compatibility changes

Changes affecting version compatibility with former or future versions.

## Changes

## Deprecations

- EZP-26885: Field Type external storage
- Abstract base class `eZ\Publish\Core\FieldType\StorageGateway` for the gateway of a Field Type
external storage and specifically its method `setConnection` are deprecated.
- Abstract base class `eZ\Publish\Core\FieldType\GatewayBasedStorage` for Field Type external storage
which uses gateway and specifically its method `getGateway` are deprecated.

See [6.11 Upgrade Notes](../upgrade/6.11.md) for the details.

## Removed features
@@ -0,0 +1,168 @@
# Upgrade steps from 6.10 to 6.11

## Field Type external storage

### External storage gateways

Abstract base class `eZ\Publish\Core\FieldType\StorageGateway` for the gateway of a Field Type
external storage and the `eZ\Publish\Core\FieldType\StorageGateway::setConnection` method are deprecated.

To prepare your FieldType for future storage engines and avoid using the deprecated abstract,
extend the`eZ\Publish\SPI\FieldType\StorageGateway` class and inject Database Handler directly
into the gateway instead.

Before:
```yml
app.field_type.custom_field_type.storage_gateway:
class: CustomFieldTypeStorageGateway
tags:
- {name: ezpublish.fieldType.externalStorageHandler.gateway, alias: customfield, identifier: LegacyStorage}
```

```php
use eZ\Publish\Core\FieldType\StorageGateway;
use eZ\Publish\Core\Persistence\Database\DatabaseHandler;
class CustomFieldTypeStorageGateway extends StorageGateway
{
/**
* @var \eZ\Publish\Core\Persistence\Database\DatabaseHandler
*/
protected $dbHandler;
public function setConnection(DatabaseHandler $dbHandler)
{
$this->dbHandler = $dbHandler;
}
// ...
}
```

After:
```yml
app.field_type.custom_field_type.storage_gateway:
class: CustomFieldTypeStorageGateway
arguments:
- "@ezpublish.api.storage_engine.legacy.dbhandler"
```

```php
use eZ\Publish\SPI\FieldType\StorageGateway;
use eZ\Publish\Core\Persistence\Database\DatabaseHandler;
class CustomFieldTypeStorageGateway extends StorageGateway
{
/**
* @var \eZ\Publish\Core\Persistence\Database\DatabaseHandler
*/
protected $dbHandler;
public function __construct(DatabaseHandler $dbHandler)
{
$this->dbHandler = $dbHandler;
}
// ...
}
```
### External storage handlers

Abstract base class `eZ\Publish\Core\FieldType\GatewayBasedStorage` for Field Type external storage
which uses gateway is deprecated.

To prepare your FieldType for future storage engines and avoid using the deprecated abstract,
use `eZ\Publish\SPI\FieldType\GatewayBasedStorage` instead and inject external
storage gateway using Dependency Injection.

Before:
```yml
app.field_type.custom_field_type.external_storage:
class: CustomFieldTypeStorage
tags:
- {name: ezpublish.fieldType.externalStorageHandler, alias: customfield}
```

```php
use eZ\Publish\Core\FieldType\GatewayBasedStorage;
class CustomFieldTypeStorage extends GatewayBasedStorage
{
public function __construct(array $gateways = [])
{
// ...
}
public function storeFieldData(VersionInfo $versionInfo, Field $field, array $context)
{
$this->getGateway($context)->storeFieldData($versionInfo, $field);
// ..
}
public function getFieldData(VersionInfo $versionInfo, Field $field, array $context)
{
$this->getGateway($context)->getFieldData($versionInfo, $field);
// ..
}
public function deleteFieldData(VersionInfo $versionInfo, array $fieldIds, array $context)
{
$this->getGateway($context)->deleteFieldData($versionInfo, $field);
// ..
}
// ...
}
```

After:
```yml
app.field_type.custom_field_type.external_storage:
class: CustomFieldTypeStorage
arguments:
- "@app.field_type.custom_field_type.storage_gateway"
tags:
- {name: ezpublish.fieldType.externalStorageHandler, alias: customfield}
```

```php
use eZ\Publish\SPI\FieldType\GatewayBasedStorage;
use eZ\Publish\SPI\FieldType\StorageGateway;
class CustomFieldTypeStorage extends GatewayBasedStorage
{
public function __construct(StorageGateway gateway)
{
parent::__construct($gateway);
// ...
}
public function storeFieldData(VersionInfo $versionInfo, Field $field, array $context)
{
$this->gateway->storeFieldData($versionInfo, $field);
// ..
}
public function getFieldData(VersionInfo $versionInfo, Field $field, array $context)
{
$this->gateway->getFieldData($versionInfo, $field);
// ..
}
public function deleteFieldData(VersionInfo $versionInfo, array $fieldIds, array $context)
{
$this->gateway->deleteFieldData($versionInfo, $field);
// ..
}
// ...
}
```
@@ -8,17 +8,16 @@
*/
namespace eZ\Publish\Core\FieldType\BinaryBase;
use eZ\Publish\Core\FieldType\GatewayBasedStorage;
use eZ\Publish\SPI\FieldType\GatewayBasedStorage;
use eZ\Publish\Core\IO\IOServiceInterface;
use eZ\Publish\SPI\FieldType\BinaryBase\PathGenerator;
use eZ\Publish\SPI\FieldType\StorageGateway;
use eZ\Publish\SPI\IO\MimeTypeDetector;
use eZ\Publish\SPI\Persistence\Content\Field;
use eZ\Publish\SPI\Persistence\Content\VersionInfo;
/**
* Storage for binary files.
*
* @method \eZ\Publish\Core\FieldType\BinaryBase\BinaryBaseStorage\Gateway getGateway(array $context)
*/
class BinaryBaseStorage extends GatewayBasedStorage
{
@@ -38,17 +37,24 @@ class BinaryBaseStorage extends GatewayBasedStorage
/** @var PathGenerator */
protected $downloadUrlGenerator;
/** @var \eZ\Publish\Core\FieldType\BinaryBase\BinaryBaseStorage\Gateway */
protected $gateway;
/**
* Construct from gateways.
*
* @param \eZ\Publish\Core\FieldType\StorageGateway[] $gateways
* @param \eZ\Publish\SPI\FieldType\StorageGateway $gateway
* @param \eZ\Publish\Core\IO\IOServiceInterface $IOService
* @param \eZ\Publish\SPI\FieldType\BinaryBase\PathGenerator $pathGenerator
* @param \eZ\Publish\SPI\IO\MimeTypeDetector $mimeTypeDetector
*/
public function __construct(array $gateways, IOServiceInterface $IOService, PathGenerator $pathGenerator, MimeTypeDetector $mimeTypeDetector)
{
parent::__construct($gateways);
public function __construct(
StorageGateway $gateway,
IOServiceInterface $IOService,
PathGenerator $pathGenerator,
MimeTypeDetector $mimeTypeDetector
) {
parent::__construct($gateway);
$this->IOService = $IOService;
$this->pathGenerator = $pathGenerator;
$this->mimeTypeDetector = $mimeTypeDetector;
@@ -90,7 +96,7 @@ public function storeFieldData(VersionInfo $versionInfo, Field $field, array $co
$this->removeOldFile($field->id, $versionInfo->versionNo, $context);
$this->getGateway($context)->storeFileReference($versionInfo, $field);
$this->gateway->storeFileReference($versionInfo, $field);
}
public function copyLegacyField(VersionInfo $versionInfo, Field $field, Field $originalField, array $context)
@@ -102,7 +108,7 @@ public function copyLegacyField(VersionInfo $versionInfo, Field $field, Field $o
// field translations have their own file reference, but to the original file
$originalField->value->externalData['id'];
return $this->getGateway($context)->storeFileReference($versionInfo, $field);
return $this->gateway->storeFileReference($versionInfo, $field);
}
/**
@@ -115,17 +121,15 @@ public function copyLegacyField(VersionInfo $versionInfo, Field $field, Field $o
*/
protected function removeOldFile($fieldId, $versionNo, array $context)
{
$gateway = $this->getGateway($context);
$fileReference = $gateway->getFileReferenceData($fieldId, $versionNo);
$fileReference = $this->gateway->getFileReferenceData($fieldId, $versionNo);
if ($fileReference === null) {
// No previous file
return;
}
$gateway->removeFileReference($fieldId, $versionNo);
$this->gateway->removeFileReference($fieldId, $versionNo);
$fileCounts = $gateway->countFileReferences(array($fileReference['id']));
$fileCounts = $this->gateway->countFileReferences(array($fileReference['id']));
if ($fileCounts[$fileReference['id']] === 0) {
$binaryFile = $this->IOService->loadBinaryFile($fileReference['id']);
@@ -135,7 +139,7 @@ protected function removeOldFile($fieldId, $versionNo, array $context)
public function getFieldData(VersionInfo $versionInfo, Field $field, array $context)
{
$field->value->externalData = $this->getGateway($context)->getFileReferenceData($field->id, $versionInfo->versionNo);
$field->value->externalData = $this->gateway->getFileReferenceData($field->id, $versionInfo->versionNo);
if ($field->value->externalData !== null) {
$binaryFile = $this->IOService->loadBinaryFile($field->value->externalData['id']);
$field->value->externalData['fileSize'] = $binaryFile->size;
@@ -151,13 +155,11 @@ public function deleteFieldData(VersionInfo $versionInfo, array $fieldIds, array
return;
}
$gateway = $this->getGateway($context);
$referencedFiles = $gateway->getReferencedFiles($fieldIds, $versionInfo->versionNo);
$referencedFiles = $this->gateway->getReferencedFiles($fieldIds, $versionInfo->versionNo);
$gateway->removeFileReferences($fieldIds, $versionInfo->versionNo);
$this->gateway->removeFileReferences($fieldIds, $versionInfo->versionNo);
$referenceCountMap = $gateway->countFileReferences($referencedFiles);
$referenceCountMap = $this->gateway->countFileReferences($referencedFiles);
foreach ($referenceCountMap as $filePath => $count) {
if ($count === 0) {
@@ -10,7 +10,7 @@
use eZ\Publish\SPI\Persistence\Content\VersionInfo;
use eZ\Publish\SPI\Persistence\Content\Field;
use eZ\Publish\Core\FieldType\StorageGateway;
use eZ\Publish\SPI\FieldType\StorageGateway;
abstract class Gateway extends StorageGateway
{
@@ -8,6 +8,7 @@
*/
namespace eZ\Publish\Core\FieldType\BinaryBase\BinaryBaseStorage\Gateway;
use eZ\Publish\Core\Persistence\Database\DatabaseHandler;
use eZ\Publish\SPI\Persistence\Content\VersionInfo;
use eZ\Publish\SPI\Persistence\Content\Field;
use eZ\Publish\Core\FieldType\BinaryBase\BinaryBaseStorage\Gateway;
@@ -17,12 +18,15 @@
abstract class LegacyStorage extends Gateway
{
/**
* Connection.
*
* @var mixed
* @var \eZ\Publish\Core\Persistence\Database\DatabaseHandler
*/
protected $dbHandler;
public function __construct(DatabaseHandler $dbHandler)
{
$this->dbHandler = $dbHandler;
}
/**
* Returns the table name to store data in.
*
@@ -110,48 +114,22 @@ protected function setInsertColumns(InsertQuery $insertQuery, VersionInfo $versi
);
}
/**
* Set database handler for this gateway.
*
* @param mixed $dbHandler
*
* @throws \RuntimeException if $dbHandler is not an instance of
* {@link \eZ\Publish\Core\Persistence\Database\DatabaseHandler}
*/
public function setConnection($dbHandler)
{
// This obviously violates the Liskov substitution Principle, but with
// the given class design there is no sane other option. Actually the
// dbHandler *should* be passed to the constructor, and there should
// not be the need to post-inject it.
if (!$dbHandler instanceof \eZ\Publish\Core\Persistence\Database\DatabaseHandler) {
throw new \RuntimeException('Invalid dbHandler passed');
}
$this->dbHandler = $dbHandler;
}
/**
* Returns the active connection.
*
* @throws \RuntimeException if no connection has been set, yet.
*
* @return \eZ\Publish\Core\Persistence\Database\DatabaseHandler
*/
protected function getConnection()
{
if ($this->dbHandler === null) {
throw new \RuntimeException('Missing database connection.');
}
return $this->dbHandler;
}
/**
* Stores the file reference in $field for $versionNo.
*
* @param VersionInfo $versionInfo
* @param Field $field
* @param \eZ\Publish\SPI\Persistence\Content\VersionInfo $versionInfo
* @param \eZ\Publish\SPI\Persistence\Content\Field $field
* @return bool
*/
public function storeFileReference(VersionInfo $versionInfo, Field $field)
{
Oops, something went wrong.

0 comments on commit 9f5f9b2

Please sign in to comment.
You can’t perform that action at this time.