Completed
Push — master ( bd1580...0ea8fb )
by Florian
09:56
created

SearchControllerTrait::setSearchService()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
declare(strict_types=1);
3
4
/*
5
 * This file is part of the Stinger Entity Search package.
6
 *
7
 * (c) Oliver Kotte <[email protected]>
8
 * (c) Florian Meyer <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace StingerSoft\EntitySearchBundle\Controller;
15
16
use StingerSoft\EntitySearchBundle\Form\QueryType;
17
use StingerSoft\EntitySearchBundle\Model\PaginatableResultSet;
18
use StingerSoft\EntitySearchBundle\Model\Query;
19
use StingerSoft\EntitySearchBundle\Services\Mapping\DocumentToEntityMapperInterface;
20
use StingerSoft\EntitySearchBundle\Services\SearchService;
21
use Symfony\Component\HttpFoundation\JsonResponse;
22
use Symfony\Component\HttpFoundation\Request;
23
use Symfony\Component\HttpFoundation\Session\SessionInterface;
24
25
trait SearchControllerTrait {
26
27
	/**
28
	 * @var SearchService
29
	 */
30
	protected $searchService;
31
	private $availableFacets;
32
	private $facetFormatter;
33
34
	public function searchAction(Request $request, DocumentToEntityMapperInterface $mapper) {
35
		if($request->query->get('term', false) !== false) {
36
			$this->setSearchTerm($request->getSession(), $request->query->get('term'));
0 ignored issues
show
Bug introduced by
It seems like $request->getSession() can be null; however, setSearchTerm() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
37
			return $this->redirectToRoute('stinger_soft_entity_search_search');
0 ignored issues
show
Bug introduced by
It seems like redirectToRoute() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
38
		}
39
40
		$term = $this->getSearchTerm($request->getSession());
0 ignored issues
show
Bug introduced by
It seems like $request->getSession() can be null; however, getSearchTerm() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
41
		$facets = $this->getSearchFacets($request->getSession());
0 ignored issues
show
Bug introduced by
It seems like $request->getSession() can be null; however, getSearchFacets() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
42
		$availableFacets = $this->getAvailableFacets();
43
44
		$query = new Query($term, $facets, array_keys($availableFacets));
45
46
		$facetForm = $this->createForm(QueryType::class, $query, array(
0 ignored issues
show
Bug introduced by
It seems like createForm() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
47
			'used_facets' => $this->getConfiguredUsedFacets($query->getUsedFacets())
48
		));
49
50
		$facetForm->handleRequest($request);
51
		if($facetForm->isSubmitted()) {
52
			if($facetForm->get('clear')->isClicked()) {
53
				$query->setFacets($this->getDefaultFacets());
54
			}
55
			$this->setSearchTerm($request->getSession(), $query->getSearchTerm());
0 ignored issues
show
Bug introduced by
It seems like $request->getSession() can be null; however, setSearchTerm() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
56
			$this->setSearchFacets($request->getSession(), $query->getFacets());
0 ignored issues
show
Bug introduced by
It seems like $request->getSession() can be null; however, setSearchFacets() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
57
		}
58
59
		try {
60
			$result = $this->searchService->search($query);
61
62
			$facetForm = $this->createForm(QueryType::class, $query, array(
0 ignored issues
show
Bug introduced by
It seems like createForm() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
63
				'result'          => $result,
64
				'used_facets'     => $this->getConfiguredUsedFacets($query->getUsedFacets()),
65
				'facet_formatter' => $this->getFacetFormatter()
66
			));
67
68
			$page = (int)$request->query->get('page', 1);
69
			$results = null;
70
			if($result instanceof PaginatableResultSet) {
71
				$results = $result->paginate($page, $this->getResultsPerPage());
72
			} elseif($results !== null) {
73
				$results = $result->getResults(($page - 1) * $this->getResultsPerPage(), $this->getResultsPerPage());
74
			}
75
76
			return $this->render($this->getTemplate(), array(
0 ignored issues
show
Bug introduced by
It seems like render() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
77
				'results'   => $results,
78
				'resultSet' => $result,
79
				'term'      => $query->getSearchTerm(),
80
				'mapper'    => $mapper,
81
				'facetForm' => $facetForm->createView()
82
			));
83
		} catch(\Exception $exception) {
84
			$response = $this->render($this->getErrorTemplate(), array(
0 ignored issues
show
Bug introduced by
It seems like render() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
85
				'error' => $exception->getMessage(),
86
				'term'  => $query->getSearchTerm()
87
			));
88
			return $response->setStatusCode(500);
89
		}
90
	}
91
92
	/**
93
	 * Returns a JSON array of autocompletions for the given term.
94
	 * The term can be provided as a GET or POST paramater with the name <em>term</em>
95
	 *
96
	 * @param Request $request
97
	 * @return \Symfony\Component\HttpFoundation\JsonResponse
98
	 */
99
	public function autocompleteAction(Request $request) {
100
		$term = $request->get('term');
101
		return new JsonResponse($this->searchService->autocomplete($term, $this->getSuggestionCount()));
102
	}
103
104
	/**
105
	 * Provides an online help for the configured search service.
106
	 * If the search service has no online help defined a warning message will be displayed to the user.
107
	 *
108
	 * @param Request $request
109
	 * @return \Symfony\Component\HttpFoundation\Response
110
	 */
