murmurations-1.0.0-alpha1/src/Form/FilterForm.php
src/Form/FilterForm.php
<?php namespace Drupal\murmurations\Form; use Drupal\murmurations\MurmurationsPluginManager; use Drupal\Core\Form\FormBase; use Drupal\Core\Form\FormStateInterface; use Drupal\user\Entity\User; use Drupal\user\UserData; use Drupal\Core\Render\Markup; use Drupal\Core\Routing\CurrentRouteMatch; use Symfony\Component\HttpFoundation\Request; use GuzzleHttp\Psr7\Response; //@todo inject messenger, guzzle,. abstract class FilterForm extends FormBase { /** * @var Symfony\Component\HttpFoundation\Request */ protected $request; /** * @var UserData */ protected $userData; /** * @var MurmurationsPluginManager */ protected $plugin; /** * @var CurrentRouteMatch */ protected $route_match; /** * @var The current user ID */ protected $uid; /** * @var array * The params collected by the form */ protected $params; /** * @var string * The url of the aggregator with a trailing slash. */ protected string $aggregator; /** * @param UserData $user_data * @param Request $request * @param CurrentRouteMatch $route_match * @param MurmurationsPluginManager $murm_plugin_manager */ public function __construct(UserData $user_data, Request $request, CurrentRouteMatch $route_match, MurmurationsPluginManager $murm_plugin_manager) { $this->userData = $user_data; $this->request = $request; $this->routeMatch = $route_match; $plugin_id = $request->attributes->get('_route_object')->getOptions()['plugin']; $this->plugin = $murm_plugin_manager->createInstance($plugin_id); $this->uid = $this->currentUser()->id(); $this->aggregator = $this->plugin->getConfiguration()['aggregator_url']; if (substr($this->aggregator, -1) <> '/') $this->aggregator .= '/'; $this->aggregator .= $this->plugin->getPluginDefinition()['schema']; } /** * {@inheritDoc} */ function buildForm(array $form, FormStateInterface $form_state) { $this->params = $this->request->query->all(); $form['basic'] = [ '#type' => 'container', 'range' => [ '#title' => $this->t('Max distance'), '#description' => $this->t('from me (0 means any)'), '#type' => 'number', '#default_value' => $this->userData->get('murmurations', $this->uid, 'range')??5, '#field_suffix' => 'km', '#access' => (bool)$this->config('murmurations.settings')->get('fallback_point.lat'), // ONly show '#weight' => 1, '#size' => 6 ], 'fragment' => [ '#title' => $this->t('Keywords'), '#description' => $this->t('Separated by commas for OR'), '#type' => 'textfield', '#default_value' => $this->params['fragment']??'', '#weight' => 2, '#size' => 10 ], '#weight' => 1 ]; $this->plugin->filterFormAlter( $form, $form_state, $this->params + (array)$this->userData->get('murmurations', $this->uid, 'pref') ); $form['submit'] = [ '#type' => 'submit', '#value' => $this->t('Submit'), '#weight' => 10 ]; if ($this->params) { $curr_user = User::load($this->uid); $this->params += murmurations_geolocate_entity_with_fallback($curr_user); [$items, $metadata] = $this->searchRequest(); if ($metadata and $metadata->number_of_results) { if (count($items) == $metadata->number_of_results) { $title = $this->t('Showing all results'); } else { $title = $this->t('Showing @count results of @total', ['@count' => count($items), '@total' => $metadata->number_of_results]); } $form['results'] = [ '#title' => $title, '#type' => 'fieldset', '#open' => TRUE, '#weight' => 12 ]; $form['results']['items'] = $this->showResults($items, $metadata->number_of_results); } else { $form['results'] = ['#markup' => Markup::create($this->t('No results.'))]; } } $form['#attached']['library'][] = 'murmurations/filter_form'; return $form; } /** * {@inheritDoc} */ function submitForm(array &$form, FormStateInterface $form_state) { foreach ($this->plugin->filterFormValues($form_state->cleanValues()->getvalues()) as $key => $val) { $filters[$key] = $val; } $filters['page_size'] = static::RESULTS_PER_PAGE; if ($range = $form_state->getValue('range')) { $filters['range'] = $range; // All searches should be centred around a point. $filters += $this->getFallbackCoords(); } if ($fragment = $form_state->getValue('fragment')) { $filters['text'] = $fragment; } $form_state->setRedirect( $this->routeMatch->getRouteName(), [], [ 'query' => array_filter($filters) ] ); // Remember the user settings. $this->userData->set('murmurations', $this->uid, 'range', $range); } /** * Get the centre of the search, the user's position or the site position. * @return array * with float 'lat' and float 'lon' */ function getFallbackCoords() : array { return \Drupal::config('murmurations.settings')->get('fallback_point'); } /** * Submit to the search engine and parse the results a bit * * @staticvar array $result * * @return array * the results array and metadata array. */ protected function searchRequest() : array { static $result; if (!isset($result)) { $options['headers'] = [ 'Accept' => 'application/json', ]; $url = $this->aggregator .'?'. http_build_query($this->params); try { $response = \Drupal::service('http_client')->get($url, $options); } catch(\Exception $e) { trigger_error($e->getMessage(), E_USER_ERROR); $response = new Response($e->getCode(), [], NULL, '1.1', $e->getMessage()); } if ($response->getStatusCode() != 200) { \Drupal::messenger()->addStatus($response->getReasonPhrase()); $result = [NULL, NULL]; } elseif ($contents = json_decode($response->getBody()->getContents())) { $result = [(array)$contents->data, $contents->meta]; } } return $result; } abstract public function showResults(array $results, int $number_of_results) :array; }