Browse Source

Adds buttons to the interface to allow sorting.

Benjamin Michalski 10 years ago
parent
commit
9cb0b11206

+ 112 - 29
src/Packagist/WebBundle/Controller/WebController.php

@@ -255,14 +255,115 @@ class WebController extends Controller
     {
         $form = $this->createSearchForm();
 
+        $orderBys = $req->query->get('orderBys', array());
+
+        if ($orderBys) {
+            $allowedSorts = array(
+                'downloads' => 1,
+                'favers' => 1
+            );
+
+            $allowedOrders = array(
+                'asc' => 1,
+                'desc' => 1,
+                'ASC' => 1,
+                'DESC' => 1
+            );
+
+            $filteredOrderBys = array();
+
+            foreach ($orderBys as $orderBy) {
+                if (isset($orderBy['sort'])
+                    && isset($allowedSorts[$orderBy['sort']])
+                    && isset($orderBy['order'])
+                    && isset($allowedOrders[$orderBy['order']])) {
+                    $filteredOrderBys[] = $orderBy;
+                }
+            }
+
+            $normalizedOrderBys = array();
+
+            foreach ($filteredOrderBys as $filteredSort) {
+                $normalizedOrderBys[$filteredSort['sort']] = $filteredSort['order'];
+            }
+        } else {
+            $filteredOrderBys = array();
+            $normalizedOrderBys = array();
+        }
+
         // transform q=search shortcut
-        if ($req->query->has('q')) {
-            $req->query->set('search_query', array('query' => $req->query->get('q')));
+        if ($req->query->has('q') || $req->query->has('orderBys')) {
+            $searchQuery = array();
+
+            $q = $req->query->get('q');
+
+            if ($q !== null) {
+                $searchQuery['query'] = $q;
+            }
+
+            if (!empty($filteredOrderBys)) {
+                $searchQuery['orderBys'] = $filteredOrderBys;
+            }
+
+            $req->query->set(
+                'search_query',
+                $searchQuery
+            );
         }
 
+        $makeDefaultArrow = function ($sort) use ($normalizedOrderBys) {
+            if (isset($normalizedOrderBys[$sort])) {
+                if (strtolower($normalizedOrderBys[$sort]) === 'asc') {
+                    $val = 'icon-arrow-up';
+                } else {
+                    $val = 'icon-arrow-down';
+                }
+            } else {
+                $val = '';
+            }
+
+            return $val;
+        };
+
+        $makeDefaultHref = function ($sort) use ($req, $normalizedOrderBys) {
+            if (isset($normalizedOrderBys[$sort])) {
+                if (strtolower($normalizedOrderBys[$sort]) === 'asc') {
+                    $order = 'desc';
+                } else {
+                    $order = 'asc';
+                }
+            } else {
+                $order = 'desc';
+            }
+
+            return '?' . http_build_query(array(
+                'q' => $req->query->get('q') === null ? '' : $req->query->get('q'),
+                'orderBys' => array(
+                    array(
+                        'sort' => $sort,
+                        'order' => $order
+                    )
+                )
+            ));
+        };
+
+        $orderBysViewModel = array(
+            'downloads' => array(
+                'title' => 'Clic to sort by downloads desc',
+                'class' => 'icon-download',
+                'arrowClass' => $makeDefaultArrow('downloads'),
+                'href' => $makeDefaultHref('downloads')
+            ),
+            'favers' => array(
+                'title' => 'Clic to sort by favorites desc',
+                'class' => 'icon-star',
+                'arrowClass' => $makeDefaultArrow('favers'),
+                'href' => $makeDefaultHref('favers')
+            ),
+        );
+
         $typeFilter = $req->query->get('type');
         $tagsFilter = $req->query->get('tags');
-        $orderBys = $req->query->get('orderBys');
 
         if ($req->query->has('search_query') || $typeFilter || $tagsFilter) {
             /** @var $solarium \Solarium_Client */
@@ -295,35 +396,13 @@ class WebController extends Controller
                 $select->addFilterQuery($filterQuery);
             }
 
-            if ($orderBys) {
-                $allowedSorts = array(
-                    'downloads' => 1,
-                    'favers' => 1
-                );
-
-                $allowedOrders = array(
-                    'asc' => 1,
-                    'desc' => 1,
-                    'ASC' => 1,
-                    'DESC' => 1
-                );
-
-                $filteredSorts = array();
-
-                foreach ($orderBys as $orderBy) {
-                    if (isset($orderBy['sort'])
-                        && isset($allowedSorts[$orderBy['sort']])
-                        && isset($orderBy['order'])
-                        && isset($allowedOrders[$orderBy['order']])) {
-                        $filteredSorts[$orderBy['sort']] = $orderBy['order'];
-                    }
-                }
-
-                $select->addSorts($filteredSorts);
+            if (!empty($filteredOrderBys)) {
+                $select->addSorts($normalizedOrderBys);
             }
 
             if ($req->query->has('search_query')) {
                 $form->bind($req);
+
                 if ($form->isValid()) {
                     $escapedQuery = $select->getHelper()->escapeTerm($form->getData()->getQuery());
                     $escapedQuery = preg_replace('/(^| )\\\\-(\S)/', '$1-$2', $escapedQuery);
@@ -439,6 +518,7 @@ class WebController extends Controller
                 'packages' => $paginator,
                 'meta' => $metadata,
                 'searchForm' => $form->createView(),
+                'orderBys' => $orderBysViewModel
             ));
         } elseif ($req->getRequestFormat() === 'json') {
             return JsonResponse::create(array(
@@ -446,7 +526,10 @@ class WebController extends Controller
             ), 400)->setCallback($req->query->get('callback'));
         }
 
-        return $this->render('PackagistWebBundle:Web:search.html.twig', array('searchForm' => $form->createView()));
+        return $this->render('PackagistWebBundle:Web:search.html.twig', array(
+            'searchForm' => $form->createView(),
+            'orderBys' => $orderBysViewModel
+        ));
     }
 
     /**

+ 49 - 0
src/Packagist/WebBundle/Form/Model/OrderBy.php

@@ -0,0 +1,49 @@
+<?php
+
+/*
+ * This file is part of Packagist.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *     Nils Adermann <naderman@naderman.de>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Packagist\WebBundle\Form\Model;
+
+/**
+ * @author Benjamin Michalski <benjamin.michalski@gmail.com>
+ */
+class OrderBy
+{
+    /**
+     * @var string
+     */
+    protected $sort;
+
+    /**
+     * @var string
+     */
+    protected $order;
+
+    public function setSort($sort)
+    {
+        $this->sort = $sort;
+    }
+
+    public function getSort()
+    {
+        return $this->sort;
+    }
+
+    public function setOrder($order)
+    {
+        $this->order = $order;
+    }
+
+    public function getOrder()
+    {
+        return $this->order;
+    }
+}

+ 15 - 0
src/Packagist/WebBundle/Form/Model/SearchQuery.php

@@ -21,6 +21,11 @@ class SearchQuery
      */
     protected $query;
 
+    /**
+     * @var array
+     */
+    protected $orderBys;
+
     public function setQuery($query)
     {
         $this->query = $query;
@@ -30,4 +35,14 @@ class SearchQuery
     {
         return $this->query;
     }
+
+    public function setOrderBys($orderBys)
+    {
+        $this->orderBys = $orderBys;
+    }
+
+    public function getOrderBys()
+    {
+        return $this->orderBys;
+    }
 }

+ 48 - 0
src/Packagist/WebBundle/Form/Type/OrderByType.php

@@ -0,0 +1,48 @@
+<?php
+
+/*
+ * This file is part of Packagist.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *     Nils Adermann <naderman@naderman.de>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Packagist\WebBundle\Form\Type;
+
+use Symfony\Component\Form\AbstractType;
+use Symfony\Component\Form\FormBuilderInterface;
+use Symfony\Component\OptionsResolver\OptionsResolverInterface;
+
+/**
+ * @author Benjamin Michalski <benjamin.michalski@gmail.com>
+ */
+class OrderByType extends AbstractType
+{
+    public function buildForm(FormBuilderInterface $builder, array $options)
+    {
+        $builder->add('sort');
+        $builder->add('order', 'choice', array(
+            'choices' => array(
+                'asc' => 'asc',
+                'desc' => 'desc'
+            )
+        ));
+    }
+
+    public function setDefaultOptions(OptionsResolverInterface $resolver)
+    {
+        $resolver->setDefaults(array(
+            'data_class' => 'Packagist\WebBundle\Form\Model\OrderBy',
+            'csrf_protection' => false,
+        ));
+    }
+
+
+    public function getName()
+    {
+        return 'order_by';
+    }
+}

+ 5 - 0
src/Packagist/WebBundle/Form/Type/SearchQueryType.php

@@ -24,6 +24,11 @@ class SearchQueryType extends AbstractType
     public function buildForm(FormBuilderInterface $builder, array $options)
     {
         $builder->add('query', 'search');
+        $builder->add('orderBys', 'collection', array(
+            'type' => new OrderByType(),
+            'allow_add' => true,
+            'allow_delete' => true
+        ));
     }
 
     public function setDefaultOptions(OptionsResolverInterface $resolver)

+ 28 - 3
src/Packagist/WebBundle/Resources/public/css/main.css

@@ -438,11 +438,36 @@ form ul {
 
 /* Search */
 #search_query_query {
-  width: 890px;
+  width: 737px;
+  display: inline;
 }
 .no-js #search_query_query {
-  width: 780px;
+  width: 600px;
+}
+
+#search_query_orderBys {
+    display: none;
 }