111
	public function onlineHelpAction(Request $request) {
112
		$template = $this->searchService->getOnlineHelp($request->getLocale(), $this->getDefaultLocale());
0 ignored issues
show
Bug introduced by
It seems like getDefaultLocale() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
113
		return $this->render($template ?: 'StingerSoftEntitySearchBundle:Help:no_help.html.twig');
0 ignored issues
show
Bug introduced by
It seems like render() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
114
	}
115
116
	/**
117
	 * @param SearchService $searchService
118
	 * @required
119
	 */
120
	public function setSearchService(SearchService $searchService): void {
121
		$this->searchService = $searchService;
122
	}
123
124
	protected function getConfiguredUsedFacets(array $queryUsedFacets) {
125
		$availableFacets = $this->getAvailableFacets();
126
		$usedFacets = array();
127
		foreach($queryUsedFacets as $queryUsedFacet) {
128
			$usedFacets[$queryUsedFacet] = $availableFacets[$queryUsedFacet];
129
		}
130
		return $usedFacets;
131
	}
132
133
	/**
134
	 * Maximum number of suggestions which should be provided by the autocomplete action
135
	 *
136
	 * @return integer
137
	 */
138
	protected function getSuggestionCount() {
139
		return 10;
140
	}
141
142
	/**
143
	 * Prefix to store information in the session variable
144
	 *
145
	 * @return string
146
	 */
147
	protected function getSessionPrefix() {
148
		return 'stinger_soft_entity_search';
149
	}
150
151
	/**
152
	 * Number of results which should be displayed per page
153
	 *
154
	 * @return integer
155
	 */
156
	protected function getResultsPerPage() {
157
		return 10;
158
	}
159
160
	protected function getTemplate() {
161
		return 'StingerSoftEntitySearchBundle:Search:results.html.twig';
162
	}
163
164
	protected function getErrorTemplate() {
165
		return 'StingerSoftEntitySearchBundle:Search:error.html.twig';
166
	}
167
168
	protected function getFacetFormatter() {
169
		$this->initFacets();
170
		return $this->facetFormatter;
171
	}
172
173
	/**
174
	 * Returns an array of preselected facets (no facet selected is the default)
175
	 *
176
	 * @return string[string][]
0 ignored issues
show
Documentation introduced by
The doc-type string[string][] could not be parsed: Expected "]" at position 2, but found "string". (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
177
	 */
178
	protected function getDefaultFacets() {
179
		$availableFacets = $this->getAvailableFacets();
180
		return array_combine(array_keys($availableFacets), array_fill(0, count($availableFacets), array()));
181
	}
182
183
	/**
184
	 * Returns an array of the available facets which should be offered the user as a filter
185
	 *
186
	 * @return string[]
187
	 */
188
	protected function getAvailableFacets() {
189
		$this->initFacets();
190
		return $this->availableFacets;
191
	}
192
193
	protected function initFacets() {
194
		if(!$this->availableFacets) {
195
			$this->availableFacets = array();
196
			$this->facetFormatter = array();
197
198
			$facetServices = $this->getParameter('stinger_soft.entity_search.available_facets');
0 ignored issues
show
Bug introduced by
It seems like getParameter() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
199
			foreach($facetServices as $facetServiceId) {
200
				$facetService = $this->searchService->getFacet($facetServiceId);
201
				$this->availableFacets[$facetService->getField()] = $facetService->getFormOptions();
202
				if($facetService->getFacetFormatter()) {
203
					$this->facetFormatter[$facetService->getField()] = $facetService->getFacetFormatter();
204
				}
205
			}
206
		}
207
	}
208
209
	/**
210
	 * Fetches the searched facets from the session object
211
	 *
212
	 * @param SessionInterface $session
213
	 * @return string[string][]
0 ignored issues
show
Documentation introduced by
The doc-type string[string][] could not be parsed: Expected "]" at position 2, but found "string". (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
214
	 */
215
	protected function getSearchFacets(SessionInterface $session) {
216
		$facets = $session->get($this->getSessionPrefix() . '_facets', false);
217
		return $facets ? \json_decode($facets, true) : $this->getDefaultFacets();
218
	}
219
220
	/**
221
	 * Sets the given search facets in the user's session
222
	 *
223
	 * @param SessionInterface $session
224
	 * @param string[string][] $facets
0 ignored issues
show
Documentation introduced by
The doc-type string[string][] could not be parsed: Expected "]" at position 2, but found "string". (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
225
	 */
226
	protected function setSearchFacets(SessionInterface $session, $facets) {
227
		$session->set($this->getSessionPrefix() . '_facets', \json_encode($facets));
228
	}
229
230
	/**
231
	 * Fetches the search term from the session object
232
	 *
233
	 * @param SessionInterface $session
234
	 * @return mixed
235
	 */
236
	protected function getSearchTerm(SessionInterface $session) {
237
		return $session->get($this->getSessionPrefix() . '_term', false);
238
	}
239
240
	/**
241
	 * Sets the given search term in the user's session
242
	 *
243
	 * @param SessionInterface $session
244
	 * @param string $term
245
	 */
246
	protected function setSearchTerm(SessionInterface $session, $term) {
247
		$session->set($this->getSessionPrefix() . '_term', $term);
248
	}
249
250
}