Completed
Pull Request — master (#27)
by Hari
09:21
created

FindCommandHandler::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 5
ccs 0
cts 5
cp 0
rs 9.4286
cc 1
eloc 3
nc 1
nop 2
crap 2
1
<?php
2
3
/*
4
 * This file is part of the puli/cli package.
5
 *
6
 * (c) Bernhard Schussek <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Puli\Cli\Handler;
13
14
use Puli\Cli\Util\StringUtil;
15
use Puli\Discovery\Api\Discovery;
16
use Puli\Discovery\Binding\ResourceBinding;
17
use Puli\Repository\Api\ResourceRepository;
18
use RuntimeException;
19
use Webmozart\Console\Api\Args\Args;
20
use Webmozart\Console\Api\IO\IO;
21
use Webmozart\Console\UI\Component\Table;
22
use Webmozart\Console\UI\Style\TableStyle;
23
use Webmozart\Expression\Expr;
24
25
/**
26
 * Handles the "find" command.
27
 *
28
 * @since  1.0
29
 *
30
 * @author Bernhard Schussek <[email protected]>
31
 */
32
class FindCommandHandler
33
{
34
    /**
35
     * @var ResourceRepository
36
     */
37
    private $repo;
38
39
    /**
40
     * @var Discovery
41
     */
42
    private $discovery;
43
44
    /**
45
     * Creates the handler.
46
     *
47
     * @param ResourceRepository $repo      The resource repository.
48
     * @param Discovery          $discovery The discovery.
49
     */
50
    public function __construct(ResourceRepository $repo, Discovery $discovery)
51
    {
52
        $this->repo = $repo;
53
        $this->discovery = $discovery;
54
    }
55
56
    /**
57
     * Handles the "find" command.
58
     *
59
     * @param Args $args The console arguments.
60
     * @param IO   $io   The I/O.
61
     *
62
     * @return int The status code.
63
     */
64
    public function handle(Args $args, IO $io)
65
    {
66
        $criteria = array();
67
68
        if ($args->isOptionSet('path')) {
69
            $criteria['path'] = $args->getOption('path');
70
            $criteria['language'] = $args->getOption('language');
71
        }
72
73
        if ($args->isOptionSet('name')) {
74
            if (isset($criteria['path'])) {
75
                throw new RuntimeException('The options --name and --path cannot be combined.');
76
            }
77
78
            $criteria['path'] = '/**/'.$args->getOption('name');
79
            $criteria['language'] = $args->getOption('language');
80
        }
81
82
        if ($args->isOptionSet('class')) {
83
            $criteria['class'] = $args->getOption('class');
84
        }
85
86
        if ($args->isOptionSet('type')) {
87
            $criteria['bindingType'] = $args->getOption('type');
88
        }
89
90
        if (empty($criteria)) {
91
            throw new RuntimeException('No search criteria specified.');
92
        }
93
94
        return $this->listMatches($io, $criteria);
95
    }
96
97
    /**
98
     * Lists the matches for the given search criteria.
99
     *
100
     * @param IO    $io       The I/O.
101
     * @param array $criteria The array with the optional keys "pattern",
102
     *                        "shortClass" and "bindingType".
103
     *
104
     * @return int The status code.
105
     */
106
    private function listMatches(IO $io, array $criteria)
107
    {
108
        if (isset($criteria['path']) && isset($criteria['bindingType'])) {
109
            $matches = array_intersect_key(
110
                $this->findByPath($criteria['path'], $criteria['language']),
111
                $this->findByBindingType($criteria['bindingType'])
112
            );
113
        } elseif (isset($criteria['path'])) {
114
            $matches = $this->findByPath($criteria['path'], $criteria['language']);
115
        } elseif (isset($criteria['bindingType'])) {
116
            $matches = $this->findByBindingType($criteria['bindingType']);
117
        } else {
118
            $matches = $this->findByPath('/*');
119
        }
120
121
        if (isset($criteria['class'])) {
122
            $shortClass = $criteria['class'];
123
124
            $matches = array_filter($matches, function ($value) use ($shortClass) {
125
                return $value === $shortClass;
126
            });
127
        }
128
129
        $this->printTable($io, $matches);
130
131
        return 0;
132
    }
133
134
    /**
135
     * Finds the resources for a given path pattern.
136
     *
137
     * @param string $query    The resource query.
138
     * @param string $language The language of the query.
139
     *
140
     * @return string[] An array of short resource class names indexed by
141
     *                  the resource path.
142
     */
143
    private function findByPath($query, $language = 'glob')
144
    {
145
        $matches = array();
146
        $query = '/'.ltrim($query, '/');
147
148
        foreach ($this->repo->find($query, $language) as $resource) {
149
            $matches[$resource->getPath()] = StringUtil::getShortClassName(get_class($resource));
150
        }
151
152
        return $matches;
153
    }
154
155
    /**
156
     * Finds the resources for a given binding type.
157
     *
158
     * @param string $typeName The type name.
159
     *
160
     * @return string[] An array of short resource class names indexed by
161
     *                  the resource path.
162
     */
163
    private function findByBindingType($typeName)
164
    {
165
        $matches = array();
166
167
        $expr = Expr::isInstanceOf('Puli\Discovery\Binding\ResourceBinding');
168
169
        foreach ($this->discovery->findBindings($typeName, $expr) as $binding) {
170
            /** @var ResourceBinding $binding */
171
            foreach ($binding->getResources() as $resource) {
172
                $matches[$resource->getPath()] = StringUtil::getShortClassName(get_class($resource));
173
            }
174
        }
175
176
        ksort($matches);
177
178
        return $matches;
179
    }
180
181
    /**
182
     * Prints the given resources.
183
     *
184
     * @param IO       $io      The I/O.
185
     * @param string[] $matches An array of short resource class names indexed
186
     *                          by the resource path.
187
     */
188
    private function printTable(IO $io, array $matches)
189
    {
190
        $table = new Table(TableStyle::borderless());
191
192
        foreach ($matches as $path => $shortClass) {
193
            $table->addRow(array($shortClass, sprintf('<c1>%s</c1>', $path)));
194
        }
195
196
        $table->render($io);
197
    }
198
}
199