Skip to content
Snippets Groups Projects
Commit aa119c75 authored by Vadim Justus's avatar Vadim Justus
Browse files

Introduce ContentEntry data model

parent cd826c6d
Branches
Tags
No related merge requests found
<?php
declare(strict_types=1);
namespace Firegento\ContentProvisioning\Api\Data;
interface ContentEntryInterface
{
/**
* Data entry keys
*/
const TYPE = 'type';
const IDENTIFIER = 'identifier';
const CONTENT = 'content';
const STORES = 'stores';
const IS_MAINTAINED = 'is_maintained';
/**
* @return string
*/
public function getType(): string;
/**
* @return string
*/
public function getIdentifier(): string;
/**
* @return string
*/
public function getContent(): string;
/**
* @return array
*/
public function getStores(): array;
/**
* @return bool
*/
public function isMaintained(): bool;
/**
* @param string $type
*/
public function setType(string $type): void;
/**
* @param string $identifier
*/
public function setIdentifier(string $identifier): void;
/**
* @param string $content
*/
public function setContent(string $content): void;
/**
* @param string[] $stores
*/
public function setStores(array $stores): void;
/**
* @param bool $isMaintained
*/
public function setIsMaintained(bool $isMaintained): void;
}
...@@ -6,9 +6,11 @@ namespace Firegento\ContentProvisioning\Model\Config; ...@@ -6,9 +6,11 @@ namespace Firegento\ContentProvisioning\Model\Config;
use DOMDocument; use DOMDocument;
use DOMElement; use DOMElement;
use DOMNode; use DOMNode;
use Firegento\ContentProvisioning\Api\Data\ContentEntryInterface;
use Firegento\ContentProvisioning\Api\StoreCodeResolverInterface; use Firegento\ContentProvisioning\Api\StoreCodeResolverInterface;
use Firegento\ContentProvisioning\Model\ContentResolverProvider; use Firegento\ContentProvisioning\Model\ContentResolverProvider;
use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Exception\LocalizedException;
use Psr\Log\LoggerInterface;
class Converter implements \Magento\Framework\Config\ConverterInterface class Converter implements \Magento\Framework\Config\ConverterInterface
{ {
...@@ -22,16 +24,24 @@ class Converter implements \Magento\Framework\Config\ConverterInterface ...@@ -22,16 +24,24 @@ class Converter implements \Magento\Framework\Config\ConverterInterface
*/ */
private $contentResolverProvider; private $contentResolverProvider;
/**
* @var LoggerInterface
*/
private $logger;
/** /**
* @param StoreCodeResolverInterface $storeCodeResolver * @param StoreCodeResolverInterface $storeCodeResolver
* @param ContentResolverProvider $contentResolverProvider * @param ContentResolverProvider $contentResolverProvider
* @param LoggerInterface $logger
*/ */
public function __construct( public function __construct(
StoreCodeResolverInterface $storeCodeResolver, StoreCodeResolverInterface $storeCodeResolver,
ContentResolverProvider $contentResolverProvider ContentResolverProvider $contentResolverProvider,
LoggerInterface $logger
) { ) {
$this->storeCodeResolver = $storeCodeResolver; $this->storeCodeResolver = $storeCodeResolver;
$this->contentResolverProvider = $contentResolverProvider; $this->contentResolverProvider = $contentResolverProvider;
$this->logger = $logger;
} }
/** /**
...@@ -40,16 +50,15 @@ class Converter implements \Magento\Framework\Config\ConverterInterface ...@@ -40,16 +50,15 @@ class Converter implements \Magento\Framework\Config\ConverterInterface
*/ */
public function convert($source): array public function convert($source): array
{ {
return [ return array_merge(
'pages' => $this->extractCmsEntityNodes($source, 'page'), $this->extractCmsEntityNodes($source, 'page'),
'blocks' => $this->extractCmsEntityNodes($source, 'block'), $this->extractCmsEntityNodes($source, 'block')
]; );
} }
/** /**
* @param DOMDocument $config * @param DOMDocument $config
* @return array * @return array
* @throws LocalizedException
*/ */
private function extractCmsEntityNodes(DOMDocument $config, string $nodeKey): array private function extractCmsEntityNodes(DOMDocument $config, string $nodeKey): array
{ {
...@@ -57,13 +66,20 @@ class Converter implements \Magento\Framework\Config\ConverterInterface ...@@ -57,13 +66,20 @@ class Converter implements \Magento\Framework\Config\ConverterInterface
/** @var $node DOMElement */ /** @var $node DOMElement */
foreach ($config->getElementsByTagName($nodeKey) as $node) { foreach ($config->getElementsByTagName($nodeKey) as $node) {
$identifier = $this->getAttributeValue($node, 'identifier'); $identifier = $this->getAttributeValue($node, 'identifier');
try {
$stores = $this->extractStores($node); $stores = $this->extractStores($node);
$output[$this->buildKey($identifier, $stores)] = [ $output[$this->buildKey($identifier, $stores, $nodeKey)] = [
'identifier' => $identifier, ContentEntryInterface::IDENTIFIER => $identifier,
'maintained' => (bool)$this->getAttributeValue($node, 'maintained', false), ContentEntryInterface::TYPE => $nodeKey,
'stores' => $stores, ContentEntryInterface::IS_MAINTAINED =>
'content' => $this->extractContent($node) (bool)$this->getAttributeValue($node, 'maintained', false),
ContentEntryInterface::STORES => $stores,
ContentEntryInterface::CONTENT => $this->extractContent($node),
]; ];
} catch (LocalizedException $exception) {
$this->logger->error($exception->getMessage(), $exception->getTrace());
continue;
}
} }
return $output; return $output;
} }
...@@ -71,11 +87,12 @@ class Converter implements \Magento\Framework\Config\ConverterInterface ...@@ -71,11 +87,12 @@ class Converter implements \Magento\Framework\Config\ConverterInterface
/** /**
* @param string $identifier * @param string $identifier
* @param array $stores * @param array $stores
* @param string $nodeKey
* @return string * @return string
*/ */
private function buildKey(string $identifier, array $stores): string private function buildKey(string $identifier, array $stores, string $nodeKey): string
{ {
return md5($identifier . json_encode($stores)); return md5($identifier . $nodeKey . json_encode($stores));
} }
/** /**
...@@ -91,6 +108,11 @@ class Converter implements \Magento\Framework\Config\ConverterInterface ...@@ -91,6 +108,11 @@ class Converter implements \Magento\Framework\Config\ConverterInterface
); );
$output = array_merge($output, $storeCodes); $output = array_merge($output, $storeCodes);
} }
if (empty($output)) {
$output = $this->storeCodeResolver->execute('*');
}
return $output; return $output;
} }
......
...@@ -3,6 +3,8 @@ declare(strict_types=1); ...@@ -3,6 +3,8 @@ declare(strict_types=1);
namespace Firegento\ContentProvisioning\Model\Config; namespace Firegento\ContentProvisioning\Model\Config;
use Magento\Framework\Module\Dir\Reader;
class SchemaLocator implements \Magento\Framework\Config\SchemaLocatorInterface class SchemaLocator implements \Magento\Framework\Config\SchemaLocatorInterface
{ {
/** /**
...@@ -20,9 +22,9 @@ class SchemaLocator implements \Magento\Framework\Config\SchemaLocatorInterface ...@@ -20,9 +22,9 @@ class SchemaLocator implements \Magento\Framework\Config\SchemaLocatorInterface
protected $_perFileSchema = null; protected $_perFileSchema = null;
/** /**
* @param \Magento\Framework\Module\Dir\Reader $moduleReader * @param Reader $moduleReader
*/ */
public function __construct(\Magento\Framework\Module\Dir\Reader $moduleReader) public function __construct(Reader $moduleReader)
{ {
$etcDir = $moduleReader->getModuleDir( $etcDir = $moduleReader->getModuleDir(
\Magento\Framework\Module\Dir::MODULE_ETC_DIR, \Magento\Framework\Module\Dir::MODULE_ETC_DIR,
......
...@@ -3,7 +3,7 @@ declare(strict_types=1); ...@@ -3,7 +3,7 @@ declare(strict_types=1);
namespace Firegento\ContentProvisioning\Model\Console; namespace Firegento\ContentProvisioning\Model\Console;
use Firegento\ContentProvisioning\Api\ConfigurationInterface; use Firegento\ContentProvisioning\Model\Query\GetAllContentEntries;
use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\OutputInterface;
...@@ -12,20 +12,20 @@ use Symfony\Component\Console\Helper\Table; ...@@ -12,20 +12,20 @@ use Symfony\Component\Console\Helper\Table;
class ListCommand extends Command class ListCommand extends Command
{ {
/** /**
* @var ConfigurationInterface * @var GetAllContentEntries
*/ */
private $configuration; private $getAllContentEntries;
/** /**
* @param ConfigurationInterface $configuration * @param GetAllContentEntries $getAllContentEntries
* @param string|null $name * @param string|null $name
*/ */
public function __construct( public function __construct(
ConfigurationInterface $configuration, GetAllContentEntries $getAllContentEntries,
string $name = null string $name = null
) { ) {
parent::__construct($name); parent::__construct($name);
$this->configuration = $configuration; $this->getAllContentEntries = $getAllContentEntries;
} }
/** /**
...@@ -36,17 +36,15 @@ class ListCommand extends Command ...@@ -36,17 +36,15 @@ class ListCommand extends Command
$table = new Table($output); $table = new Table($output);
$table->setHeaders(['Type', 'Identifier', 'Stores', 'Maintained', 'Content (Teaser)']); $table->setHeaders(['Type', 'Identifier', 'Stores', 'Maintained', 'Content (Teaser)']);
foreach ($this->configuration->getList() as $type => $entries) { foreach ($this->getAllContentEntries->get() as $entry) {
foreach ($entries as $entry) {
$table->addRow([ $table->addRow([
$type, $entry->getType(),
$entry['identifier'], $entry->getIdentifier(),
implode(', ', $entry['stores']), implode(', ', $entry->getStores()),
$entry['maintained'] ? 'yes' : 'no', $entry->isMaintained() ? 'yes' : 'no',
substr($entry['content'], 0, 200), substr($entry->getContent(), 0, 147) . '...',
]); ]);
} }
}
$table->render($output); $table->render($output);
} }
......
<?php
declare(strict_types=1);
namespace Firegento\ContentProvisioning\Model;
use Firegento\ContentProvisioning\Api\Data\ContentEntryInterface;
use Magento\Framework\DataObject;
class ContentEntry extends DataObject implements ContentEntryInterface
{
/**
* @return string
*/
public function getType(): string
{
return (string)$this->getData(ContentEntryInterface::TYPE);
}
/**
* @return string
*/
public function getIdentifier(): string
{
return (string)$this->getData(ContentEntryInterface::IDENTIFIER);
}
/**
* @return string
*/
public function getContent(): string
{
return (string)$this->getData(ContentEntryInterface::CONTENT);
}
/**
* @return array
*/
public function getStores(): array
{
return (array)$this->getData(ContentEntryInterface::STORES);
}
/**
* @return bool
*/
public function isMaintained(): bool
{
return (bool)$this->getData(ContentEntryInterface::IS_MAINTAINED);
}
/**
* @param string $type
*/
public function setType(string $type): void
{
$this->setData(ContentEntryInterface::TYPE, $type);
}
/**
* @param string $identifier
*/
public function setIdentifier(string $identifier): void
{
$this->setData(ContentEntryInterface::IDENTIFIER, $identifier);
}
/**
* @param string $content
*/
public function setContent(string $content): void
{
$this->setData(ContentEntryInterface::CONTENT, $content);
}
/**
* @param string[] $stores
*/
public function setStores(array $stores): void
{
$this->setData(ContentEntryInterface::STORES, $stores);
}
/**
* @param bool $isMaintained
*/
public function setIsMaintained(bool $isMaintained): void
{
$this->setData(ContentEntryInterface::IS_MAINTAINED, $isMaintained);
}
}
\ No newline at end of file
<?php
declare(strict_types=1);
namespace Firegento\ContentProvisioning\Model;
use Firegento\ContentProvisioning\Api\ContentInstallerInterface;
class ContentInstaller implements ContentInstallerInterface
{
/**
* Apply all configured CMS content changes
*
* @return void
*/
public function install(): void
{
// TODO: Implement install() method.
}
}
\ No newline at end of file
<?php
declare(strict_types=1);
namespace Firegento\ContentProvisioning\Model\Query;
use Firegento\ContentProvisioning\Api\ConfigurationInterface;
use Firegento\ContentProvisioning\Api\Data\ContentEntryInterface;
use Firegento\ContentProvisioning\Api\Data\ContentEntryInterfaceFactory;
class GetAllContentEntries
{
/**
* @var ConfigurationInterface
*/
private $configuration;
/**
* @var ContentEntryInterfaceFactory
*/
private $contentEntryFactory;
/**
* @var ContentEntryInterface[]
*/
private $items = [];
/**
* @param ConfigurationInterface $configuration
* @param ContentEntryInterfaceFactory $contentEntryFactory
*/
public function __construct(
ConfigurationInterface $configuration,
ContentEntryInterfaceFactory $contentEntryFactory
) {
$this->configuration = $configuration;
$this->contentEntryFactory = $contentEntryFactory;
}
/**
* @return ContentEntryInterface[]
*/
public function get(): array
{
if (empty($this->items)) {
foreach ($this->configuration->getList() as $data) {
$this->items[] = $this->contentEntryFactory->create(['data' => $data]);
}
}
return $this->items;
}
}
\ No newline at end of file
...@@ -5,18 +5,69 @@ namespace Firegento\ContentProvisioning\Model\Resolver; ...@@ -5,18 +5,69 @@ namespace Firegento\ContentProvisioning\Model\Resolver;
use DOMElement; use DOMElement;
use Firegento\ContentProvisioning\Api\ContentResolverInterface; use Firegento\ContentProvisioning\Api\ContentResolverInterface;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Filesystem\DirectoryList;
use Magento\Framework\Module\Dir\Reader;
class FileContentResolver implements ContentResolverInterface class FileContentResolver implements ContentResolverInterface
{ {
/**
* @var Reader
*/
private $moduleReader;
/**
* @var DirectoryList
*/
private $directoryList;
/**
* @param Reader $moduleReader
* @param DirectoryList $directoryList
*/
public function __construct(
Reader $moduleReader,
DirectoryList $directoryList
) {
$this->moduleReader = $moduleReader;
$this->directoryList = $directoryList;
}
/** /**
* @param DOMElement $node * @param DOMElement $node
* @return string * @return string
* @throws LocalizedException
*/ */
public function execute(DOMElement $node): string public function execute(DOMElement $node): string
{ {
$path = (string)$node->textContent; $path = $this->resolvePath((string)$node->textContent);
// @TODO: resolve relative and absolute paths if (!is_file($path)) {
// @TODO: resolve module namespace prefixes throw new LocalizedException(__('Given content file %file does not exists.', ['file' => $path]));
return 'foobar -> ' . $path; }
return file_get_contents($path);
}
/**
* @param string $path
* @return string
*/
private function resolvePath(string $path): string
{
if (strpos($path, '::') !== false) {
$pathParts = explode('::', $path, 2);
$moduleName = $pathParts[0];
$filePath = $pathParts[1];
$moduleDirectory = $this->moduleReader->getModuleDir('', $moduleName);
return implode(DIRECTORY_SEPARATOR, [
$moduleDirectory,
$filePath
]);
} else {
return implode(DIRECTORY_SEPARATOR, [
$this->directoryList->getRoot(),
$path
]);
}
} }
} }
\ No newline at end of file
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Firegento/ContentProvisioning/etc/content_provisioning.xsd">
<page identifier="foobar" maintained="true">
<stores>
<store code="default" />
</stores>
<content type="file">path/to/file.html</content>
</page>
<page identifier="test" maintained="false">
<stores>
<store code="*" />
</stores>
<content><![CDATA[this is some sample content...]]></content>
</page>
<block identifier="test">
<stores>
<store code="*" />
</stores>
<content><![CDATA[this is some sample content...]]></content>
</block>
<block identifier="test2" maintained="false">
<content><![CDATA[this is some sample content...]]></content>
<stores>
<store code="default" />
<store code="admin" />
</stores>
</block>
</config>
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
</xs:documentation> </xs:documentation>
</xs:annotation> </xs:annotation>
<xs:restriction base="xs:string"> <xs:restriction base="xs:string">
<xs:pattern value="[a-zA-Z0-9_\\]{1,}" /> <xs:pattern value="[a-zA-Z0-9_\\\-]{1,}" />
<xs:minLength value="2" /> <xs:minLength value="2" />
</xs:restriction> </xs:restriction>
</xs:simpleType> </xs:simpleType>
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<preference for="Firegento\ContentProvisioning\Api\ConfigurationInterface" type="Firegento\ContentProvisioning\Model\Config\Data" /> <preference for="Firegento\ContentProvisioning\Api\ConfigurationInterface" type="Firegento\ContentProvisioning\Model\Config\Data" />
<preference for="Firegento\ContentProvisioning\Api\StoreCodeResolverInterface" type="Firegento\ContentProvisioning\Model\Resolver\StoreCodeResolver" /> <preference for="Firegento\ContentProvisioning\Api\StoreCodeResolverInterface" type="Firegento\ContentProvisioning\Model\Resolver\StoreCodeResolver" />
<preference for="Firegento\ContentProvisioning\Api\ContentInstallerInterface" type="Firegento\ContentProvisioning\Model\ContentInstaller" />
<preference for="Firegento\ContentProvisioning\Api\Data\ContentEntryInterface" type="Firegento\ContentProvisioning\Model\ContentEntry" />
<virtualType name="Firegento\ContentProvisioning\Model\Config\Reader" type="Magento\Framework\Config\Reader\Filesystem"> <virtualType name="Firegento\ContentProvisioning\Model\Config\Reader" type="Magento\Framework\Config\Reader\Filesystem">
<arguments> <arguments>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment