Skip to content

Commit 67fab73

Browse files
authored
Merge pull request acseo#65 from acseo/feature/collection-prefix
allow tu prefix collection
2 parents f4d1475 + f5cd856 commit 67fab73

File tree

9 files changed

+221
-10
lines changed

9 files changed

+221
-10
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ acseo_typesense:
4646
typesense:
4747
url: '%env(resolve:TYPESENSE_URL)%'
4848
key: '%env(resolve:TYPESENSE_KEY)%'
49+
collection_prefix: 'test_' # Optional : add prefix to all collection
50+
# names in Typesense
4951
# Collection settings
5052
collections:
5153
books: # Typesense collection name

composer.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@
2121
},
2222
"require-dev": {
2323
"symfony/phpunit-bridge": "^5.0|^6.0",
24-
"phpunit/phpunit": "^9.5"
24+
"phpunit/phpunit": "^9.5",
25+
"symfony/yaml": "^3.4 || ^4.4 || ^5.4 || ^6.0"
2526
},
2627
"autoload": {
2728
"psr-4": { "ACSEO\\TypesenseBundle\\": "src/" }
@@ -34,7 +35,7 @@
3435
"scripts": {
3536
"typesenseServer": [
3637
"Composer\\Config::disableProcessTimeout",
37-
"docker run -i -p 8108:8108 -v/tmp/typesense-server-data-1c/:/data typesense/typesense:0.22.0 --data-dir /data --api-key=123 --listen-port 8108 --enable-cors"
38+
"docker run -i -p 8108:8108 -v/tmp/typesense-server-data-1c/:/data typesense/typesense:0.23.0 --data-dir /data --api-key=123 --listen-port 8108 --enable-cors"
3839
]
3940
}
4041
}

src/Command/CreateCommand.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,16 @@ protected function execute(InputInterface $input, OutputInterface $output): int
3434
$defs = $this->collectionManager->getCollectionDefinitions();
3535

3636
foreach ($defs as $name => $def) {
37+
$name = $def['name'];
38+
$typesenseName = $def['typesense_name'];
3739
try {
38-
$output->writeln(sprintf('<info>Deleting</info> <comment>%s</comment>', $name));
40+
$output->writeln(sprintf('<info>Deleting</info> <comment>%s</comment> (<comment>%s</comment> in Typesense)', $name, $typesenseName));
3941
$this->collectionManager->deleteCollection($name);
4042
} catch (\Typesense\Exceptions\ObjectNotFound $exception) {
41-
$output->writeln(sprintf('<comment>%s</comment> <info>does not exists</info> ', $name));
43+
$output->writeln(sprintf('Collection <comment>%s</comment> <info>does not exists</info> ', $typesenseName));
4244
}
4345

44-
$output->writeln(sprintf('<info>Creating</info> <comment>%s</comment>', $name));
46+
$output->writeln(sprintf('<info>Creating</info> <comment>%s</comment> (<comment>%s</comment> in Typesense)', $name, $typesenseName));
4547
$this->collectionManager->createCollection($name);
4648
}
4749

src/DependencyInjection/ACSEOTypesenseExtension.php

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,13 @@ class ACSEOTypesenseExtension extends Extension
2727
*/
2828
private $findersConfig = [];
2929

30+
/**
31+
* An array of parameters to use as configured by the extension.
32+
*
33+
* @var array
34+
*/
35+
private $parameters = [];
36+
3037
public function load(array $configs, ContainerBuilder $container)
3138
{
3239
$configuration = new Configuration();
@@ -70,6 +77,8 @@ private function loadClient($config, ContainerBuilder $container)
7077
$clientDef->replaceArgument(0, $config['url']);
7178
$clientDef->replaceArgument(1, $config['key']);
7279
$container->setDefinition($clientId, $clientDef);
80+
81+
$this->parameters['collection_prefix'] = $config['collection_prefix'] ?? '';
7382
}
7483

