Completed
Branch master (59afb3)
by Adam
05:44
created

SearchBuilder::setLanguages()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Coyote\Services\Elasticsearch\Builders\Job;
4
5
use Coyote\Services\Elasticsearch\Aggs;
6
use Coyote\Services\Elasticsearch\Functions\Decay;
7
use Coyote\Services\Elasticsearch\Functions\FieldValueFactor;
8
use Coyote\Services\Elasticsearch\Functions\Random;
9
use Coyote\Services\Elasticsearch\MultiMatch;
10
use Coyote\Services\Elasticsearch\QueryBuilder;
11
use Coyote\Services\Elasticsearch\Filters;
12
use Coyote\Services\Elasticsearch\Sort;
13
use Coyote\Services\Geocoder\Location;
14
use Illuminate\Http\Request;
15
16
class SearchBuilder extends QueryBuilder
17
{
18
    const PER_PAGE = 15;
19
    const DEFAULT_SORT = '_score';
20
21
    /**
22
     * @var Request
23
     */
24
    protected $request;
25
26
    /**
27
     * @var Filters\Job\City
28
     */
29
    public $city;
30
31
    /**
32
     * @var Filters\Job\Location
33
     */
34
    public $location;
35
36
    /**
37
     * @var Filters\Job\Tag
38
     */
39
    public $tag;
40
41
    /**
42
     * @var string|null
43
     */
44
    protected $sessionId = null;
45
46
    /**
47
     * @var array
48
     */
49
    protected $languages = [];
50
51
    /**
52
     * @param Request $request
53
     */
54
    public function __construct(Request $request)
55
    {
56
        $this->request = $request;
57
58
        $this->city = new Filters\Job\City();
59
        $this->tag = new Filters\Job\Tag();
60
        $this->location = new Filters\Job\Location();
61
    }
62
63
    /**
64
     * @param string $sessionId
65
     */
66
    public function setSessionId(string $sessionId)
67
    {
68
        $this->sessionId = $sessionId;
69
    }
70
71
    /**
72
     * @param array $languages
73
     */
74
    public function setLanguages(array $languages)
75
    {
76
        $this->languages = $languages;
77
    }
78
79
    /**
80
     * @param \Coyote\Job\Preferences $preferences
81
     */
82
    public function setPreferences($preferences)
83
    {
84
        if (!empty($preferences->locations)) {
85
            $this->location->setLocations($preferences->locations);
86
        }
87
88
        if (!empty($preferences->tags)) {
89
            $this->tag->setTags($preferences->tags);
90
        }
91
92
        if (!empty($preferences->is_remote)) {
93
            $this->addRemoteFilter();
94
        }
95
96
        if (!empty($preferences->salary)) {
0 ignored issues
show
Documentation introduced by
The property salary does not exist on object<Coyote\Job\Preferences>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
97
            $this->addSalaryFilter($preferences->salary, $preferences->currency_id);
0 ignored issues
show
Documentation introduced by
The property salary does not exist on object<Coyote\Job\Preferences>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
98
        }
99
    }
100
101
    /**
102
     * @param Location|null $location
103
     */
104
    public function boostLocation(Location $location = null)
105
    {
106
        $this->should(new Filters\Job\LocationScore($location));
107
    }
108
109
    /**
110
     * Apply remote job filter
111
     */
112
    public function addRemoteFilter()
113
    {
114
        $this->must(new Filters\Job\Remote());
115
116
        if ($this->request->has('remote_range')) {
117
            $this->must(new Filters\Job\RemoteRange());
118
        }
119
    }
120
121
    /**
122
     * @param int $salary
123
     * @param int $currencyId
124
     */
125
    public function addSalaryFilter($salary, $currencyId)
126
    {
127
        $this->must(new Filters\Range('salary', ['gte' => $salary]));
128
        $this->must(new Filters\Job\Currency($currencyId));
129
    }
130
131
    /**
132
     * @param string $name
133
     */
134
    public function addFirmFilter($name)
135
    {
136
        $this->must(new Filters\Job\Firm($name));
137
    }
138
139
    /**
140
     * @param int $userId
141
     */
142
    public function addUserFilter($userId)
143
    {
144
        $this->must(new Filters\Term('user_id', $userId));
145
    }
146
147
    /**
148
     * @return array
149
     */
150
    public function build()
151
    {
152
        if ($this->request->has('q')) {
153
            $this->must(
154
                new MultiMatch($this->request->get('q'), ['title^3', 'description', 'requirements', 'recruitment', 'tags^2', 'firm.name'])
155
            );
156
        } else {
157
            // no keywords were provided -- let's calculate score based on score functions
158
            $this->setupScoreFunctions();
159
        }
160
161
        if ($this->request->has('city')) {
162
            $this->city->addCity($this->request->get('city'));
163
        }
164
165
        if ($this->request->has('tag')) {
166
            $this->tag->addTag($this->request->get('tag'));
167
        }
168
169
        if ($this->request->has('salary')) {
170
            $this->addSalaryFilter($this->request->get('salary'), $this->request->get('currency'));
171
        }
172
173
        if ($this->request->has('remote')) {
174
            $this->addRemoteFilter();
175
        }
176
177
        $this->score(new Random($this->sessionId, 2));
178
        $this->sort(new Sort($this->getSort(), $this->getOrder()));
179
180
        $this->setupFilters();
181
182
        // facet search
183
        $this->setupAggregations();
184
185
        $this->size(self::PER_PAGE * ((int) $this->request->get('page', 1) - 1), self::PER_PAGE);
186
187
        return parent::build();
188
    }
189
190
    protected function setupFilters()
191
    {
192
        $this->must($this->city);
193
        $this->must($this->tag);
194
        $this->must($this->location);
195
    }
196
197
    protected function setupScoreFunctions()
198
    {
199
        // wazniejsze sa te ofery, ktorych pole score jest wyzsze. obliczamy to za pomoca wzoru: log(score * 1)
200
        $this->score(new FieldValueFactor('score', 'log', 1));
201
        // strsze ogloszenia traca na waznosci, glownie po 14d. z kazdym dniem score bedzie malalo o 1/10
202
        // za wyjatkiem pierwszych 2h publikacji
203
        $this->score(new Decay('boost_at', '14d', 0.1, '2h'));
204
    }
205
206
    protected function setupAggregations()
207
    {
208
        $this->aggs(new Aggs\Job\Location());
209
        $this->aggs(new Aggs\Job\Remote());
210
        $this->aggs(new Aggs\Job\Tag($this->languages));
211
        $this->aggs(new Aggs\Job\Boost());
212
    }
213
214
    /**
215
     * @return string
216
     */
217
    private function getSort()
218
    {
219
        $sort = $this->request->get('sort', '_score');
220
221
        return in_array($sort, ['id', '_score', 'salary']) ? $sort : self::DEFAULT_SORT;
222
    }
223
224
    /**
225
     * @return string
226
     */
227
    private function getOrder()
228
    {
229
        $order = $this->request->get('order', 'desc');
230
231
        return in_array($order, ['asc', 'desc']) ? $order : 'desc';
232
    }
233
}
234