Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
0 / 0
CRAP
100.00% covered (success)
100.00%
0 / 0
BrowseController
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
4 / 4
21
100.00% covered (success)
100.00%
0 / 0
 index
100.00% covered (success)
100.00%
1 / 1
11
100.00% covered (success)
100.00%
0 / 0
 anonymous function
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
0 / 0
 convertQuery
100.00% covered (success)
100.00%
1 / 1
3
100.00% covered (success)
100.00%
0 / 0
 generateUrl
100.00% covered (success)
100.00%
1 / 1
6
100.00% covered (success)
100.00%
0 / 0
<?php
namespace Mtc\Shop\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Mtc\Core\Admin\Node;
use Mtc\Core\Taxonomy;
use Mtc\Shop\Contracts\ProductRepositoryContract;
use Mtc\Shop\Product;
class BrowseController extends Controller
{
    public $sort_options = [
        [
            'key' => 'new-additions',
            'label' => 'New Additions'
        ],
        [
            'key' => 'price-asc',
            'label' => 'Price (Low-High)'
        ],
        [
            'key' => 'price-desc',
            'label' => 'Price (High-Low)'
        ],
    ];
    public function index(Request $request, ProductRepositoryContract $repository, $query = '')
    {
        if (false === $request->wantsJson()) {
            return view('shop::public.browse')->with($this->convertQuery($query));
        }
        $products = $repository->filter($request);
        if (true == $request->input('full', true)) {
            // @todo: Limit to all product nodes and the taxonomies ancestors.
            // @todo: Functionalty to go through taxonomy levels.
            $options = \Cache::remember(
                'taxonomy_roots_with_children',
                30,
                function() {
                    return Taxonomy::roots()->with('children')->get();
                }
            );
            $selected = Taxonomy::whereIn(
                    'id',
                    collect(
                        $request->input('selected', [])
                    )->pluck('id')
                )->get()
                ->map(
                    function($item) use ($options) {
                        // As we are using nested sets, we can determine the
                        // root by finding which ids are within the root's
                        // lft/rgt attributes.
                        foreach ($options as $root) {
                            if (
                                $item->id > $root->lft &&
                                $item->id < $root->rgt
                            ) {
                                $item->root = $root;
                                return $item;
                            }
                        }
                        return $item;
                    }
                );
            $options = $options->map(
                function($option) use ($selected, $request) {
                    $children = $selected->where('root.id', $option->id)
                        ->sortByDesc('id');
                    $option = $option->toArray();
                    if ($children->isEmpty() === false) {
                        $taxonomy = $children->first();
                        if ($taxonomy->children->isEmpty() === false) {
                            $option['children'] = $taxonomy->children;
                        } elseif ($taxonomy->isLeaf()) {
                            $option['children'] = $taxonomy->siblingsAndSelf()->get();
                        };
                        // Generate a URL for each option
                        foreach ($option['children'] as &$child) {
                            $items = collect($request->input('selected', []));
                            // If selected, remove the item from the URL.
                            if ($items->where('id', $child->id)->isEmpty()) {
                                $items = $items->push(['id' => $child->id]);
                            // If not selected, add the item in.
                            } else {
                                $items = $items->reject(
                                    function($item) use ($child) {
                                        return $item['id'] == $child->id;
                                    }
                                );
                            }
                            $child['url'] = $this->generateUrl($request, $items);
                        }
                    }
                    return (object)$option;
                }
            );
        }
        $url = $this->generateUrl($request);
        $sort_options = $this->sort_options;
        return compact('products', 'options', 'url', 'sort_options');
    }
    /**
     * Take the incoming URL and parse this into the selected variables, sort,
     * and pagination.
     *
     * @param  string $query Incoming query string
     * @return array
     */
    protected function convertQuery($query)
    {
        // Set any defaults
        $data = [
            'selected' => collect([]),
            'sort' => '',
            'page' => 1,
        ];
        // Get the sort/page information
        preg_match_all("/\/?(sort|page)-([-_\w]+)?/", $query, $matches);
        collect($matches)->transpose()->each(
            function($item) use (&$data) {
                $data[$item[1]] = $item[2];
            }
        );
        // + will be used to separate items within the same taxonomy
        $query = str_replace('+', '/', $query);
        // / will be used to seperate different terms
        $slugs = collect(explode('/', $query))
            ->reject(
                function($item) {
                    // Remove sort/pagination (just in case)
                    return empty($item) || preg_match('/(?:sort|page)-.*/', $item) > 0;
                }
            );
        // If we have potential nodes, get information about them.
        if ($slugs->isEmpty() === false) {
            $data['selected'] = Node::select(['nodeable_id as id', 'title'])
                ->whereIn('slug', $slugs)
                ->get();
        }
        return $data;
    }
    /**
     * Generate the current URL or a URL containing additional options.
     *
     * @param  Request $request
     * @param  array   $selected Optionally include an array to override
     *                           $request->input('selected')
     * @return array
     */
    public function generateUrl(Request $request, $selected = [])
    {
        // Get a list of all IDs selected.
        $selected = empty($selected) ? $request->input('selected', []) : $selected;
        $ids = collect($selected)->pluck('id');
        $ids = Taxonomy::whereIn('id', $ids)->get();
        // Now find the root notes for each.
        $root_nodes = $ids->map(
            function($child) {
                return $child->getRoot();
            }
        )->unique()->sortBy('id');
        // Determine sort of page options
        $additional = [];
        if ($request->input('sort_by')) {
            $additional[] = 'sort-' . $request->input('sort_by');
        }
        if ($request->input('page') && $request->input('page') > 1) {
            $additional[] = 'page-' . $request->input('page');
        }
        // Generate the URL
        return route('shop.browse') . '/' . $root_nodes->map(
            function($root) use (&$ids) {
                return $ids->map(
                    function($child, $child_index) use ($root, &$ids) {
                        if ($child->isDescendantOf($root)) {
                            $ids->forget($child_index);
                            return $child->node->slug;
                        }
                        return null;
                    }
                )->reject(
                    function($child) {
                        return is_null($child);
                    }
                )->implode('+');
            }
        )->push($additional)->flatten()->implode('/');
        return $root_nodes->toArray();
    }
}