|
0
|
1 |
<?php |
|
|
2 |
|
|
|
3 |
/* |
|
|
4 |
* Copyright 2010 Johannes M. Schmitt <schmittjoh@gmail.com> |
|
|
5 |
* |
|
|
6 |
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
|
7 |
* you may not use this file except in compliance with the License. |
|
|
8 |
* You may obtain a copy of the License at |
|
|
9 |
* |
|
|
10 |
* http://www.apache.org/licenses/LICENSE-2.0 |
|
|
11 |
* |
|
|
12 |
* Unless required by applicable law or agreed to in writing, software |
|
|
13 |
* distributed under the License is distributed on an "AS IS" BASIS, |
|
|
14 |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
|
15 |
* See the License for the specific language governing permissions and |
|
|
16 |
* limitations under the License. |
|
|
17 |
*/ |
|
|
18 |
|
|
|
19 |
namespace JMS\SecurityExtraBundle\Generator; |
|
|
20 |
|
|
|
21 |
use JMS\SecurityExtraBundle\Metadata\MethodMetadata; |
|
|
22 |
use JMS\SecurityExtraBundle\Metadata\ServiceMetadata; |
|
|
23 |
use Symfony\Component\DependencyInjection\Definition; |
|
|
24 |
use \ReflectionClass; |
|
|
25 |
use \ReflectionMethod; |
|
|
26 |
|
|
|
27 |
/** |
|
|
28 |
* Generates the proxy class which has security checks built-in according to |
|
|
29 |
* the given metadata information. |
|
|
30 |
* |
|
|
31 |
* @author Johannes M. Schmitt <schmittjoh@gmail.com> |
|
|
32 |
* |
|
|
33 |
*/ |
|
|
34 |
class ProxyClassGenerator |
|
|
35 |
{ |
|
|
36 |
private $classCount = array(); |
|
|
37 |
|
|
|
38 |
/** |
|
|
39 |
* Generates the proxy class |
|
|
40 |
* |
|
|
41 |
* @param Definition $definition |
|
|
42 |
* @param ServiceMetadata $metadata |
|
|
43 |
* @return array<string, string> |
|
|
44 |
*/ |
|
|
45 |
public function generate(Definition $definition, ServiceMetadata $metadata) |
|
|
46 |
{ |
|
|
47 |
list($className, $proxy) = $this->getClassDefinition($definition); |
|
|
48 |
foreach ($metadata->methodMetadata as $name => $method) { |
|
|
49 |
$reflection = $method->reflection; |
|
|
50 |
|
|
|
51 |
$proxy .= $this->getMethodDefinition($reflection); |
|
|
52 |
|
|
|
53 |
$proxy .= ' static $jmsSecurityExtra__metadata = '.$this->getMethodSecurityMetadata($method).'; |
|
|
54 |
|
|
|
55 |
'; |
|
|
56 |
|
|
|
57 |
$proxy .= ' return '; |
|
|
58 |
|
|
|
59 |
$proxy .= '$this->jmsSecurityExtraBundle__methodSecurityInterceptor->invoke( |
|
|
60 |
'; |
|
|
61 |
$proxy .= ' '.$this->getSecureMethodInvocation($method).', |
|
|
62 |
'; |
|
|
63 |
$proxy .= ' $jmsSecurityExtra__metadata |
|
|
64 |
'; |
|
|
65 |
$proxy .= ' );'; |
|
|
66 |
|
|
|
67 |
$proxy .= ' |
|
|
68 |
} |
|
|
69 |
|
|
|
70 |
'; |
|
|
71 |
} |
|
|
72 |
|
|
|
73 |
return array($className, substr($proxy, 0, -6).'}'); |
|
|
74 |
} |
|
|
75 |
|
|
|
76 |
private function getMethodSecurityMetadata(MethodMetadata $method) |
|
|
77 |
{ |
|
|
78 |
$metadata = var_export($method->getAsArray(), true); |
|
|
79 |
|
|
|
80 |
$staticReplaces = array( |
|
|
81 |
"\n" => '', |
|
|
82 |
'array (' => 'array(', |
|
|
83 |
); |
|
|
84 |
$metadata = strtr($metadata, $staticReplaces); |
|
|
85 |
|
|
|
86 |
$regexReplaces = array( |
|
|
87 |
'/\s+/' => ' ', |
|
|
88 |
'/\(\s+/' => '(', |
|
|
89 |
'/[0-9]+\s+=>\s+/' => '', |
|
|
90 |
'/,\s*\)/' => ')', |
|
|
91 |
); |
|
|
92 |
$metadata = preg_replace(array_keys($regexReplaces), array_values($regexReplaces), $metadata); |
|
|
93 |
|
|
|
94 |
return $metadata; |
|
|
95 |
} |
|
|
96 |
|
|
|
97 |
private function getSecureMethodInvocation(MethodMetadata $method) |
|
|
98 |
{ |
|
|
99 |
$code = 'new MethodInvocation(' |
|
|
100 |
.var_export($method->reflection->getDeclaringClass()->getName(), true) |
|
|
101 |
.', '.var_export($method->reflection->getName(), true) |
|
|
102 |
.', $this' |
|
|
103 |
.', array('; |
|
|
104 |
|
|
|
105 |
$arguments = array(); |
|
|
106 |
foreach ($method->reflection->getParameters() as $param) { |
|
|
107 |
$arguments[] = '$'.$param->getName(); |
|
|
108 |
} |
|
|
109 |
$code .= implode(', ', $arguments).'))'; |
|
|
110 |
|
|
|
111 |
return $code; |
|
|
112 |
} |
|
|
113 |
|
|
|
114 |
private function getClassDefinition(Definition $definition) |
|
|
115 |
{ |
|
|
116 |
$baseClass = $definition->getClass(); |
|
|
117 |
if (false !== $pos = strrpos($baseClass, '\\')) { |
|
|
118 |
$className = substr($baseClass, $pos + 1); |
|
|
119 |
} else { |
|
|
120 |
$className = $baseClass; |
|
|
121 |
} |
|
|
122 |
|
|
|
123 |
if (isset($this->classCount[$className])) { |
|
|
124 |
$className .= '_'.(++$this->classCount[$className]); |
|
|
125 |
} else { |
|
|
126 |
$this->classCount[$className] = 1; |
|
|
127 |
} |
|
|
128 |
|
|
|
129 |
$requiredFiles = ''; |
|
|
130 |
if (null !== $file = $definition->getFile()) { |
|
|
131 |
$requiredFiles .= sprintf("\nrequire_once %s;", var_export($definition->getFile(), true)); |
|
|
132 |
} |
|
|
133 |
if ('' !== $requiredFiles) { |
|
|
134 |
$requiredFiles .= "\n"; |
|
|
135 |
} |
|
|
136 |
|
|
|
137 |
return array($className, sprintf('<?php |
|
|
138 |
|
|
|
139 |
namespace SecurityProxies; |
|
|
140 |
|
|
|
141 |
use JMS\SecurityExtraBundle\Security\Authorization\Interception\MethodInvocation; |
|
|
142 |
use JMS\SecurityExtraBundle\Security\Authorization\Interception\MethodSecurityInterceptor; |
|
|
143 |
%s |
|
|
144 |
/** |
|
|
145 |
* This class has been auto-generated. Manual changes will be lost. |
|
|
146 |
* Last updated at '.date('r').' |
|
|
147 |
* |
|
|
148 |
* @author Johannes M. Schmitt <schmittjoh@gmail.com> |
|
|
149 |
*/ |
|
|
150 |
class %s extends \%s |
|
|
151 |
{ |
|
|
152 |
private $jmsSecurityExtraBundle__methodSecurityInterceptor; |
|
|
153 |
|
|
|
154 |
public function jmsSecurityExtraBundle__setMethodSecurityInterceptor(MethodSecurityInterceptor $interceptor) |
|
|
155 |
{ |
|
|
156 |
$this->jmsSecurityExtraBundle__methodSecurityInterceptor = $interceptor; |
|
|
157 |
} |
|
|
158 |
|
|
|
159 |
', $requiredFiles, $className, $baseClass)); |
|
|
160 |
} |
|
|
161 |
|
|
|
162 |
private function getMethodDefinition(ReflectionMethod $method) |
|
|
163 |
{ |
|
|
164 |
$def = ''; |
|
|
165 |
if ($method->isProtected()) { |
|
|
166 |
$def .= 'protected '; |
|
|
167 |
} else { |
|
|
168 |
$def .= 'public '; |
|
|
169 |
} |
|
|
170 |
|
|
|
171 |
if ($method->isStatic()) { |
|
|
172 |
$def .= 'static '; |
|
|
173 |
} |
|
|
174 |
|
|
|
175 |
if ($method->returnsReference()) { |
|
|
176 |
$def .= '&'; |
|
|
177 |
} |
|
|
178 |
|
|
|
179 |
$def .= 'function '.$method->getName().'('; |
|
|
180 |
$parameters = $method->getParameters(); |
|
|
181 |
foreach ($parameters as $param) { |
|
|
182 |
if (null !== $class = $param->getClass()) { |
|
|
183 |
$def .= '\\'.$class->getName().' '; |
|
|
184 |
} else if ($param->isArray()) { |
|
|
185 |
$def .= 'array '; |
|
|
186 |
} |
|
|
187 |
|
|
|
188 |
if ($param->isPassedByReference()) { |
|
|
189 |
$def .= '&'; |
|
|
190 |
} |
|
|
191 |
|
|
|
192 |
$def .= '$'.$param->getName(); |
|
|
193 |
|
|
|
194 |
if ($param->isOptional()) { |
|
|
195 |
$def .= ' = '.var_export($param->getDefaultValue(), true); |
|
|
196 |
} |
|
|
197 |
|
|
|
198 |
$def .= ', '; |
|
|
199 |
} |
|
|
200 |
|
|
|
201 |
if (count($parameters) > 0) { |
|
|
202 |
$def = substr($def, 0, -2); |
|
|
203 |
} |
|
|
204 |
|
|
|
205 |
$def .= ') |
|
|
206 |
{ |
|
|
207 |
'; |
|
|
208 |
|
|
|
209 |
return $def; |
|
|
210 |
} |
|
|
211 |
} |