forked from biblioverse/biblioteca
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
17 changed files
with
745 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
53 changes: 53 additions & 0 deletions
53
BibliotecaTypesenseBundle/src/BibliotecaTypesenseBundle.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
<?php | ||
|
||
namespace Biblioteca\TypesenseBundle; | ||
|
||
use Biblioteca\TypesenseBundle\Mapper\MapperInterface; | ||
use Symfony\Component\Config\Definition\Configurator\DefinitionConfigurator; | ||
use Symfony\Component\DependencyInjection\ContainerBuilder; | ||
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; | ||
use Symfony\Component\HttpKernel\Bundle\AbstractBundle; | ||
|
||
class BibliotecaTypesenseBundle extends AbstractBundle | ||
{ | ||
public function configure(DefinitionConfigurator $definition): void | ||
{ | ||
$definition->rootNode() | ||
->children() | ||
->arrayNode('typesense') | ||
->info('Typesense server configuration') | ||
->isRequired() | ||
->children() | ||
->scalarNode('uri') | ||
->info('The URL of the Typesense server') | ||
->isRequired() | ||
->cannotBeEmpty() | ||
->end() | ||
->scalarNode('key') | ||
->info('The API key for accessing the Typesense server') | ||
->isRequired() | ||
->cannotBeEmpty() | ||
->end() | ||
->scalarNode('connection_timeout_seconds') | ||
->defaultValue(5) | ||
->cannotBeEmpty() | ||
->end() | ||
->end() | ||
->end() | ||
->end(); | ||
} | ||
|
||
public function loadExtension(array $config, ContainerConfigurator $container, ContainerBuilder $builder): void | ||
{ | ||
foreach ($config['typesense'] as $key => $value) { | ||
$container->parameters()->set('biblioteca_typesense.config.'.$key, $value); | ||
} | ||
|
||
$container->services() | ||
->instanceof(MapperInterface::class) | ||
->tag('typesense.mapper') | ||
->autowire(); | ||
|
||
$container->import(__DIR__.'/Resources/config/services.yaml'); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
<?php | ||
|
||
namespace Biblioteca\TypesenseBundle\Client; | ||
|
||
use Typesense\Aliases; | ||
use Typesense\Analytics; | ||
use Typesense\Client; | ||
use Typesense\Collections; | ||
use Typesense\Debug; | ||
use Typesense\Health; | ||
use Typesense\Keys; | ||
use Typesense\Metrics; | ||
use Typesense\MultiSearch; | ||
use Typesense\Operations; | ||
use Typesense\Presets; | ||
|
||
class ClientAdapter implements ClientInterface | ||
{ | ||
public function __construct( | ||
private readonly Client $client, | ||
) { | ||
} | ||
|
||
public function __call($name, $arguments) | ||
{ | ||
return $this->client->$name(...$arguments); | ||
} | ||
|
||
public function getCollections(): Collections | ||
{ | ||
return $this->client->getCollections(); | ||
} | ||
|
||
public function getAliases(): Aliases | ||
{ | ||
return $this->client->getAliases(); | ||
} | ||
|
||
public function getKeys(): Keys | ||
{ | ||
return $this->client->getKeys(); | ||
} | ||
|
||
public function getDebug(): Debug | ||
{ | ||
return $this->client->getDebug(); | ||
} | ||
|
||
public function getMetrics(): Metrics | ||
{ | ||
return $this->client->getMetrics(); | ||
} | ||
|
||
public function getHealth(): Health | ||
{ | ||
return $this->client->getHealth(); | ||
} | ||
|
||
public function getOperations(): Operations | ||
{ | ||
return $this->client->getOperations(); | ||
} | ||
|
||
public function getMultiSearch(): MultiSearch | ||
{ | ||
return $this->client->getMultiSearch(); | ||
} | ||
|
||
public function getPresets(): Presets | ||
{ | ||
return $this->client->getPresets(); | ||
} | ||
|
||
public function getAnalytics(): Analytics | ||
{ | ||
return $this->client->getAnalytics(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
<?php | ||
|
||
namespace Biblioteca\TypesenseBundle\Client; | ||
|
||
use Typesense\Client; | ||
use Typesense\Exceptions\ConfigError; | ||
|
||
class ClientFactory | ||
{ | ||
public function __construct( | ||
private readonly string $uri, | ||
#[\SensitiveParameter] private readonly string $apiKey, | ||
private readonly int $connectionTimeoutSeconds = 5, | ||
) { | ||
} | ||
|
||
/** | ||
* @throws ConfigError | ||
*/ | ||
public function __invoke(): ClientInterface | ||
{ | ||
return new ClientAdapter(new Client($this->getConfiguration())); | ||
} | ||
|
||
private function getConfiguration(): array | ||
{ | ||
$urlParsed = parse_url($this->uri); | ||
if ($urlParsed === false) { | ||
throw new \InvalidArgumentException('Invalid URI'); | ||
} | ||
|
||
return [ | ||
'nodes' => [ | ||
[ | ||
'host' => $urlParsed['host'], | ||
'port' => $urlParsed['port'], | ||
'protocol' => $urlParsed['scheme'], | ||
], | ||
], | ||
'api_key' => $this->apiKey, | ||
'connection_timeout_seconds' => $this->connectionTimeoutSeconds, | ||
]; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
<?php | ||
|
||
namespace Biblioteca\TypesenseBundle\Client; | ||
|
||
use Typesense\Aliases; | ||
use Typesense\Analytics; | ||
use Typesense\Collections; | ||
use Typesense\Debug; | ||
use Typesense\Health; | ||
use Typesense\Keys; | ||
use Typesense\Metrics; | ||
use Typesense\MultiSearch; | ||
use Typesense\Operations; | ||
use Typesense\Presets; | ||
|
||
interface ClientInterface | ||
{ | ||
public function getCollections(): Collections; | ||
|
||
public function getAliases(): Aliases; | ||
|
||
public function getKeys(): Keys; | ||
|
||
public function getDebug(): Debug; | ||
|
||
public function getMetrics(): Metrics; | ||
|
||
public function getHealth(): Health; | ||
|
||
public function getOperations(): Operations; | ||
|
||
public function getMultiSearch(): MultiSearch; | ||
|
||
public function getPresets(): Presets; | ||
|
||
public function getAnalytics(): Analytics; | ||
} |
66 changes: 66 additions & 0 deletions
66
BibliotecaTypesenseBundle/src/Command/TypesensePopulateCommand.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
<?php | ||
|
||
namespace Biblioteca\TypesenseBundle\Command; | ||
|
||
use Biblioteca\TypesenseBundle\Mapper\MapperInterface; | ||
use Biblioteca\TypesenseBundle\Mapper\MapperLocator; | ||
use Biblioteca\TypesenseBundle\PopulateService; | ||
use Symfony\Component\Console\Attribute\AsCommand; | ||
use Symfony\Component\Console\Command\Command; | ||
use Symfony\Component\Console\Helper\ProgressBar; | ||
use Symfony\Component\Console\Input\InputInterface; | ||
use Symfony\Component\Console\Output\OutputInterface; | ||
use Symfony\Component\Console\Style\SymfonyStyle; | ||
|
||
#[AsCommand( | ||
name: 'biblioteca:typesense:populate', | ||
description: 'Populate Typesense collections', | ||
)] | ||
class TypesensePopulateCommand extends Command | ||
{ | ||
public function __construct( | ||
private PopulateService $populateService, | ||
private MapperLocator $mapperLocator, | ||
) { | ||
parent::__construct(); | ||
} | ||
|
||
protected function configure(): void | ||
{ | ||
} | ||
|
||
protected function execute(InputInterface $input, OutputInterface $output): int | ||
{ | ||
$io = new SymfonyStyle($input, $output); | ||
|
||
$count = $this->mapperLocator->count(); | ||
if ($count === 0) { | ||
$io->warning('No mappers found. Declare at least one service implementing '.MapperInterface::class); | ||
|
||
return Command::SUCCESS; | ||
} | ||
|
||
$progress = new ProgressBar($output, 0); | ||
|
||
foreach ($this->mapperLocator->getMappers() as $mapper) { | ||
$name = $mapper->getMapping()->getName(); | ||
$io->writeln('Deleting collection '.$name); | ||
$this->populateService->deleteCollection($mapper); | ||
|
||
$io->writeln('Creating collection '.$name); | ||
$this->populateService->createCollection($mapper); | ||
|
||
$io->writeln('Filling collection '.$name); | ||
$progress->start($mapper->getDataCount()); | ||
foreach ($this->populateService->fillCollection($mapper) as $_) { | ||
$progress->advance(); | ||
} | ||
$progress->clear(); | ||
} | ||
$progress->finish(); | ||
|
||
$io->success('Finished'); | ||
|
||
return Command::SUCCESS; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
<?php | ||
|
||
namespace Biblioteca\TypesenseBundle\Mapper; | ||
|
||
interface MapperInterface | ||
{ | ||
public function getMapping(): Mapping; | ||
|
||
/** | ||
* @return \generator<array<string, mixed>> | ||
*/ | ||
public function getData(): \generator; | ||
|
||
public function getDataCount(): ?int; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
<?php | ||
|
||
namespace Biblioteca\TypesenseBundle\Mapper; | ||
|
||
class MapperLocator | ||
{ | ||
/** | ||
* @param iterable<MapperInterface> $mappers | ||
*/ | ||
public function __construct(private iterable $mappers) | ||
{ | ||
} | ||
|
||
/** | ||
* @return \generator<MapperInterface> | ||
*/ | ||
public function getMappers(): \Generator | ||
{ | ||
foreach ($this->mappers as $mapper) { | ||
yield $mapper; | ||
} | ||
} | ||
|
||
public function addMapper(MapperInterface $mapper): void | ||
{ | ||
$this->mappers[] = $mapper; | ||
} | ||
|
||
public function count(): int | ||
{ | ||
return count($this->mappers); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
<?php | ||
|
||
namespace Biblioteca\TypesenseBundle\Mapper; | ||
|
||
use Symfony\Component\OptionsResolver\OptionsResolver; | ||
|
||
class Mapping | ||
{ | ||
public function __construct(private string $name, private array $fields = []) | ||
{ | ||
} | ||
|
||
public function getFields(): array | ||
{ | ||
return $this->fields; | ||
} | ||
|
||
public function setField(string $name, array $options): self | ||
{ | ||
$optionResolver = new OptionsResolver(); | ||
$optionResolver->setRequired(['name', 'type']); | ||
$optionResolver->setDefined(['facet', 'optional']); | ||
|
||
$data = $optionResolver->resolve($options); | ||
unset($data['optional']); | ||
$this->fields[$name] = $data; | ||
|
||
return $this; | ||
} | ||
|
||
public function getName(): string | ||
{ | ||
return $this->name; | ||
} | ||
|
||
public function getCollectionOptions(): array | ||
{ | ||
return []; | ||
} | ||
} |
Oops, something went wrong.