Completed
Pull Request — master (#65)
by Daniel
03:38 queued 01:31
created

GridViewFactory::resolveOrderings()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 24
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 24
rs 8.6845
c 0
b 0
f 0
cc 4
eloc 13
nc 4
nop 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Psi\Component\Grid;
6
7
use Psi\Component\Grid\Metadata\GridMetadata;
8
use Psi\Component\Grid\View\Grid as GridView;
9
use Psi\Component\ObjectAgent\AgentInterface;
10
use Psi\Component\ObjectAgent\Query\Composite;
11
use Psi\Component\ObjectAgent\Query\Query;
12
13
class GridViewFactory
14
{
15
    /**
16
     * @var ColumnFactory
17
     */
18
    private $columnFactory;
19
20
    /**
21
     * @var FilterFactory
22
     */
23
    private $filterFactory;
24
25
    public function __construct(
26
        ColumnFactory $columnFactory,
27
        FilterBarFactory $filterFactory,
28
        QueryFactory $queryFactory
29
    ) {
30
        $this->columnFactory = $columnFactory;
31
        $this->filterFactory = $filterFactory;
0 ignored issues
show
Documentation Bug introduced by
It seems like $filterFactory of type object<Psi\Component\Grid\FilterBarFactory> is incompatible with the declared type object<Psi\Component\Grid\FilterFactory> of property $filterFactory.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
32
        $this->queryFactory = $queryFactory;
0 ignored issues
show
Bug introduced by
The property queryFactory does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
33
    }
34
35
    public function createView(AgentInterface $agent, GridContext $gridContext, GridMetadata $gridMetadata): GridView
36
    {
37
        // create the filter form based on the metadata and submit any data.
38
        $filterForm = $this->filterFactory->createForm($gridMetadata, $agent->getCapabilities());
39
        $filterForm->submit($gridContext->getFilter());
40
41
        $criteria = [
42
            'criteria' => $this->filterFactory->createExpression($gridMetadata, $filterForm->getData()),
43
            'orderings' => $this->resolveOrderings($gridContext->getOrderings(), $gridMetadata),
44
            'firstResult' => $gridContext->getPageOffset(),
45
            'maxResults' => $gridContext->isPaginated() ? $gridContext->getPageSize() : null,
46
        ];
47
48
        if ($gridMetadata->hasQuery()) {
49
            $query = $this->queryFactory->createQuery($gridContext->getClassFqn(), $gridMetadata->getQuery());
50
            $criteria['selects'] = $query->getSelects();
51
            $criteria['joins'] = $query->getJoins();
52
53
            if ($query->hasExpression()) {
54
                if (null === $criteria['criteria']) {
55
                    $criteria['criteria'] = $query->getExpression();
56
                } else {
57
                    // filter and user criterias need to be combined
58
                    $criteria['criteria'] = new Composite(Composite::AND, [$query->getExpression(), $criteria['criteria']]);
59
                }
60
            }
61
        }
62
63
        // create the query and get the data collection from the object-agent.
64
        $query = Query::create($gridContext->getClassFqn(), $criteria);
65
        $collection = new \IteratorIterator($agent->query($query));
66
67
        return new View\Grid(
68
            $gridContext->getClassFqn(),
69
            $gridMetadata->getName(),
70
            new View\Table($this->columnFactory, $gridMetadata, $gridContext, $collection, $gridContext),
0 ignored issues
show
Unused Code introduced by
The call to Table::__construct() has too many arguments starting with $gridContext.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
71
            new View\Paginator($gridContext, count($collection), $this->getNumberOfRecords($agent, $query)),
72
            new View\FilterBar($filterForm->createView(), $gridContext),
73
            new View\ActionBar($gridMetadata)
74
        );
75
    }
76
77
    private function getNumberOfRecords(AgentInterface $agent, Query $query)
78
    {
79
        if (false === $agent->getCapabilities()->canQueryCount()) {
80
            return;
81
        }
82
83
        return $agent->queryCount($query);
84
    }
85
86
    private function resolveOrderings(array $orderings, GridMetadata $metadata)
87
    {
88
        $columns = $metadata->getColumns();
89
        $realOrderings = [];
90
91
        foreach ($orderings as $columnName => $direction) {
92
            if (!isset($columns[$columnName])) {
93
                throw new \RuntimeException(sprintf(
94
                    'Invalid column "%s"', $columnName
95
                ));
96
            }
97
98
            $column = $columns[$columnName];
99
            $options = $column->getOptions();
100
101
            if (!isset($options['sort_field'])) {
102
                $options['sort_field'] = $columnName;
103
            }
104
105
            $realOrderings[$options['sort_field']] = $direction;
106
        }
107
108
        return $realOrderings;
109
    }
110
}
111