1: <?php
2:
3: /*
4: * This file is part of the Symfony package.
5: *
6: * (c) Fabien Potencier <fabien@symfony.com>
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 Symfony\Component\Finder\Expression;
13:
14: /**
15: * @author Jean-François Simon <contact@jfsimon.fr>
16: */
17: class Glob implements ValueInterface
18: {
19: /**
20: * @var string
21: */
22: private $pattern;
23:
24: /**
25: * @param string $pattern
26: */
27: public function __construct($pattern)
28: {
29: $this->pattern = $pattern;
30: }
31:
32: /**
33: * {@inheritdoc}
34: */
35: public function render()
36: {
37: return $this->pattern;
38: }
39:
40: /**
41: * {@inheritdoc}
42: */
43: public function renderPattern()
44: {
45: return $this->pattern;
46: }
47:
48: /**
49: * {@inheritdoc}
50: */
51: public function getType()
52: {
53: return Expression::TYPE_GLOB;
54: }
55:
56: /**
57: * {@inheritdoc}
58: */
59: public function isCaseSensitive()
60: {
61: return true;
62: }
63:
64: /**
65: * {@inheritdoc}
66: */
67: public function prepend($expr)
68: {
69: $this->pattern = $expr.$this->pattern;
70:
71: return $this;
72: }
73:
74: /**
75: * {@inheritdoc}
76: */
77: public function append($expr)
78: {
79: $this->pattern .= $expr;
80:
81: return $this;
82: }
83:
84: /**
85: * Tests if glob is expandable ("*.{a,b}" syntax).
86: *
87: * @return bool
88: */
89: public function isExpandable()
90: {
91: return false !== strpos($this->pattern, '{')
92: && false !== strpos($this->pattern, '}');
93: }
94:
95: /**
96: * @param bool $strictLeadingDot
97: * @param bool $strictWildcardSlash
98: *
99: * @return Regex
100: */
101: public function toRegex($strictLeadingDot = true, $strictWildcardSlash = true)
102: {
103: $firstByte = true;
104: $escaping = false;
105: $inCurlies = 0;
106: $regex = '';
107: $sizeGlob = strlen($this->pattern);
108: for ($i = 0; $i < $sizeGlob; $i++) {
109: $car = $this->pattern[$i];
110: if ($firstByte) {
111: if ($strictLeadingDot && '.' !== $car) {
112: $regex .= '(?=[^\.])';
113: }
114:
115: $firstByte = false;
116: }
117:
118: if ('/' === $car) {
119: $firstByte = true;
120: }
121:
122: if ('.' === $car || '(' === $car || ')' === $car || '|' === $car || '+' === $car || '^' === $car || '$' === $car) {
123: $regex .= "\\$car";
124: } elseif ('*' === $car) {
125: $regex .= $escaping ? '\\*' : ($strictWildcardSlash ? '[^/]*' : '.*');
126: } elseif ('?' === $car) {
127: $regex .= $escaping ? '\\?' : ($strictWildcardSlash ? '[^/]' : '.');
128: } elseif ('{' === $car) {
129: $regex .= $escaping ? '\\{' : '(';
130: if (!$escaping) {
131: ++$inCurlies;
132: }
133: } elseif ('}' === $car && $inCurlies) {
134: $regex .= $escaping ? '}' : ')';
135: if (!$escaping) {
136: --$inCurlies;
137: }
138: } elseif (',' === $car && $inCurlies) {
139: $regex .= $escaping ? ',' : '|';
140: } elseif ('\\' === $car) {
141: if ($escaping) {
142: $regex .= '\\\\';
143: $escaping = false;
144: } else {
145: $escaping = true;
146: }
147:
148: continue;
149: } else {
150: $regex .= $car;
151: }
152: $escaping = false;
153: }
154:
155: return new Regex('^'.$regex.'$');
156: }
157: }
158: