Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
91.18% covered (success)
91.18%
31 / 34
50.00% covered (danger)
50.00%
3 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
IndexTemplateBuilder
91.18% covered (success)
91.18%
31 / 34
50.00% covered (danger)
50.00%
3 / 6
9.06
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
1
 build
85.71% covered (warning)
85.71%
6 / 7
0.00% covered (danger)
0.00%
0 / 1
2.01
 execute
92.31% covered (success)
92.31%
12 / 13
0.00% covered (danger)
0.00%
0 / 1
3.00
 getTemplateName
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getSearchConfig
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 createIndexTemplate
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace CirrusSearch\Maintenance;
4
5use CirrusSearch\Connection;
6use Elastica\IndexTemplate;
7use Wikimedia\Assert\Assert;
8
9class IndexTemplateBuilder {
10    /**
11     * @var array
12     */
13    private $templateDefinition;
14
15    /**
16     * @var string
17     */
18    private $templateName;
19
20    /**
21     * @var string[]
22     */
23    private $availablePlugins;
24
25    /**
26     * @var Connection
27     */
28    private $connection;
29
30    /**
31     * @var string
32     */
33    private $languageCode;
34
35    /**
36     * @param Connection $connection
37     * @param string $templateName
38     * @param array $templateDefinition
39     * @param string[] $availablePlugins
40     * @param string $languageCode
41     */
42    public function __construct(
43        Connection $connection,
44        $templateName,
45        array $templateDefinition,
46        array $availablePlugins,
47        $languageCode
48    ) {
49        Assert::parameter( isset( $templateDefinition['mappings']['properties'] ), '$templateDefinition',
50            'Mapping types are no longer supported, properties must be top level in mappings' );
51        $this->connection = $connection;
52        $this->templateName = $templateName;
53        $this->templateDefinition = $templateDefinition;
54        $this->availablePlugins = $availablePlugins;
55        $this->languageCode = $languageCode;
56    }
57
58    /**
59     * @param Connection $connection
60     * @param array $templateDefinition
61     * @param string[] $availablePlugins
62     * @return IndexTemplateBuilder
63     * @throws \InvalidArgumentException
64     */
65    public static function build(
66        Connection $connection,
67        array $templateDefinition,
68        array $availablePlugins
69    ): IndexTemplateBuilder {
70        $templateName = $templateDefinition['template_name'] ?? null;
71        $langCode = $templateDefinition['language_code'] ?? 'int';
72        if ( $templateName === null ) {
73            throw new \InvalidArgumentException( "Missing template name in profile." );
74        }
75        unset( $templateDefinition['template_name'] );
76        unset( $templateDefinition['language_code'] );
77        return new self( $connection, $templateName, $templateDefinition, $availablePlugins, $langCode );
78    }
79
80    public function execute() {
81        $indexTemplate = $this->createIndexTemplate();
82        $analysisConfigBuilder = new AnalysisConfigBuilder( $this->languageCode, $this->availablePlugins, $this->getSearchConfig() );
83        $filter = new AnalysisFilter();
84        [ $analysis, $mappings ] = $filter->filterAnalysis( $analysisConfigBuilder->buildConfig(),
85            $this->templateDefinition['mappings'], true );
86        $templateDefinition = array_merge_recursive( $this->templateDefinition, [ 'settings' => [ 'analysis' => $analysis ] ] );
87        $templateDefinition['mappings'] = $mappings;
88        $response = $indexTemplate->create( $templateDefinition );
89        if ( !$response->isOk() ) {
90            $message = $response->getErrorMessage();
91            if ( $message ) {
92                $message = 'Received HTTP ' . $response->getStatus();
93            }
94            throw new \RuntimeException( "Cannot add template {$this->templateName}$message" );
95        }
96    }
97
98    /**
99     * @return string
100     */
101    public function getTemplateName() {
102        return $this->templateName;
103    }
104
105    private function getSearchConfig() {
106        return $this->connection->getConfig();
107    }
108
109    //
110    private function createIndexTemplate() {
111        // Can go back to plain IndexTemplate when upgrading to Elastica 7
112        return new class( $this->connection->getClient(), $this->templateName ) extends IndexTemplate {
113            public function request( $method, $data = [], array $query = [] ) {
114                $path = '_template/' . $this->getName();
115                return $this->getClient()->request( $path, $method, $data, $query );
116            }
117
118            public function create( array $args = [] ) {
119                return $this->request( \Elastica\Request::PUT, $args );
120            }
121        };
122    }
123}