+
+#order-bys-wrapper {
+    margin-left: 0.7em;
+    display: inline;
+    font-size: 24px;
+    position: relative;
+    top: 4px;
+}
+
+#order-bys-wrapper a {
+    width: 46px;
+    margin-right: 7px;
+    display: inline-block;
+}
+
+#order-bys-wrapper a.clear {
+    width: auto;
+    margin-right: 0px;
+}
+
 #search-form .submit-wrapper {
   width: 100px;
   float: right;
@@ -776,4 +801,4 @@ pre {
   @page { margin: 0.5cm; }
   p, h2, h3 { orphans: 3; widows: 3; }
   h2, h3{ page-break-after: avoid; }
-}
+}

+ 21 - 0
src/Packagist/WebBundle/Resources/views/Web/searchForm.html.twig

@@ -3,6 +3,27 @@
     <p>
         {{ form_errors(searchForm.query) }}
         {{ form_widget(searchForm.query, {'attr': {'autocomplete': 'off', 'autofocus': 'autofocus', 'placeholder': 'Search packages...', 'tabindex': 1}}) }}
+        <div
+            id="order-bys-wrapper">
+            {% for sort,param in orderBys %}
+                <a
+                    title="{{ param.title }}"
+                    href="{{ param.href }}">
+                    <i class="icon {{ param.class }}"></i>
+                    <i class="icon {{ param.arrowClass }}"></i>
+                </a>
+            {% endfor %}
+            <a
+                title="Clear order bys"
+                href="?q={{ searchForm.vars.value.query }}"
+                class="clear">
+                <i class="icon icon-remove-circle"></i>
+            </a>
+        </div>
+        <div
+            class="hidden">
+            {{ form_widget(searchForm.orderBys) }}
+        </div>
         {{ form_rest(searchForm) }}
     </p>
 </form>