7584
/**
@@ -83,7 +92,7 @@ private function loadClient($config, ContainerBuilder $container)
8392
private function loadCollections(array $collections, ContainerBuilder $container)
8493
{
8594
foreach ($collections as $name => $config) {
86-
$collectionName = $config['collection_name'] ?? $name;
95+
$collectionName = $this->parameters['collection_prefix'] . ($config['collection_name'] ?? $name);
8796

8897
$primaryKeyExists = false;
8998

@@ -112,8 +121,9 @@ private function loadCollections(array $collections, ContainerBuilder $container
112121

113122
if (isset($config['finders'])) {
114123
foreach ($config['finders'] as $finderName => $finderConfig) {
115-
$finderName = $collectionName.'.'.$finderName;
124+
$finderName = $name.'.'.$finderName;
116125
$finderConfig['collection_name'] = $collectionName;
126+
$finderConfig['name'] = $name;
117127
$finderConfig['finder_name'] = $finderName;
118128
if (!isset($finderConfig['finder_parameters']['query_by'])) {
119129
throw new \Exception('acseo_typesense.collections.'.$finderName.'.finder_parameters.query_by must be set');
@@ -158,9 +168,10 @@ private function loadTransformer(ContainerBuilder $container)
158168
private function loadCollectionsFinder(ContainerBuilder $container)
159169
{
160170
foreach ($this->collectionsConfig as $name => $config) {
161-
$collectionName = $config['typesense_name'];
171+
$collectionName = $config['name'];
162172

163173
$finderId = sprintf('typesense.finder.%s', $collectionName);
174+
$finderId = sprintf('typesense.finder.%s', $name);
164175
$finderDef = new ChildDefinition('typesense.finder');
165176
$finderDef->replaceArgument(2, $config);
166177

@@ -175,7 +186,7 @@ private function loadFinderServices(ContainerBuilder $container)
175186
{
176187
foreach ($this->findersConfig as $name => $config) {
177188
$finderName = $config['finder_name'];
178-
$collectionName = $config['collection_name'];
189+
$collectionName = $config['name'];
179190
$finderId = sprintf('typesense.finder.%s', $collectionName);
180191

181192
if (isset($config['finder_service'])) {

src/DependencyInjection/Configuration.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,15 @@ public function getConfigTreeBuilder(): TreeBuilder
2121
->children()
2222
->scalarNode('url')->isRequired()->cannotBeEmpty()->end()
2323
->scalarNode('key')->isRequired()->cannotBeEmpty()->end()
24+
->scalarNode('collection_prefix')->end()
2425
->end()
2526
->end()
2627
->arrayNode('collections')
2728
->info('Collection definition')
2829
->useAttributeAsKey('name')
2930
->arrayPrototype()
3031
->children()
32+
->scalarNode('collection_name')->end()
3133
->scalarNode('entity')->end()
3234
->arrayNode('fields')
3335
->arrayPrototype()

src/Manager/CollectionManager.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ public function getManagedClassNames()
2929
{
3030
$managedClassNames = [];
3131
foreach ($this->collectionDefinitions as $name => $collectionDefinition) {
32-
$managedClassNames[$name] = $collectionDefinition['entity'];
32+
$collectionName = $collectionDefinition['typesense_name'] ?? $name;
33+
$managedClassNames[$collectionName] = $collectionDefinition['entity'];
3334
}
3435

3536
return $managedClassNames;
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace ACSEO\Bundle\TypesenseBundle\Tests\Unit\DependencyInjection;
6+
7+
8+
use ACSEO\TypesenseBundle\DependencyInjection\ACSEOTypesenseExtension;
9+
// use FOS\ElasticaBundle\Doctrine\MongoDBPagerProvider;
10+
// use FOS\ElasticaBundle\Doctrine\ORMPagerProvider;
11+
// use FOS\ElasticaBundle\Doctrine\PHPCRPagerProvider;
12+
// use FOS\ElasticaBundle\Doctrine\RegisterListenersService;
13+
// use FOS\ElasticaBundle\Persister\InPlacePagerPersister;
14+
// use FOS\ElasticaBundle\Persister\Listener\FilterObjectsListener;
15+
// use FOS\ElasticaBundle\Persister\PagerPersisterRegistry;
16+
use PHPUnit\Framework\TestCase;
17+
use Symfony\Component\Config\FileLocator;
18+
// use Symfony\Component\DependencyInjection\ChildDefinition;
19+
use Symfony\Component\DependencyInjection\ContainerBuilder;
20+
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
21+
// use Symfony\Component\DependencyInjection\Reference;
22+
use Symfony\Component\Yaml\Yaml;
23+
24+
/**
25+
* @internal
26+
*/
27+
class ACSEOTypesenseExtensionTest extends TestCase
28+
{
29+
30+
public function testTypesenseClientDefinition()
31+
{
32+
$containerBuilder = new ContainerBuilder();
33+
$containerBuilder->registerExtension($extension = new ACSEOTypesenseExtension());
34+
$containerBuilder->setParameter('kernel.debug', true);
35+
36+
$loader = new YamlFileLoader($containerBuilder, new FileLocator(__DIR__.'/fixtures'));
37+
$loader->load('acseo_typesense.yml');
38+
39+
$extensionConfig = $containerBuilder->getExtensionConfig($extension->getAlias());
40+
$extension->load($extensionConfig, $containerBuilder);
41+
42+
$this->assertTrue($containerBuilder->hasDefinition('typesense.client'));
43+
44+
$clientDefinition = $containerBuilder->findDefinition('typesense.client');
45+
46+
$this->assertSame('http://localhost:8108', $clientDefinition->getArgument(0));
47+
$this->assertSame('ACSEO', $clientDefinition->getArgument(1));
48+
}
49+
50+
public function testFinderServiceDefinition()
51+
{
52+
$containerBuilder = new ContainerBuilder();
53+
$containerBuilder->registerExtension($extension = new ACSEOTypesenseExtension());
54+
$containerBuilder->setParameter('kernel.debug', true);
55+
56+
$loader = new YamlFileLoader($containerBuilder, new FileLocator(__DIR__.'/fixtures'));
57+
$loader->load('acseo_typesense.yml');
58+
59+
$extensionConfig = $containerBuilder->getExtensionConfig($extension->getAlias());
60+
$extension->load($extensionConfig, $containerBuilder);
61+
62+
$this->assertTrue($containerBuilder->hasDefinition('typesense.finder'));
63+
$this->assertTrue($containerBuilder->hasDefinition('typesense.finder.books'));
64+
65+
$finderBooksDefinition = $containerBuilder->findDefinition('typesense.finder.books');
66+
$finderBooksDefinitionArguments = $finderBooksDefinition->getArguments();
67+
$arguments = array_pop($finderBooksDefinitionArguments);
68+
69+
$this->assertSame('books', $arguments['typesense_name']);
70+
$this->assertSame('books', $arguments['name']);
71+
}
72+
73+
public function testFinderServiceDefinitionWithCollectionPrefix()
74+
{
75+
$containerBuilder = new ContainerBuilder();
76+
$containerBuilder->registerExtension($extension = new ACSEOTypesenseExtension());
77+
$containerBuilder->setParameter('kernel.debug', true);
78+
79+
$loader = new YamlFileLoader($containerBuilder, new FileLocator(__DIR__.'/fixtures'));
80+
$loader->load('acseo_typesense_collection_prefix.yml');
81+
82+
$extensionConfig = $containerBuilder->getExtensionConfig($extension->getAlias());
83+
$extension->load($extensionConfig, $containerBuilder);
84+
85+
$this->assertTrue($containerBuilder->hasDefinition('typesense.finder'));
86+
$this->assertTrue($containerBuilder->hasDefinition('typesense.finder.books'));
87+
88+
$finderBooksDefinition = $containerBuilder->findDefinition('typesense.finder.books');
89+
$finderBooksDefinitionArguments = $finderBooksDefinition->getArguments();
90+
$arguments = array_pop($finderBooksDefinitionArguments);
91+
92+
$this->assertSame('acseo_prefix_books', $arguments['typesense_name']);
93+
$this->assertSame('books', $arguments['name']);
94+
}
95+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
acseo_typesense:
2+
typesense:
3+
url: 'http://localhost:8108'
4+
key: 'ACSEO'
5+
collections:
6+
# Collection settings
7+
books: # Typesense collection name
8+
entity: 'App\Entity\Book' # Doctrine Entity class
9+
collection_name: 'books'
10+
fields:
11+
#
12+
# Keeping Database and Typesense synchronized with ids
13+
#
14+
id: # Entity attribute name
15+
name: id # Typesense attribute name
16+
type: primary # Attribute type
17+
#
18+
# Using again id as a sortable field (int32 required)
19+
#
20+
sortable_id:
21+
entity_attribute: id # Entity attribute name forced
22+
name: sortable_id # Typesense field name
23+
type: int32
24+
title:
25+
name: title
26+
type: string
27+
author:
28+
name: author
29+
type: object # Object conversion with __toString()
30+
author.country:
31+
name: author_country
32+
type: string
33+
facet: true # Declare field as facet (required to use "group_by" query option)
34+
entity_attribute: author.country # Equivalent of $book->getAuthor()->getCountry()
35+
genres:
36+
name: genres
37+
type: collection # Convert ArrayCollection to array of strings
38+
publishedAt:
39+
name: publishedAt
40+
type: datetime
41+
optional: true # Declare field as optional
42+
default_sorting_field: sortable_id # Default sorting field. Must be int32 or float
43+
finders:
44+
title_or_author:
45+
finder_parameters:
46+
query_by : 'title,author'
47+
limit: 10
48+
num_typos: 2
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
acseo_typesense:
2+
typesense:
3+
url: 'http://localhost:8108'
4+
key: 'ACSEO'
5+
collection_prefix: 'acseo_prefix_'
6+
collections:
7+
# Collection settings
8+
books: # Typesense collection name
9+
entity: 'App\Entity\Book' # Doctrine Entity class
10+
collection_name: 'books'
11+
fields:
12+
#
13+
# Keeping Database and Typesense synchronized with ids
14+
#
15+
id: # Entity attribute name
16+
name: id # Typesense attribute name
17+
type: primary # Attribute type
18+
#
19+
# Using again id as a sortable field (int32 required)
20+
#
21+
sortable_id:
22+
entity_attribute: id # Entity attribute name forced
23+
name: sortable_id # Typesense field name
24+
type: int32
25+
title:
26+
name: title
27+
type: string
28+
author:
29+
name: author
30+
type: object # Object conversion with __toString()
31+
author.country:
32+
name: author_country
33+
type: string
34+
facet: true # Declare field as facet (required to use "group_by" query option)
35+
entity_attribute: author.country # Equivalent of $book->getAuthor()->getCountry()
36+
genres:
37+
name: genres
38+
type: collection # Convert ArrayCollection to array of strings
39+
publishedAt:
40+
name: publishedAt
41+
type: datetime
42+
optional: true # Declare field as optional
43+
default_sorting_field: sortable_id # Default sorting field. Must be int32 or float
44+
finders:
45+
title_or_author:
46+
finder_parameters:
47+
query_by : 'title,author'
48+
limit: 10
49+
num_typos: 2

0 commit comments

Comments
 (0)