Version 1
[yaffs-website] / vendor / psy / psysh / src / Psy / Command / ListCommand / Enumerator.php
1 <?php
2
3 /*
4  * This file is part of Psy Shell.
5  *
6  * (c) 2012-2017 Justin Hileman
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 Psy\Command\ListCommand;
13
14 use Psy\Formatter\SignatureFormatter;
15 use Psy\Util\Mirror;
16 use Psy\VarDumper\Presenter;
17 use Symfony\Component\Console\Input\InputInterface;
18
19 /**
20  * Abstract Enumerator class.
21  */
22 abstract class Enumerator
23 {
24     // Output styles
25     const IS_PUBLIC    = 'public';
26     const IS_PROTECTED = 'protected';
27     const IS_PRIVATE   = 'private';
28     const IS_GLOBAL    = 'global';
29     const IS_CONSTANT  = 'const';
30     const IS_CLASS     = 'class';
31     const IS_FUNCTION  = 'function';
32
33     private $presenter;
34
35     private $filter       = false;
36     private $invertFilter = false;
37     private $pattern;
38
39     /**
40      * Enumerator constructor.
41      *
42      * @param Presenter $presenter
43      */
44     public function __construct(Presenter $presenter)
45     {
46         $this->presenter = $presenter;
47     }
48
49     /**
50      * Return a list of categorized things with the given input options and target.
51      *
52      * @param InputInterface $input
53      * @param Reflector      $reflector
54      * @param mixed          $target
55      *
56      * @return array
57      */
58     public function enumerate(InputInterface $input, \Reflector $reflector = null, $target = null)
59     {
60         $this->setFilter($input);
61
62         return $this->listItems($input, $reflector, $target);
63     }
64
65     /**
66      * Enumerate specific items with the given input options and target.
67      *
68      * Implementing classes should return an array of arrays:
69      *
70      *     [
71      *         'Constants' => [
72      *             'FOO' => [
73      *                 'name'  => 'FOO',
74      *                 'style' => 'public',
75      *                 'value' => '123',
76      *             ],
77      *         ],
78      *     ]
79      *
80      * @param InputInterface $input
81      * @param Reflector      $reflector
82      * @param mixed          $target
83      *
84      * @return array
85      */
86     abstract protected function listItems(InputInterface $input, \Reflector $reflector = null, $target = null);
87
88     protected function presentRef($value)
89     {
90         return $this->presenter->presentRef($value);
91     }
92
93     protected function showItem($name)
94     {
95         return $this->filter === false || (preg_match($this->pattern, $name) xor $this->invertFilter);
96     }
97
98     private function setFilter(InputInterface $input)
99     {
100         if ($pattern = $input->getOption('grep')) {
101             if (substr($pattern, 0, 1) !== '/' || substr($pattern, -1) !== '/' || strlen($pattern) < 3) {
102                 $pattern = '/' . preg_quote($pattern, '/') . '/';
103             }
104
105             if ($input->getOption('insensitive')) {
106                 $pattern .= 'i';
107             }
108
109             $this->validateRegex($pattern);
110
111             $this->filter       = true;
112             $this->pattern      = $pattern;
113             $this->invertFilter = $input->getOption('invert');
114         } else {
115             $this->filter = false;
116         }
117     }
118
119     /**
120      * Validate that $pattern is a valid regular expression.
121      *
122      * @param string $pattern
123      *
124      * @return bool
125      */
126     private function validateRegex($pattern)
127     {
128         set_error_handler(array('Psy\Exception\ErrorException', 'throwException'));
129         try {
130             preg_match($pattern, '');
131         } catch (ErrorException $e) {
132             throw new RuntimeException(str_replace('preg_match(): ', 'Invalid regular expression: ', $e->getRawMessage()));
133         }
134         restore_error_handler();
135     }
136
137     protected function presentSignature($target)
138     {
139         // This might get weird if the signature is actually for a reflector. Hrm.
140         if (!$target instanceof \Reflector) {
141             $target = Mirror::get($target);
142         }
143
144         return SignatureFormatter::format($target);
145     }
146 }