Completed
Push — master ( 6d6774...64f3ed )
by Jeroen
11:23 queued 05:13
created

Kunstmaan/NodeSearchBundle/Search/NodeSearcher.php (1 issue)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace Kunstmaan\NodeSearchBundle\Search;
4
5
use Doctrine\ORM\EntityManager;
6
use Elastica\Query;
7
use Elastica\Query\BoolQuery;
8
use Elastica\Query\Match;
9
use Elastica\Query\QueryString;
10
use Elastica\Query\Term;
11
use Elastica\Util;
12
use Kunstmaan\AdminBundle\Entity\BaseUser;
13
use Kunstmaan\AdminBundle\Helper\DomainConfigurationInterface;
14
use Kunstmaan\NodeBundle\Entity\Node;
15
use Kunstmaan\NodeSearchBundle\Entity\NodeSearch;
16
use Kunstmaan\NodeSearchBundle\Helper\SearchBoostInterface;
17
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
18
19
/**
20
 * Default node searcher implementation
21
 */
22
class NodeSearcher extends AbstractElasticaSearcher
23
{
24
    /**
25
     * @var TokenStorageInterface
26
     */
27
    protected $tokenStorage = null;
28
29
    /**
30
     * @var DomainConfigurationInterface
31
     */
32
    protected $domainConfiguration;
33
34
    /**
35
     * @var EntityManager
36
     */
37
    protected $em;
38
39
    /**
40
     * @var bool
41
     */
42
    protected $useMatchQueryForTitle = false;
43
44
    /**
45
     * @param TokenStorageInterface $tokenStorage
46
     */
47
    public function setTokenStorage(TokenStorageInterface $tokenStorage)
48
    {
49
        $this->tokenStorage = $tokenStorage;
50
    }
51
52
    /**
53
     * @param DomainConfigurationInterface $domainConfiguration
54
     */
55
    public function setDomainConfiguration(DomainConfigurationInterface $domainConfiguration)
56
    {
57
        $this->domainConfiguration = $domainConfiguration;
58
    }
59
60
    /**
61
     * @param EntityManager $em
62
     */
63
    public function setEntityManager(EntityManager $em)
64
    {
65
        $this->em = $em;
66
    }
67
68
    /**
69
     * @param bool $useMatchQueryForTitle
70
     */
71
    public function setUseMatchQueryForTitle($useMatchQueryForTitle)
72
    {
73
        $this->useMatchQueryForTitle = $useMatchQueryForTitle;
74
    }
75
76
    /**
77
     * @param mixed  $query
78
     * @param string $type
79
     *
80
     * @return mixed|void
81
     */
82
    public function defineSearch($query, $type)
83
    {
84
        $query = Util::escapeTerm($query);
85
86
        $elasticaQueryString = new Match();
87
        $elasticaQueryString
88
            ->setFieldMinimumShouldMatch('content', '80%')
89
            ->setFieldQuery('content', $query);
90
91
        if ($this->useMatchQueryForTitle) {
92
            $elasticaQueryTitle = new Match();
93
            $elasticaQueryTitle
94
                ->setFieldQuery('title', $query)
95
                ->setFieldMinimumShouldMatch('title', '80%')
96
                ->setFieldBoost('title', 2)
97
            ;
98
        } else {
99
            $elasticaQueryTitle = new QueryString();
100
            $elasticaQueryTitle
101
              ->setDefaultField('title')
102
              ->setQuery($query);
103
        }
104
105
        $elasticaQueryBool = new BoolQuery();
106
        $elasticaQueryBool
107
            ->addShould($elasticaQueryTitle)
108
            ->addShould($elasticaQueryString)
109
            ->setMinimumShouldMatch(1);
110
111
        $this->applySecurityFilter($elasticaQueryBool);
112
113
        if (!\is_null($type)) {
114
            $elasticaQueryType = new Term();
115
            $elasticaQueryType->setTerm('type', $type);
116
            $elasticaQueryBool->addMust($elasticaQueryType);
117
        }
118
119
        $rootNode = $this->domainConfiguration->getRootNode();
120
        if (!\is_null($rootNode)) {
121
            $elasticaQueryRoot = new Term();
122
            $elasticaQueryRoot->setTerm('root_id', $rootNode->getId());
123
            $elasticaQueryBool->addMust($elasticaQueryRoot);
124
        }
125
126
        $rescore = new \Elastica\Rescore\Query();
127
        $rescore->setRescoreQuery($this->getPageBoosts());
128
129
        $this->query->setQuery($elasticaQueryBool);
130
        $this->query->setRescore($rescore);
131
        $this->query->setHighlight(
132
            array(
133
                'pre_tags' => array('<strong>'),
134
                'post_tags' => array('</strong>'),
135
                'fields' => array(
136
                    'content' => array(
137
                        'fragment_size' => 150,
138
                        'number_of_fragments' => 3,
139
                    ),
140
                ),
141
            )
142
        );
143
    }
144
145
    /**
146
     * Filter search results so only documents that are viewable by the current
147
     * user will be returned...
148
     *
149
     * @param \Elastica\Query\BoolQuery $elasticaQueryBool
150
     */
151
    protected function applySecurityFilter($elasticaQueryBool)
152
    {
153
        $roles = $this->getCurrentUserRoles();
154
155
        $elasticaQueryRoles = new Query\Terms('view_roles', $roles);
156
        $elasticaQueryBool->addMust($elasticaQueryRoles);
157
    }
158
159
    /**
160
     * @return array
161
     */
162
    protected function getCurrentUserRoles()
163
    {
164
        $roles = array();
165
        if (!\is_null($this->tokenStorage)) {
166
            $user = $this->tokenStorage->getToken()->getUser();
167
            if ($user instanceof BaseUser) {
168
                $roles = $user->getRoles();
169
            }
170
        }
171
172
        // Anonymous access should always be available for both anonymous & logged in users
173
        if (!\in_array('IS_AUTHENTICATED_ANONYMOUSLY', $roles, true)) {
174
            $roles[] = 'IS_AUTHENTICATED_ANONYMOUSLY';
175
        }
176
177
        // Return a re-indexed array to make sure the array keys are incremental and don't skip a number. Otherwise
178
        // this causes issues in ES7.
179
        return array_values($roles);
180
    }
181
182
    /**
183
     * Apply PageType specific and Page specific boosts
184
     *
185
     * @return \Elastica\Query\BoolQuery
186
     */
187
    protected function getPageBoosts()
188
    {
189
        $rescoreQueryBool = new BoolQuery();
190
191
        //Apply page type boosts
192
        $pageClasses = $this->em->getRepository(Node::class)->findAllDistinctPageClasses();
0 ignored issues
show
The method findAllDistinctPageClasses() does not exist on Doctrine\Persistence\ObjectRepository. Did you maybe mean findAll()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
193
        foreach ($pageClasses as $pageClass) {
194
            $page = new $pageClass['refEntityName']();
195
196
            if ($page instanceof SearchBoostInterface) {
197
                $elasticaQueryTypeBoost = new QueryString();
198
                $elasticaQueryTypeBoost
199
                    ->setBoost($page->getSearchBoost())
200
                    ->setDefaultField('page_class')
201
                    ->setQuery(addslashes($pageClass['refEntityName']));
202
203
                $rescoreQueryBool->addShould($elasticaQueryTypeBoost);
204
            }
205
        }
206
207
        //Apply page specific boosts
208
        $nodeSearches = $this->em->getRepository(NodeSearch::class)->findAll();
209
        foreach ($nodeSearches as $nodeSearch) {
210
            $elasticaQueryNodeId = new QueryString();
211
            $elasticaQueryNodeId
212
                ->setBoost($nodeSearch->getBoost())
213
                ->setDefaultField('node_id')
214
                ->setQuery($nodeSearch->getNode()->getId());
215
216
            $rescoreQueryBool->addShould($elasticaQueryNodeId);
217
        }
218
219
        return $rescoreQueryBool;
220
    }
221
}
222