diff --git a/.github/workflows/test-application.yaml b/.github/workflows/test-application.yaml
index 6bed923d6..02871301e 100644
--- a/.github/workflows/test-application.yaml
+++ b/.github/workflows/test-application.yaml
@@ -41,7 +41,6 @@ jobs:
dependency-versions: 'highest'
php-extensions: 'ctype, iconv, mysql, imagick'
tools: 'composer:v2'
- phpstan: true
lint: true
env:
SYMFONY_DEPRECATIONS_HELPER: weak
@@ -54,7 +53,6 @@ jobs:
dependency-versions: 'highest'
php-extensions: 'ctype, iconv, mysql, imagick'
tools: 'composer:v2'
- phpstan: false
lint: false
env:
SYMFONY_DEPRECATIONS_HELPER: weak
diff --git a/Article/Domain/Model/Article.php b/Article/Domain/Model/Article.php
new file mode 100644
index 000000000..afd7a2b4f
--- /dev/null
+++ b/Article/Domain/Model/Article.php
@@ -0,0 +1,39 @@
+id = $id ?: Uuid::uuid4()->toString();
+ }
+
+ public function getId(): string
+ {
+ return $this->id;
+ }
+}
diff --git a/Article/Domain/Model/ArticleInterface.php b/Article/Domain/Model/ArticleInterface.php
new file mode 100644
index 000000000..d626e41ef
--- /dev/null
+++ b/Article/Domain/Model/ArticleInterface.php
@@ -0,0 +1,25 @@
+children()
- ->scalarNode('index_name')->isRequired()->end()
+ ->arrayNode('article')
+ ->addDefaultsIfNotSet()
+ ->children()
+ ->enumNode('storage')
+ ->values([self::ARTICLE_STORAGE_PHPCR, self::ARTICLE_STORAGE_EXPERIMENTAL])
+ ->defaultValue(self::ARTICLE_STORAGE_PHPCR)
+ ->end()
+ ->arrayNode('objects')
+ ->addDefaultsIfNotSet()
+ ->children()
+ ->arrayNode('article')
+ ->addDefaultsIfNotSet()
+ ->children()
+ ->scalarNode('model')->defaultValue(Article::class)->end()
+ ->end()
+ ->end()
+ ->end()
+ ->end()
+ ->end()
+ ->end()
+ ->scalarNode('index_name')->end()
->arrayNode('hosts')
->prototype('scalar')->end()
->end()
diff --git a/DependencyInjection/SuluArticleExtension.php b/DependencyInjection/SuluArticleExtension.php
index 0d0418fd9..9a234ce9f 100644
--- a/DependencyInjection/SuluArticleExtension.php
+++ b/DependencyInjection/SuluArticleExtension.php
@@ -11,6 +11,7 @@
namespace Sulu\Bundle\ArticleBundle\DependencyInjection;
+use Sulu\Bundle\ArticleBundle\Article\Domain\Model\ArticleInterface;
use Sulu\Bundle\ArticleBundle\Document\ArticleDocument;
use Sulu\Bundle\ArticleBundle\Document\ArticlePageDocument;
use Sulu\Bundle\ArticleBundle\Document\Form\ArticleDocumentType;
@@ -19,6 +20,7 @@
use Sulu\Bundle\ArticleBundle\Document\Structure\ArticlePageBridge;
use Sulu\Bundle\ArticleBundle\Exception\ArticlePageNotFoundException;
use Sulu\Bundle\ArticleBundle\Exception\ParameterNotAllowedException;
+use Sulu\Bundle\PersistenceBundle\DependencyInjection\PersistenceExtensionTrait;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
@@ -26,16 +28,122 @@
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
/**
- * This is the class that loads and manages article bundle configuration.
+ * @internal
+ *
+ * This is the class that loads and manages article bundle configuration
*/
class SuluArticleExtension extends Extension implements PrependExtensionInterface
{
+ use PersistenceExtensionTrait;
+
/**
* {@inheritdoc}
*/
public function prepend(ContainerBuilder $container)
+ {
+ $configs = $container->getExtensionConfig($this->getAlias());
+ $resolvingBag = $container->getParameterBag();
+ $configs = $resolvingBag->resolveValue($configs);
+ $config = $this->processConfiguration(new Configuration(), $configs);
+
+ $storage = $config['article']['storage'];
+
+ if ($container->hasExtension('jms_serializer')) {
+ $container->prependExtensionConfig(
+ 'jms_serializer',
+ [
+ 'metadata' => [
+ 'directories' => [
+ 'sulu_article' => [
+ 'path' => __DIR__ . '/../Resources/config/serializer',
+ 'namespace_prefix' => 'Sulu\Bundle\ArticleBundle',
+ ],
+ ],
+ ],
+ ]
+ );
+ }
+
+ if ($container->hasExtension('sulu_admin')) {
+ $container->prependExtensionConfig(
+ 'sulu_admin',
+ [
+ 'lists' => [
+ 'directories' => [
+ __DIR__ . '/../Resources/config/lists',
+ ],
+ ],
+ 'forms' => [
+ 'directories' => [
+ __DIR__ . '/../Resources/config/forms',
+ ],
+ ],
+ 'resources' => [
+ 'articles' => [
+ 'routes' => [
+ 'list' => 'sulu_article.get_articles',
+ 'detail' => 'sulu_article.get_article',
+ ],
+ ],
+ 'article_versions' => [
+ 'routes' => [
+ 'list' => 'sulu_article.get_article_versions',
+ 'detail' => 'sulu_article.post_article_version_trigger',
+ ],
+ ],
+ ],
+ 'field_type_options' => [
+ 'selection' => [
+ 'article_selection' => [
+ 'default_type' => 'list_overlay',
+ 'resource_key' => 'articles',
+ 'types' => [
+ 'list_overlay' => [
+ 'adapter' => 'table',
+ 'list_key' => 'articles',
+ 'display_properties' => ['title', 'routePath'],
+ 'icon' => 'su-newspaper',
+ 'label' => 'sulu_article.selection_label',
+ 'overlay_title' => 'sulu_article.selection_overlay_title',
+ ],
+ ],
+ ],
+ ],
+ 'single_selection' => [
+ 'single_article_selection' => [
+ 'default_type' => 'list_overlay',
+ 'resource_key' => 'articles',
+ 'types' => [
+ 'list_overlay' => [
+ 'adapter' => 'table',
+ 'list_key' => 'articles',
+ 'display_properties' => ['title'],
+ 'empty_text' => 'sulu_article.no_article_selected',
+ 'icon' => 'su-newspaper',
+ 'overlay_title' => 'sulu_article.single_selection_overlay_title',
+ ],
+ ],
+ ],
+ ],
+ ],
+ ]
+ );
+ }
+
+ if (Configuration::ARTICLE_STORAGE_PHPCR === $storage) {
+ $this->prependPHPCRStorage($container);
+ } elseif (Configuration::ARTICLE_STORAGE_EXPERIMENTAL === $storage) {
+ $this->prependExperimentalStorage($container);
+ }
+ }
+
+ /**
+ * Can be removed when phpcr storage is removed.
+ */
+ private function prependPHPCRStorage(ContainerBuilder $container): void
{
if ($container->hasExtension('sulu_core')) {
+ // can be removed when phpcr storage is removed
$container->prependExtensionConfig(
'sulu_core',
[
@@ -62,6 +170,7 @@ public function prepend(ContainerBuilder $container)
}
if ($container->hasExtension('sulu_route')) {
+ // can be removed when phpcr storage is removed
$container->prependExtensionConfig(
'sulu_route',
[
@@ -77,23 +186,8 @@ public function prepend(ContainerBuilder $container)
);
}
- if ($container->hasExtension('jms_serializer')) {
- $container->prependExtensionConfig(
- 'jms_serializer',
- [
- 'metadata' => [
- 'directories' => [
- 'sulu_article' => [
- 'path' => __DIR__ . '/../Resources/config/serializer',
- 'namespace_prefix' => 'Sulu\Bundle\ArticleBundle',
- ],
- ],
- ],
- ]
- );
- }
-
if ($container->hasExtension('sulu_search')) {
+ // can be removed when phpcr storage is removed
$container->prependExtensionConfig(
'sulu_page',
[
@@ -108,6 +202,7 @@ public function prepend(ContainerBuilder $container)
}
if ($container->hasExtension('sulu_document_manager')) {
+ // can be removed when phpcr storage is removed
$container->prependExtensionConfig(
'sulu_document_manager',
[
@@ -131,6 +226,7 @@ public function prepend(ContainerBuilder $container)
}
if ($container->hasExtension('fos_js_routing')) {
+ // can be removed when phpcr storage is removed
$container->prependExtensionConfig(
'fos_js_routing',
[
@@ -142,6 +238,7 @@ public function prepend(ContainerBuilder $container)
}
if ($container->hasExtension('fos_rest')) {
+ // can be removed when phpcr storage is removed
$container->prependExtensionConfig(
'fos_rest',
[
@@ -156,6 +253,7 @@ public function prepend(ContainerBuilder $container)
}
if ($container->hasExtension('massive_build')) {
+ // can be removed when phpcr storage is removed
$container->prependExtensionConfig(
'massive_build',
[
@@ -180,73 +278,8 @@ public function prepend(ContainerBuilder $container)
);
}
- if ($container->hasExtension('sulu_admin')) {
- $container->prependExtensionConfig(
- 'sulu_admin',
- [
- 'lists' => [
- 'directories' => [
- __DIR__ . '/../Resources/config/lists',
- ],
- ],
- 'forms' => [
- 'directories' => [
- __DIR__ . '/../Resources/config/forms',
- ],
- ],
- 'resources' => [
- 'articles' => [
- 'routes' => [
- 'list' => 'sulu_article.get_articles',
- 'detail' => 'sulu_article.get_article',
- ],
- ],
- 'article_versions' => [
- 'routes' => [
- 'list' => 'sulu_article.get_article_versions',
- 'detail' => 'sulu_article.post_article_version_trigger',
- ],
- ],
- ],
- 'field_type_options' => [
- 'selection' => [
- 'article_selection' => [
- 'default_type' => 'list_overlay',
- 'resource_key' => 'articles',
- 'types' => [
- 'list_overlay' => [
- 'adapter' => 'table',
- 'list_key' => 'articles',
- 'display_properties' => ['title', 'routePath'],
- 'icon' => 'su-newspaper',
- 'label' => 'sulu_article.selection_label',
- 'overlay_title' => 'sulu_article.selection_overlay_title',
- ],
- ],
- ],
- ],
- 'single_selection' => [
- 'single_article_selection' => [
- 'default_type' => 'list_overlay',
- 'resource_key' => 'articles',
- 'types' => [
- 'list_overlay' => [
- 'adapter' => 'table',
- 'list_key' => 'articles',
- 'display_properties' => ['title'],
- 'empty_text' => 'sulu_article.no_article_selected',
- 'icon' => 'su-newspaper',
- 'overlay_title' => 'sulu_article.single_selection_overlay_title',
- ],
- ],
- ],
- ],
- ],
- ]
- );
- }
-
if ($container->hasExtension('ongr_elasticsearch')) {
+ // can be removed when phpcr storage is removed
$configs = $container->getExtensionConfig($this->getAlias());
$config = $this->processConfiguration(new Configuration(), $configs);
@@ -282,6 +315,86 @@ public function prepend(ContainerBuilder $container)
}
}
+ private function prependExperimentalStorage(ContainerBuilder $container): void
+ {
+ if ($container->hasExtension('doctrine')) {
+ $container->prependExtensionConfig(
+ 'doctrine',
+ [
+ 'orm' => [
+ 'mappings' => [
+ 'SuluBundleArticle' => [
+ 'type' => 'xml',
+ 'prefix' => 'Sulu\Bundle\ArticleBundle\Article\Domain\Model',
+ 'dir' => \dirname(__DIR__) . '/Resources/config/doctrine/Article',
+ 'alias' => 'SuluArticleBundle',
+ 'is_bundle' => false,
+ 'mapping' => true,
+ ],
+ ],
+ ],
+ ]
+ );
+ }
+
+ if ($container->hasExtension('sulu_core')) {
+ $container->prependExtensionConfig(
+ 'sulu_core',
+ [
+ 'content' => [
+ 'structure' => [
+ 'paths' => [
+ ArticleInterface::TEMPLATE_TYPE => [
+ 'path' => '%kernel.project_dir%/config/templates/articles',
+ 'type' => 'article',
+ ],
+ ],
+ 'default_type' => [
+ ArticleInterface::TEMPLATE_TYPE => 'default',
+ ],
+ ],
+ ],
+ ]
+ );
+ }
+
+ if ($container->hasExtension('sulu_route')) {
+ $container->prependExtensionConfig(
+ 'sulu_route',
+ [
+ 'mappings' => [
+ ArticleInterface::class => [
+ 'generator' => 'schema',
+ 'options' => [
+ 'route_schema' => '/{implode("-", object)}',
+ ],
+ 'resource_key' => ArticleInterface::RESOURCE_KEY,
+ ],
+ ],
+ ]
+ );
+ }
+
+ if ($container->hasExtension('sulu_search')) {
+ $suluSearchConfigs = $container->getExtensionConfig('sulu_search');
+
+ foreach ($suluSearchConfigs as $suluSearchConfig) {
+ if (isset($suluSearchConfig['website']['indexes'])) {
+ $container->prependExtensionConfig(
+ 'sulu_search',
+ [
+ 'website' => [
+ 'indexes' => [
+ ArticleInterface::RESOURCE_KEY => ArticleInterface::RESOURCE_KEY . '_published',
+ ],
+ ],
+ ]
+ );
+ }
+ }
+ }
+ }
+
/**
* {@inheritdoc}
*/
@@ -289,23 +402,40 @@ public function load(array $configs, ContainerBuilder $container)
{
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);
+
+ $loader = new Loader\XmlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
+
+ $storage = $config['article']['storage'];
+ $container->setParameter('sulu_article.article_storage', $storage);
+
+ if (Configuration::ARTICLE_STORAGE_PHPCR === $storage) {
+ $this->loadPHPCRStorage($config, $container, $loader);
+ } elseif (Configuration::ARTICLE_STORAGE_EXPERIMENTAL === $storage) {
+ $this->loadExperimentalStorage($config, $container, $loader);
+ }
+ }
+
+ private function loadExperimentalStorage(array $config, ContainerBuilder $container, Loader\XmlFileLoader $loader): void
+ {
+ $this->configurePersistence($config['article']['objects'], $container);
+ }
+
+ /**
+ * Can be removed when phpcr storage is removed.
+ */
+ private function loadPHPCRStorage(array $config, ContainerBuilder $container, Loader\XmlFileLoader $loader): void
+ {
$container->setParameter('sulu_article.default_main_webspace', $config['default_main_webspace']);
$container->setParameter('sulu_article.default_additional_webspaces', $config['default_additional_webspaces']);
$container->setParameter('sulu_article.types', $config['types']);
- $container->setParameter('sulu_article.documents', $config['documents']);
- $container->setParameter('sulu_article.view_document.article.class', $config['documents']['article']['view']);
$container->setParameter('sulu_article.display_tab_all', $config['display_tab_all']);
$container->setParameter('sulu_article.smart_content.default_limit', $config['smart_content']['default_limit']);
$container->setParameter('sulu_article.search_fields', $config['search_fields']);
+ $container->setParameter('sulu_article.documents', $config['documents']);
+ $container->setParameter('sulu_article.view_document.article.class', $config['documents']['article']['view']);
- $loader = new Loader\XmlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
$loader->load('services.xml');
- $bundles = $container->getParameter('kernel.bundles');
- if (array_key_exists('SuluAutomationBundle', $bundles)) {
- $loader->load('automation.xml');
- }
-
$this->appendDefaultAuthor($config, $container);
$this->appendArticlePageConfig($container);
@@ -328,6 +458,8 @@ public function load(array $configs, ContainerBuilder $container)
/**
* Append configuration for article "set_default_author".
+ *
+ * Can be removed when phpcr storage is removed.
*/
private function appendDefaultAuthor(array $config, ContainerBuilder $container): void
{
@@ -344,6 +476,8 @@ private function appendDefaultAuthor(array $config, ContainerBuilder $container)
/**
* Append configuration for article-page (cloned from article).
+ *
+ * Can be removed when phpcr storage is removed.
*/
private function appendArticlePageConfig(ContainerBuilder $container): void
{
@@ -360,6 +494,8 @@ private function appendArticlePageConfig(ContainerBuilder $container): void
/**
* Clone given path configuration and use given type.
+ *
+ * Can be removed when phpcr storage is removed.
*/
private function cloneArticleConfig(array $config, string $type): array
{
diff --git a/Resources/config/doctrine/Article/Article.orm.xml b/Resources/config/doctrine/Article/Article.orm.xml
new file mode 100644
index 000000000..2ad383d86
--- /dev/null
+++ b/Resources/config/doctrine/Article/Article.orm.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
diff --git a/Resources/config/services.xml b/Resources/config/services.xml
index 8a578e64c..d55c26c6e 100644
--- a/Resources/config/services.xml
+++ b/Resources/config/services.xml
@@ -2,6 +2,12 @@
+
+
@SuluArticle/Export/Article/1.2.xliff.twig
diff --git a/Resources/doc/experimental-storage.md b/Resources/doc/experimental-storage.md
new file mode 100644
index 000000000..11c21313f
--- /dev/null
+++ b/Resources/doc/experimental-storage.md
@@ -0,0 +1,70 @@
+# Experimental Content Bundle Storage
+
+For the **experimental** storage the articles are stored using the [SuluContentBundle](https://github.com/sulu/sulucontentbundle).
+
+## Installation
+
+To use the experimental storage you need to have the [SuluContentBundle](https://github.com/sulu/sulucontentbundle) installed.
+
+```bash
+composer require sulu/content-bundle
+```
+
+Then you can configure it:
+
+```yaml
+sulu_article:
+ article:
+ storage: experimental
+```
+
+## Configuration
+
+The following is showing the full configuration of the **experimental** article module:
+
+```yaml
+sulu_product:
+ article:
+ storage: experimental
+
+ # optional
+ objects:
+ article:
+ model: 'Sulu\Bundle\ArticleBundle\Article\Domain\Model\Article'
+```
+
+## Override Entities
+
+### Override Article Entity
+
+```php
+addCompilerPass(new ConverterCompilerPass());
+ $container->addCompilerPass($this);
$container->addCompilerPass(new StructureValidatorCompilerPass(), PassConfig::TYPE_AFTER_REMOVING);
- $container->addCompilerPass(new RouteEnhancerCompilerPass());
+ }
+
+ public function process(ContainerBuilder $container): void
+ {
+ $storage = $container->getParameter('sulu_article.article_storage');
+
+ $compilerPasses = [];
+
+ if (Configuration::ARTICLE_STORAGE_PHPCR === $storage) {
+ $compilerPasses = $this->getPHPCRStorageCompilerPasses($container);
+ } elseif (Configuration::ARTICLE_STORAGE_EXPERIMENTAL === $storage) {
+ $compilerPasses = $this->getExperimentalStorageCompilerPasses($container);
+ }
+
+ foreach ($compilerPasses as $compilerPass) {
+ $compilerPass->process($container);
+ }
+ }
+
+ /**
+ * @return CompilerPassInterface[]
+ */
+ private function getExperimentalStorageCompilerPasses(ContainerBuilder $container): array
+ {
+ return [
+ new ResolveTargetEntitiesPass([
+ ArticleInterface::class => 'sulu.model.article.class',
+ ]),
+ ];
+ }
+
+ /**
+ * @return compilerPassInterface[]
+ *
+ * Can be removed when phpcr storage is removed
+ */
+ private function getPHPCRStorageCompilerPasses(ContainerBuilder $container): array
+ {
+ return [
+ new RouteEnhancerCompilerPass(),
+ new ConverterCompilerPass(),
+ ];
}
}
diff --git a/Tests/Application/Kernel.php b/Tests/Application/Kernel.php
index 2cec8f994..4e1d3efcb 100644
--- a/Tests/Application/Kernel.php
+++ b/Tests/Application/Kernel.php
@@ -16,6 +16,7 @@
use Sulu\Bundle\ArticleBundle\Tests\Application\Testing\ArticleBundleKernelBrowser;
use Sulu\Bundle\ArticleBundle\Tests\TestExtendBundle\TestExtendBundle;
use Sulu\Bundle\TestBundle\Kernel\SuluTestKernel;
+use Sulu\Component\HttpKernel\SuluKernel;
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
@@ -25,6 +26,20 @@
*/
class Kernel extends SuluTestKernel implements CompilerPassInterface
{
+ /**
+ * @var string|null
+ */
+ private $config = 'phpcr_storage';
+
+ public function __construct(string $environment, bool $debug, string $suluContext = SuluKernel::CONTEXT_ADMIN)
+ {
+ $environmentParts = explode('_', $environment, 2);
+ $environment = $environmentParts[0];
+ $this->config = $environmentParts[1] ?? $this->config;
+
+ parent::__construct($environment, $debug, $suluContext);
+ }
+
/**
* {@inheritdoc}
*/
@@ -32,7 +47,10 @@ public function registerBundles()
{
$bundles = parent::registerBundles();
$bundles[] = new SuluArticleBundle();
- $bundles[] = new ONGRElasticsearchBundle();
+
+ if ('phpcr_storage' === $this->config) {
+ $bundles[] = new ONGRElasticsearchBundle();
+ }
if ('extend' === getenv('ARTICLE_TEST_CASE')) {
$bundles[] = new TestExtendBundle();
@@ -53,6 +71,8 @@ public function registerContainerConfiguration(LoaderInterface $loader)
}
$loader->load(__DIR__ . '/config/config.yml');
+ $loader->load(__DIR__ . '/config/config_' . $this->config . '.yml');
+
$type = 'default';
if (getenv('ARTICLE_TEST_CASE')) {
$type = getenv('ARTICLE_TEST_CASE');
diff --git a/Tests/Application/config/config.yml b/Tests/Application/config/config.yml
index 684f6ef6b..cd3e3c3bc 100644
--- a/Tests/Application/config/config.yml
+++ b/Tests/Application/config/config.yml
@@ -1,20 +1,5 @@
# Doctrine Configuration
doctrine:
- dbal:
- driver: pdo_mysql
- host: 127.0.0.1
- port: 3306
- dbname: su_articles_test
- user: root
- password:
- server_version: '5.7'
- url: '%env(DATABASE_URL)%'
-
- charset: '%env(DATABASE_CHARSET)%'
- default_table_options:
- charset: '%env(DATABASE_CHARSET)%'
- collate: '%env(DATABASE_COLLATE)%'
-
orm:
mappings:
gedmo_tree:
@@ -23,30 +8,3 @@ doctrine:
dir: "%gedmo_directory%/Tree/Entity"
alias: GedmoTree
is_bundle: false
-
-# Sulu Routing
-sulu_route:
- mappings:
- Sulu\Bundle\ArticleBundle\Document\ArticleDocument:
- generator: "schema"
- options:
- route_schema: "/articles/{object.getTitle()}"
- Sulu\Bundle\ArticleBundle\Document\ArticlePageDocument:
- generator: "article_page"
- options:
- route_schema: "/{translator.trans(\"page\")}-{object.getPageNumber()}"
- parent: "{object.getParent().getRoutePath()}"
-
-sulu_article:
- index_name: "su_articles_tests"
- hosts: ["%env(ELASTICSEARCH_HOST)%"]
- default_main_webspace: 'sulu_io'
-
-ongr_elasticsearch:
- analysis:
- tokenizer:
- pathTokenizer:
- type: path_hierarchy
- analyzer:
- pathAnalyzer:
- tokenizer: pathTokenizer
diff --git a/Tests/Application/config/config_experimental_storage.yml b/Tests/Application/config/config_experimental_storage.yml
new file mode 100644
index 000000000..fbc84c7d4
--- /dev/null
+++ b/Tests/Application/config/config_experimental_storage.yml
@@ -0,0 +1,4 @@
+sulu_article:
+ article:
+ storage: 'experimental'
+ default_main_webspace: 'sulu_io'
diff --git a/Tests/Application/config/config_phpcr_storage.yml b/Tests/Application/config/config_phpcr_storage.yml
new file mode 100644
index 000000000..72b470ecf
--- /dev/null
+++ b/Tests/Application/config/config_phpcr_storage.yml
@@ -0,0 +1,27 @@
+sulu_route:
+ mappings:
+ Sulu\Bundle\ArticleBundle\Document\ArticleDocument:
+ generator: "schema"
+ options:
+ route_schema: "/articles/{object.getTitle()}"
+ Sulu\Bundle\ArticleBundle\Document\ArticlePageDocument:
+ generator: "article_page"
+ options:
+ route_schema: "/{translator.trans(\"page\")}-{object.getPageNumber()}"
+ parent: "{object.getParent().getRoutePath()}"
+
+sulu_article:
+ article:
+ storage: 'phpcr'
+ index_name: "su_articles_tests"
+ hosts: ["%env(ELASTICSEARCH_HOST)%"]
+ default_main_webspace: 'sulu_io'
+
+ongr_elasticsearch:
+ analysis:
+ tokenizer:
+ pathTokenizer:
+ type: path_hierarchy
+ analyzer:
+ pathAnalyzer:
+ tokenizer: pathTokenizer
diff --git a/Tests/Unit/Article/Domain/Model/ArticleTest.php b/Tests/Unit/Article/Domain/Model/ArticleTest.php
new file mode 100644
index 000000000..9aaa6292b
--- /dev/null
+++ b/Tests/Unit/Article/Domain/Model/ArticleTest.php
@@ -0,0 +1,40 @@
+createArticle();
+
+ $this->assertNotNull($article->getId());
+ }
+
+ public function testGetIdCustom()
+ {
+ $article = $this->createArticle(['id' => '9dd3f8c6-f000-4a37-a780-fe8c3128526d']);
+
+ $this->assertSame('9dd3f8c6-f000-4a37-a780-fe8c3128526d', $article->getId());
+ }
+
+ private function createArticle(array $data = []): ArticleInterface
+ {
+ return new Article(
+ $data['id'] ?? null
+ );
+ }
+}
diff --git a/UPGRADE.md b/UPGRADE.md
index cbf07a792..92c4150af 100644
--- a/UPGRADE.md
+++ b/UPGRADE.md
@@ -1,5 +1,16 @@
# Upgrade
+## 2.x
+
+### Elasticsearch Bundle need to be required
+
+The SuluArticleBundle defines not longer its dependency to `handcraftedinthealps/elasticsearch-bundle` because
+of the new `experimental` storage. If you update you need to require the bundle in your `composer.json`.
+
+```bash
+composer require "handcraftedinthealps/elasticsearch-bundle:^5.2"
+```
+
## 2.2.0
### Index mapping changed
diff --git a/composer.json b/composer.json
index e89318b1a..686a6ff56 100644
--- a/composer.json
+++ b/composer.json
@@ -20,12 +20,14 @@
"require": {
"php": "^7.2 || ^8.0",
"ext-json": "*",
- "elasticsearch/elasticsearch": "^5.0 || ^6.0 || ^7.0",
- "handcraftedinthealps/elasticsearch-bundle": "^5.2.6.4",
- "handcraftedinthealps/elasticsearch-dsl": "^5.0.7.1 || ^6.2.0.1 || ^7.2.0.1",
+ "doctrine/collections": "^1.0",
+ "doctrine/orm": "^2.5.3",
+ "doctrine/doctrine-bundle": "^1.10 || ^2.0",
+ "doctrine/persistence": "^1.3 || ^2.0",
"jms/serializer": "^3.3",
"jms/serializer-bundle": "^3.3",
- "sulu/sulu": "^2.0.10 || ^2.1@dev",
+ "ramsey/uuid": "^3.1 || ^4.0",
+ "sulu/sulu": "^2.1.1 || ^2.3@dev",
"symfony/config": "^4.3 || ^5.0",
"symfony/dependency-injection": "^4.3 || ^5.0",
"symfony/http-foundation": "^4.3 || ^5.0",
@@ -34,8 +36,11 @@
"twig/twig": "^1.41 || ^2.0 || ^3.0"
},
"require-dev": {
- "doctrine/data-fixtures": "^1.1",
+ "doctrine/data-fixtures": "^1.3.3",
+ "elasticsearch/elasticsearch": "^5.0 || ^6.0 || ^7.0",
"friendsofphp/php-cs-fixer": "^2.17",
+ "handcraftedinthealps/elasticsearch-bundle": "^5.2.6.4",
+ "handcraftedinthealps/elasticsearch-dsl": "^5.0.7.1 || ^6.2.0.1 || ^7.2.0.1",
"handcraftedinthealps/zendsearch": "^2.0",
"jackalope/jackalope-doctrine-dbal": "^1.3.4",
"jackalope/jackalope-jackrabbit": "^1.3",
@@ -46,14 +51,23 @@
"phpstan/phpstan-symfony": "^0.12.3",
"phpunit/phpunit": "^8.2",
"sulu/automation-bundle": "^2.0@dev",
+ "sulu/content-bundle": "^0.6.1",
"symfony/browser-kit": "^4.3 || ^5.0",
"symfony/dotenv": "^4.3 || ^5.0",
"symfony/monolog-bundle": "^3.1",
"symfony/stopwatch": "^4.3 || ^5.0",
"thecodingmachine/phpstan-strict-rules": "^0.12.0"
},
+ "conflict": {
+ "elasticsearch/elasticsearch": "<5.0 || >=8.0",
+ "handcraftedinthealps/elasticsearch-bundle": "<5.2.6.4 || >=6.0",
+ "handcraftedinthealps/elasticsearch-dsl": "<5.0.7.1 || 6.0 - 6.2.0 || 7.0 - 7.2.0 || >=8.0"
+ },
"suggest": {
- "sulu/automation-bundle": "Allows to outsource long-running route update processes."
+ "elasticsearch/elasticsearch": "Required for the default article phpcr storage.",
+ "handcraftedinthealps/elasticsearch-bundle": "Required for the default article phpcr storage.",
+ "sulu/automation-bundle": "Allows publish automation and outsource long-running route update processes.",
+ "sulu/content-bundle": "Allows to use the experimental article storage."
},
"autoload": {
"psr-4": {