1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* Prado command line developer tools. |
5
|
|
|
* |
6
|
|
|
* @author Wei Zhuo <weizhuo[at]gmail[dot]com> |
7
|
|
|
* @link https://github.com/pradosoft/prado |
8
|
|
|
* @license https://github.com/pradosoft/prado/blob/master/LICENSE |
9
|
|
|
*/ |
10
|
|
|
|
11
|
|
|
if (!isset($_SERVER['argv']) || php_sapi_name() !== 'cli') { |
12
|
|
|
die('Must be run from the command line'); |
13
|
|
|
} |
14
|
|
|
|
15
|
|
|
// Locate composer's autoloader |
16
|
|
|
if (file_exists($autoloader = realpath(__DIR__ . '/../vendor/autoload.php'))) { |
17
|
|
|
// if we are running inside a prado repo checkout, get out of bin/ |
18
|
|
|
include($autoloader); |
19
|
|
|
} elseif (file_exists($autoloader = realpath(__DIR__ . '/../../../autoload.php'))) { |
20
|
|
|
// if we are running from inside an application's vendor/ directory, get out of pradosoft/prado/bin/ |
21
|
|
|
include($autoloader); |
22
|
|
|
} |
23
|
|
|
|
24
|
|
|
use Prado\TApplication; |
25
|
|
|
use Prado\Prado; |
26
|
|
|
|
27
|
|
|
//stub application class |
28
|
|
|
class PradoShellApplication extends TApplication |
29
|
|
|
{ |
30
|
|
|
public function run() |
31
|
|
|
{ |
32
|
|
|
$this->initApplication(); |
33
|
|
|
} |
34
|
|
|
} |
35
|
|
|
|
36
|
|
|
restore_exception_handler(); |
37
|
|
|
|
38
|
|
|
|
39
|
|
|
//register action classes |
40
|
|
|
PradoCommandLineInterpreter::getInstance()->addActionClass('PradoCommandLineCreateProject'); |
41
|
|
|
PradoCommandLineInterpreter::getInstance()->addActionClass('PradoCommandLineCreateTests'); |
42
|
|
|
PradoCommandLineInterpreter::getInstance()->addActionClass('PradoCommandLinePhpShell'); |
43
|
|
|
PradoCommandLineInterpreter::getInstance()->addActionClass('PradoCommandLineActiveRecordGen'); |
44
|
|
|
PradoCommandLineInterpreter::getInstance()->addActionClass('PradoCommandLineActiveRecordGenAll'); |
45
|
|
|
|
46
|
|
|
//run it; |
47
|
|
|
PradoCommandLineInterpreter::getInstance()->run($_SERVER['argv']); |
48
|
|
|
|
49
|
|
|
/**************** END CONFIGURATION **********************/ |
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* PradoCommandLineInterpreter Class |
53
|
|
|
* |
54
|
|
|
* Command line interface, configures the action classes and dispatches the command actions. |
55
|
|
|
* |
56
|
|
|
* @author Wei Zhuo <weizhuo[at]gmail[dot]com> |
57
|
|
|
* @since 3.0.5 |
58
|
|
|
*/ |
59
|
|
|
class PradoCommandLineInterpreter |
60
|
|
|
{ |
61
|
|
|
/** |
62
|
|
|
* @var array command action classes |
63
|
|
|
*/ |
64
|
|
|
protected $_actions = []; |
65
|
|
|
|
66
|
|
|
/** |
67
|
|
|
* @param string $class action class name |
68
|
|
|
*/ |
69
|
|
|
public function addActionClass($class) |
70
|
|
|
{ |
71
|
|
|
$this->_actions[$class] = new $class; |
72
|
|
|
} |
73
|
|
|
|
74
|
|
|
/** |
75
|
|
|
* @return PradoCommandLineInterpreter static instance |
76
|
|
|
*/ |
77
|
|
|
public static function getInstance() |
78
|
|
|
{ |
79
|
|
|
static $instance; |
80
|
|
|
if ($instance === null) { |
81
|
|
|
$instance = new self; |
82
|
|
|
} |
83
|
|
|
return $instance; |
84
|
|
|
} |
85
|
|
|
|
86
|
|
|
public static function printGreeting() |
87
|
|
|
{ |
88
|
|
|
echo "Command line tools for Prado " . Prado::getVersion() . ".\n"; |
89
|
|
|
} |
90
|
|
|
|
91
|
|
|
/** |
92
|
|
|
* Dispatch the command line actions. |
93
|
|
|
* @param array $args command line arguments |
94
|
|
|
*/ |
95
|
|
|
public function run($args) |
96
|
|
|
{ |
97
|
|
|
if (count($args) > 1) { |
98
|
|
|
array_shift($args); |
99
|
|
|
} |
100
|
|
|
$valid = false; |
101
|
|
|
foreach ($this->_actions as $class => $action) { |
102
|
|
|
if ($action->isValidAction($args)) { |
103
|
|
|
$valid |= $action->performAction($args); |
104
|
|
|
break; |
105
|
|
|
} else { |
106
|
|
|
$valid = false; |
107
|
|
|
} |
108
|
|
|
} |
109
|
|
|
if (!$valid) { |
|
|
|
|
110
|
|
|
$this->printHelp(); |
111
|
|
|
} |
112
|
|
|
} |
113
|
|
|
|
114
|
|
|
/** |
115
|
|
|
* Print command line help, default action. |
116
|
|
|
*/ |
117
|
|
|
public function printHelp() |
118
|
|
|
{ |
119
|
|
|
PradoCommandLineInterpreter::printGreeting(); |
120
|
|
|
|
121
|
|
|
echo "usage: php prado-cli.php action <parameter> [optional]\n"; |
122
|
|
|
echo "example: php prado-cli.php -c mysite\n\n"; |
123
|
|
|
echo "actions:\n"; |
124
|
|
|
foreach ($this->_actions as $action) { |
125
|
|
|
echo $action->renderHelp(); |
126
|
|
|
} |
127
|
|
|
} |
128
|
|
|
} |
129
|
|
|
|
130
|
|
|
/** |
131
|
|
|
* Base class for command line actions. |
132
|
|
|
* |
133
|
|
|
* @author Wei Zhuo <weizhuo[at]gmail[dot]com> |
134
|
|
|
* @since 3.0.5 |
135
|
|
|
*/ |
136
|
|
|
abstract class PradoCommandLineAction |
137
|
|
|
{ |
138
|
|
|
/** |
139
|
|
|
* Execute the action. |
140
|
|
|
* @param array $args command line parameters |
141
|
|
|
* @return bool true if action was handled |
142
|
|
|
*/ |
143
|
|
|
abstract public function performAction($args); |
144
|
|
|
|
145
|
|
|
/** |
146
|
|
|
* Creates a directory and sets its mode |
147
|
|
|
* @param string $dir directory name |
148
|
|
|
* @param int $mask directory mode mask suitable for chmod() |
149
|
|
|
*/ |
150
|
|
|
protected function createDirectory($dir, $mask) |
151
|
|
|
{ |
152
|
|
|
if (!is_dir($dir)) { |
153
|
|
|
mkdir($dir); |
154
|
|
|
echo "creating $dir\n"; |
155
|
|
|
} |
156
|
|
|
if (is_dir($dir)) { |
157
|
|
|
chmod($dir, $mask); |
158
|
|
|
} |
159
|
|
|
} |
160
|
|
|
|
161
|
|
|
/** |
162
|
|
|
* Creates a file and fills it with content |
163
|
|
|
* @param string $filename file name |
164
|
|
|
* @param int $content file contents |
165
|
|
|
*/ |
166
|
|
|
protected function createFile($filename, $content) |
167
|
|
|
{ |
168
|
|
|
if (!is_file($filename)) { |
169
|
|
|
file_put_contents($filename, $content); |
170
|
|
|
echo "creating $filename\n"; |
171
|
|
|
} |
172
|
|
|
} |
173
|
|
|
|
174
|
|
|
/** |
175
|
|
|
* Checks if specified parameters are suitable for the specified action |
176
|
|
|
* @param array $args parameters |
177
|
|
|
* @return bool |
178
|
|
|
*/ |
179
|
|
|
public function isValidAction($args) |
180
|
|
|
{ |
181
|
|
|
return 0 == strcasecmp($args[0], $this->action) && |
182
|
|
|
count($args) - 1 >= count($this->parameters); |
183
|
|
|
} |
184
|
|
|
|
185
|
|
|
/** |
186
|
|
|
* @return string |
187
|
|
|
*/ |
188
|
|
|
public function renderHelp() |
189
|
|
|
{ |
190
|
|
|
$params = []; |
191
|
|
|
foreach ($this->parameters as $v) { |
192
|
|
|
$params[] = '<' . $v . '>'; |
193
|
|
|
} |
194
|
|
|
$parameters = implode($params, ' '); |
|
|
|
|
195
|
|
|
$options = []; |
196
|
|
|
foreach ($this->optional as $v) { |
197
|
|
|
$options[] = '[' . $v . ']'; |
198
|
|
|
} |
199
|
|
|
$optional = (strlen($parameters) ? ' ' : '') . implode($options, ' '); |
200
|
|
|
$description = ''; |
201
|
|
|
foreach (explode("\n", wordwrap($this->description, 65)) as $line) { |
202
|
|
|
$description .= ' ' . $line . "\n"; |
203
|
|
|
} |
204
|
|
|
return <<<EOD |
205
|
|
|
{$this->action} {$parameters}{$optional} |
206
|
|
|
{$description} |
207
|
|
|
|
208
|
|
|
EOD; |
209
|
|
|
} |
210
|
|
|
|
211
|
|
|
/** |
212
|
|
|
* Initalize a Prado application inside the specified directory |
213
|
|
|
* @param string $directory directory name |
214
|
|
|
* @return false|TApplication |
215
|
|
|
*/ |
216
|
|
|
protected function initializePradoApplication($directory) |
217
|
|
|
{ |
218
|
|
|
$_SERVER['SCRIPT_FILENAME'] = $directory . '/index.php'; |
219
|
|
|
$app_dir = realpath($directory . '/protected/'); |
220
|
|
|
if ($app_dir !== false && is_dir($app_dir)) { |
221
|
|
|
if (Prado::getApplication() === null) { |
222
|
|
|
$app = new PradoShellApplication($app_dir); |
223
|
|
|
$app->run(); |
224
|
|
|
$dir = substr(str_replace(realpath('./'), '', $app_dir), 1); |
225
|
|
|
PradoCommandLineInterpreter::printGreeting(); |
226
|
|
|
echo '** Loaded PRADO appplication in directory "' . $dir . "\".\n"; |
227
|
|
|
} |
228
|
|
|
|
229
|
|
|
return Prado::getApplication(); |
230
|
|
|
} else { |
231
|
|
|
PradoCommandLineInterpreter::printGreeting(); |
232
|
|
|
echo '+' . str_repeat('-', 77) . "+\n"; |
233
|
|
|
echo '** Unable to load PRADO application in directory "' . $directory . "\".\n"; |
234
|
|
|
echo '+' . str_repeat('-', 77) . "+\n"; |
235
|
|
|
} |
236
|
|
|
return false; |
237
|
|
|
} |
238
|
|
|
} |
239
|
|
|
|
240
|
|
|
/** |
241
|
|
|
* Create a Prado project skeleton, including directories and files. |
242
|
|
|
* |
243
|
|
|
* @author Wei Zhuo <weizhuo[at]gmail[dot]com> |
244
|
|
|
* @since 3.0.5 |
245
|
|
|
*/ |
246
|
|
|
class PradoCommandLineCreateProject extends PradoCommandLineAction |
247
|
|
|
{ |
248
|
|
|
protected $action = '-c'; |
249
|
|
|
protected $parameters = ['directory']; |
250
|
|
|
protected $optional = []; |
251
|
|
|
protected $description = 'Creates a Prado project skeleton for the given <directory>.'; |
252
|
|
|
|
253
|
|
|
/** |
254
|
|
|
* @param array $args parameters |
255
|
|
|
* @return bool |
256
|
|
|
*/ |
257
|
|
|
public function performAction($args) |
258
|
|
|
{ |
259
|
|
|
PradoCommandLineInterpreter::printGreeting(); |
260
|
|
|
$this->createNewPradoProject($args[1]); |
261
|
|
|
return true; |
262
|
|
|
} |
263
|
|
|
|
264
|
|
|
/** |
265
|
|
|
* Functions to create new prado project. |
266
|
|
|
* @param mixed $dir |
267
|
|
|
*/ |
268
|
|
|
protected function createNewPradoProject($dir) |
269
|
|
|
{ |
270
|
|
|
if (strlen(trim($dir)) == 0) { |
271
|
|
|
return; |
272
|
|
|
} |
273
|
|
|
|
274
|
|
|
$rootPath = realpath(dirname(trim($dir))); |
275
|
|
|
|
276
|
|
|
if (basename($dir) !== '.') { |
277
|
|
|
$basePath = $rootPath . DIRECTORY_SEPARATOR . basename($dir); |
278
|
|
|
} else { |
279
|
|
|
$basePath = $rootPath; |
280
|
|
|
} |
281
|
|
|
$appName = basename($basePath); |
282
|
|
|
$assetPath = $basePath . DIRECTORY_SEPARATOR . 'assets'; |
283
|
|
|
$protectedPath = $basePath . DIRECTORY_SEPARATOR . 'protected'; |
284
|
|
|
$runtimePath = $basePath . DIRECTORY_SEPARATOR . 'protected' . DIRECTORY_SEPARATOR . 'runtime'; |
285
|
|
|
$pagesPath = $protectedPath . DIRECTORY_SEPARATOR . 'pages'; |
286
|
|
|
|
287
|
|
|
$indexFile = $basePath . DIRECTORY_SEPARATOR . 'index.php'; |
288
|
|
|
$htaccessFile = $protectedPath . DIRECTORY_SEPARATOR . '.htaccess'; |
289
|
|
|
$configFile = $protectedPath . DIRECTORY_SEPARATOR . 'application.xml'; |
290
|
|
|
$defaultPageFile = $pagesPath . DIRECTORY_SEPARATOR . 'Home.page'; |
291
|
|
|
|
292
|
|
|
$this->createDirectory($basePath, 0755); |
293
|
|
|
$this->createDirectory($assetPath, 0777); |
294
|
|
|
$this->createDirectory($protectedPath, 0755); |
295
|
|
|
$this->createDirectory($runtimePath, 0777); |
296
|
|
|
$this->createDirectory($pagesPath, 0755); |
297
|
|
|
|
298
|
|
|
$this->createFile($indexFile, $this->renderIndexFile()); |
|
|
|
|
299
|
|
|
$this->createFile($configFile, $this->renderConfigFile($appName)); |
|
|
|
|
300
|
|
|
$this->createFile($htaccessFile, $this->renderHtaccessFile()); |
301
|
|
|
$this->createFile($defaultPageFile, $this->renderDefaultPage()); |
302
|
|
|
} |
303
|
|
|
|
304
|
|
|
/** |
305
|
|
|
* @return string |
306
|
|
|
*/ |
307
|
|
|
protected function renderIndexFile() |
308
|
|
|
{ |
309
|
|
|
$framework = realpath(dirname(__DIR__)) . DIRECTORY_SEPARATOR . 'framework' . DIRECTORY_SEPARATOR . 'prado.php'; |
310
|
|
|
return '<?php |
311
|
|
|
|
312
|
|
|
$frameworkPath=\'' . $framework . '\'; |
313
|
|
|
|
314
|
|
|
// The following directory checks may be removed if performance is required |
315
|
|
|
$basePath=dirname(__FILE__); |
316
|
|
|
$assetsPath=$basePath.\'/assets\'; |
317
|
|
|
$runtimePath=$basePath.\'/protected/runtime\'; |
318
|
|
|
|
319
|
|
|
if(!is_file($frameworkPath)) |
320
|
|
|
die("Unable to find prado framework path $frameworkPath."); |
321
|
|
|
if(!is_writable($assetsPath)) |
322
|
|
|
die("Please make sure that the directory $assetsPath is writable by Web server process."); |
323
|
|
|
if(!is_writable($runtimePath)) |
324
|
|
|
die("Please make sure that the directory $runtimePath is writable by Web server process."); |
325
|
|
|
|
326
|
|
|
|
327
|
|
|
require_once($frameworkPath); |
328
|
|
|
|
329
|
|
|
$application=new TApplication; |
330
|
|
|
$application->run(); |
331
|
|
|
'; |
332
|
|
|
} |
333
|
|
|
|
334
|
|
|
/** |
335
|
|
|
* @param array $appName application id |
336
|
|
|
* @return string |
337
|
|
|
*/ |
338
|
|
|
protected function renderConfigFile($appName) |
339
|
|
|
{ |
340
|
|
|
return <<<EOD |
341
|
|
|
<?xml version="1.0" encoding="utf-8"?> |
342
|
|
|
|
343
|
|
|
<application id="$appName" mode="Debug"> |
344
|
|
|
<!-- alias definitions and namespace usings |
345
|
|
|
<paths> |
346
|
|
|
<alias id="myalias" path="./lib" /> |
347
|
|
|
<using namespace="Application.common.*" /> |
348
|
|
|
</paths> |
349
|
|
|
--> |
350
|
|
|
|
351
|
|
|
<!-- configurations for modules --> |
352
|
|
|
<modules> |
353
|
|
|
<!-- Remove this comment mark to enable caching |
354
|
|
|
<module id="cache" class="Prado\Caching\TDbCache" /> |
355
|
|
|
--> |
356
|
|
|
|
357
|
|
|
<!-- Remove this comment mark to enable PATH url format |
358
|
|
|
<module id="request" class="THttpRequest" UrlFormat="Path" /> |
359
|
|
|
--> |
360
|
|
|
|
361
|
|
|
<!-- Remove this comment mark to enable logging |
362
|
|
|
<module id="log" class="Prado\Util\TLogRouter"> |
363
|
|
|
<route class="TBrowserLogRoute" Categories="System" /> |
364
|
|
|
</module> |
365
|
|
|
--> |
366
|
|
|
</modules> |
367
|
|
|
|
368
|
|
|
<!-- configuration for available services --> |
369
|
|
|
<services> |
370
|
|
|
<service id="page" class="TPageService" DefaultPage="Home" /> |
371
|
|
|
</services> |
372
|
|
|
|
373
|
|
|
<!-- application parameters |
374
|
|
|
<parameters> |
375
|
|
|
<parameter id="param1" value="value1" /> |
376
|
|
|
<parameter id="param2" value="value2" /> |
377
|
|
|
</parameters> |
378
|
|
|
--> |
379
|
|
|
</application> |
380
|
|
|
EOD; |
381
|
|
|
} |
382
|
|
|
|
383
|
|
|
/** |
384
|
|
|
* @return string |
385
|
|
|
*/ |
386
|
|
|
protected function renderHtaccessFile() |
387
|
|
|
{ |
388
|
|
|
return 'deny from all'; |
389
|
|
|
} |
390
|
|
|
|
391
|
|
|
/** |
392
|
|
|
* @return string |
393
|
|
|
*/ |
394
|
|
|
protected function renderDefaultPage() |
395
|
|
|
{ |
396
|
|
|
return <<<EOD |
397
|
|
|
<html> |
398
|
|
|
<head> |
399
|
|
|
<title>Welcome to PRADO</title> |
400
|
|
|
</head> |
401
|
|
|
<body> |
402
|
|
|
<h1>Welcome to PRADO!</h1> |
403
|
|
|
</body> |
404
|
|
|
</html> |
405
|
|
|
EOD; |
406
|
|
|
} |
407
|
|
|
} |
408
|
|
|
|
409
|
|
|
/** |
410
|
|
|
* Creates test fixtures for a Prado application. |
411
|
|
|
* |
412
|
|
|
* @author Wei Zhuo <weizhuo[at]gmail[dot]com> |
413
|
|
|
* @since 3.0.5 |
414
|
|
|
*/ |
415
|
|
|
class PradoCommandLineCreateTests extends PradoCommandLineAction |
416
|
|
|
{ |
417
|
|
|
protected $action = '-t'; |
418
|
|
|
protected $parameters = ['directory']; |
419
|
|
|
protected $optional = []; |
420
|
|
|
protected $description = 'Create test fixtures in the given <directory>.'; |
421
|
|
|
|
422
|
|
|
/** |
423
|
|
|
* @param array $args parameters |
424
|
|
|
* @return bool |
425
|
|
|
*/ |
426
|
|
|
public function performAction($args) |
427
|
|
|
{ |
428
|
|
|
PradoCommandLineInterpreter::printGreeting(); |
429
|
|
|
$this->createTestFixtures($args[1]); |
430
|
|
|
return true; |
431
|
|
|
} |
432
|
|
|
|
433
|
|
|
/** |
434
|
|
|
* @param string $dir directory name |
435
|
|
|
*/ |
436
|
|
|
protected function createTestFixtures($dir) |
437
|
|
|
{ |
438
|
|
|
if (strlen(trim($dir)) == 0) { |
439
|
|
|
return; |
440
|
|
|
} |
441
|
|
|
|
442
|
|
|
$rootPath = realpath(dirname(trim($dir))); |
443
|
|
|
$basePath = $rootPath . '/' . basename($dir); |
444
|
|
|
|
445
|
|
|
$tests = $basePath . '/tests'; |
446
|
|
|
$unit_tests = $tests . '/unit'; |
447
|
|
|
$functional_tests = $tests . '/functional'; |
448
|
|
|
|
449
|
|
|
$this->createDirectory($tests, 0755); |
450
|
|
|
$this->createDirectory($unit_tests, 0755); |
451
|
|
|
$this->createDirectory($functional_tests, 0755); |
452
|
|
|
|
453
|
|
|
$unit_test_index = $tests . '/unit.php'; |
454
|
|
|
$functional_test_index = $tests . '/functional.php'; |
455
|
|
|
|
456
|
|
|
$this->createFile($unit_test_index, $this->renderUnitTestFixture()); |
|
|
|
|
457
|
|
|
$this->createFile($functional_test_index, $this->renderFunctionalTestFixture()); |
458
|
|
|
} |
459
|
|
|
|
460
|
|
|
/** |
461
|
|
|
* @return string |
462
|
|
|
*/ |
463
|
|
|
protected function renderUnitTestFixture() |
464
|
|
|
{ |
465
|
|
|
$tester = realpath(dirname(__DIR__)) . '/tests/test_tools/unit_tests.php'; |
466
|
|
|
return '<?php |
467
|
|
|
|
468
|
|
|
include_once \'' . $tester . '\'; |
469
|
|
|
|
470
|
|
|
$app_directory = "../protected"; |
471
|
|
|
$test_cases = dirname(__FILE__)."/unit"; |
472
|
|
|
|
473
|
|
|
$tester = new PradoUnitTester($test_cases, $app_directory); |
474
|
|
|
$tester->run(new HtmlReporter()); |
475
|
|
|
'; |
476
|
|
|
} |
477
|
|
|
|
478
|
|
|
/** |
479
|
|
|
* @return string |
480
|
|
|
*/ |
481
|
|
|
protected function renderFunctionalTestFixture() |
482
|
|
|
{ |
483
|
|
|
$tester = realpath(dirname(__DIR__)) . '/tests/test_tools/functional_tests.php'; |
484
|
|
|
return '<?php |
485
|
|
|
|
486
|
|
|
include_once \'' . $tester . '\'; |
487
|
|
|
|
488
|
|
|
$test_cases = dirname(__FILE__)."/functional"; |
489
|
|
|
|
490
|
|
|
$tester=new PradoFunctionalTester($test_cases); |
491
|
|
|
$tester->run(new SimpleReporter()); |
492
|
|
|
'; |
493
|
|
|
} |
494
|
|
|
} |
495
|
|
|
|
496
|
|
|
/** |
497
|
|
|
* Creates and run a Prado application in a PHP Shell. |
498
|
|
|
* |
499
|
|
|
* @author Wei Zhuo <weizhuo[at]gmail[dot]com> |
500
|
|
|
* @since 3.0.5 |
501
|
|
|
*/ |
502
|
|
|
class PradoCommandLinePhpShell extends PradoCommandLineAction |
503
|
|
|
{ |
504
|
|
|
protected $action = 'shell'; |
505
|
|
|
protected $parameters = []; |
506
|
|
|
protected $optional = ['directory']; |
507
|
|
|
protected $description = 'Runs a PHP interactive interpreter. Initializes the Prado application in the given [directory].'; |
508
|
|
|
|
509
|
|
|
/** |
510
|
|
|
* @param array $args parameters |
511
|
|
|
* @return bool |
512
|
|
|
*/ |
513
|
|
|
public function performAction($args) |
514
|
|
|
{ |
515
|
|
|
if (count($args) > 1) { |
516
|
|
|
$this->initializePradoApplication($args[1]); |
517
|
|
|
} |
518
|
|
|
|
519
|
|
|
\Psy\debug([], Prado::getApplication()); |
520
|
|
|
return true; |
521
|
|
|
} |
522
|
|
|
} |
523
|
|
|
|
524
|
|
|
/** |
525
|
|
|
* Create active record skeleton |
526
|
|
|
* |
527
|
|
|
* @author Wei Zhuo <weizhuo[at]gmail[dot]com> |
528
|
|
|
* @since 3.1 |
529
|
|
|
*/ |
530
|
|
|
class PradoCommandLineActiveRecordGen extends PradoCommandLineAction |
531
|
|
|
{ |
532
|
|
|
protected $action = 'generate'; |
533
|
|
|
protected $parameters = ['table', 'output']; |
534
|
|
|
protected $optional = ['directory', 'soap']; |
535
|
|
|
protected $description = 'Generate Active Record skeleton for <table> to <output> file using application.xml in [directory]. May also generate [soap] properties.'; |
536
|
|
|
private $_soap = false; |
537
|
|
|
|
538
|
|
|
/** |
539
|
|
|
* @param array $args parameters |
540
|
|
|
* @return bool |
541
|
|
|
*/ |
542
|
|
|
public function performAction($args) |
543
|
|
|
{ |
544
|
|
|
$app_dir = count($args) > 3 ? $this->getAppDir($args[3]) : $this->getAppDir(); |
545
|
|
|
$this->_soap = count($args) > 4; |
546
|
|
|
if ($app_dir !== false) { |
547
|
|
|
$config = $this->getActiveRecordConfig($app_dir); |
548
|
|
|
$output = $this->getOutputFile($app_dir, $args[2]); |
549
|
|
|
if (is_file($output)) { |
|
|
|
|
550
|
|
|
echo "** File $output already exists, skiping. \n"; |
551
|
|
|
} elseif ($config !== false && $output !== false) { |
|
|
|
|
552
|
|
|
$this->generateActiveRecord($config, $args[1], $output); |
553
|
|
|
} |
554
|
|
|
} |
555
|
|
|
return true; |
556
|
|
|
} |
557
|
|
|
|
558
|
|
|
/** |
559
|
|
|
* @param string $dir application directory |
560
|
|
|
* @return false|string |
561
|
|
|
*/ |
562
|
|
|
protected function getAppDir($dir = ".") |
563
|
|
|
{ |
564
|
|
|
if (is_dir($dir)) { |
565
|
|
|
return realpath($dir); |
566
|
|
|
} |
567
|
|
|
if (false !== ($app_dir = realpath($dir . '/protected/')) && is_dir($app_dir)) { |
568
|
|
|
return $app_dir; |
569
|
|
|
} |
570
|
|
|
echo '** Unable to find directory "' . $dir . "\".\n"; |
571
|
|
|
return false; |
572
|
|
|
} |
573
|
|
|
|
574
|
|
|
/** |
575
|
|
|
* @param string $app_dir application directory |
576
|
|
|
* @return false|string |
577
|
|
|
*/ |
578
|
|
|
protected function getXmlFile($app_dir) |
579
|
|
|
{ |
580
|
|
|
if (false !== ($xml = realpath($app_dir . '/application.xml')) && is_file($xml)) { |
581
|
|
|
return $xml; |
582
|
|
|
} |
583
|
|
|
if (false !== ($xml = realpath($app_dir . '/protected/application.xml')) && is_file($xml)) { |
584
|
|
|
return $xml; |
585
|
|
|
} |
586
|
|
|
echo '** Unable to find application.xml in ' . $app_dir . "\n"; |
587
|
|
|
return false; |
588
|
|
|
} |
589
|
|
|
|
590
|
|
|
/** |
591
|
|
|
* @param string $app_dir application directory |
592
|
|
|
* @return false|string |
593
|
|
|
*/ |
594
|
|
|
protected function getActiveRecordConfig($app_dir) |
595
|
|
|
{ |
596
|
|
|
if (false === ($xml = $this->getXmlFile($app_dir))) { |
597
|
|
|
return false; |
598
|
|
|
} |
599
|
|
|
if (false !== ($app = $this->initializePradoApplication($app_dir))) { |
600
|
|
|
Prado::using('Prado\Data\ActiveRecord\TActiveRecordConfig'); |
601
|
|
|
foreach ($app->getModules() as $module) { |
602
|
|
|
if ($module instanceof TActiveRecordConfig) { |
|
|
|
|
603
|
|
|
return $module; |
604
|
|
|
} |
605
|
|
|
} |
606
|
|
|
echo '** Unable to find TActiveRecordConfig module in ' . $xml . "\n"; |
607
|
|
|
} |
608
|
|
|
return false; |
609
|
|
|
} |
610
|
|
|
|
611
|
|
|
/** |
612
|
|
|
* @param string $app_dir application directory |
613
|
|
|
* @param string $namespace output file in namespace format |
614
|
|
|
* @return false|string |
615
|
|
|
*/ |
616
|
|
|
protected function getOutputFile($app_dir, $namespace) |
617
|
|
|
{ |
618
|
|
|
if (is_file($namespace) && strpos($namespace, $app_dir) === 0) { |
619
|
|
|
return $namespace; |
620
|
|
|
} |
621
|
|
|
$file = Prado::getPathOfNamespace($namespace, ".php"); |
622
|
|
|
if ($file !== null && false !== ($path = realpath(dirname($file))) && is_dir($path)) { |
623
|
|
|
if (strpos($path, $app_dir) === 0) { |
624
|
|
|
return $file; |
625
|
|
|
} |
626
|
|
|
} |
627
|
|
|
echo '** Output file ' . $file . ' must be within directory ' . $app_dir . "\n"; |
628
|
|
|
return false; |
629
|
|
|
} |
630
|
|
|
|
631
|
|
|
/** |
632
|
|
|
* @param string $config database configuration |
633
|
|
|
* @param string $tablename table name |
634
|
|
|
* @param string $output output file name |
635
|
|
|
* @return bool |
636
|
|
|
*/ |
637
|
|
|
protected function generateActiveRecord($config, $tablename, $output) |
638
|
|
|
{ |
639
|
|
|
$manager = TActiveRecordManager::getInstance(); |
|
|
|
|
640
|
|
|
if ($manager->getDbConnection()) { |
641
|
|
|
$gateway = $manager->getRecordGateway(); |
642
|
|
|
$tableInfo = $gateway->getTableInfo($manager->getDbConnection(), $tablename); |
643
|
|
|
if (count($tableInfo->getColumns()) === 0) { |
644
|
|
|
echo '** Unable to find table or view "' . $tablename . '" in "' . $manager->getDbConnection()->getConnectionString() . "\".\n"; |
645
|
|
|
return false; |
646
|
|
|
} else { |
647
|
|
|
$properties = []; |
648
|
|
|
foreach ($tableInfo->getColumns() as $field => $column) { |
649
|
|
|
$properties[] = $this->generateProperty($field, $column); |
650
|
|
|
} |
651
|
|
|
} |
652
|
|
|
|
653
|
|
|
$classname = basename($output, '.php'); |
654
|
|
|
$class = $this->generateClass($properties, $tablename, $classname); |
655
|
|
|
echo " Writing class $classname to file $output\n"; |
656
|
|
|
file_put_contents($output, $class); |
657
|
|
|
} else { |
658
|
|
|
echo '** Unable to connect to database with ConnectionID=\'' . $config->getConnectionID() . "'. Please check your settings in application.xml and ensure your database connection is set up first.\n"; |
659
|
|
|
} |
660
|
|
|
} |
661
|
|
|
|
662
|
|
|
/** |
663
|
|
|
* @param string $field php variable name |
664
|
|
|
* @param string $column database column name |
665
|
|
|
* @return string |
666
|
|
|
*/ |
667
|
|
|
protected function generateProperty($field, $column) |
668
|
|
|
{ |
669
|
|
|
$prop = ''; |
670
|
|
|
$name = '$' . $field; |
671
|
|
|
$type = $column->getPHPType(); |
672
|
|
|
if ($this->_soap) { |
673
|
|
|
$prop .= <<<EOD |
674
|
|
|
|
675
|
|
|
/** |
676
|
|
|
* @var $type $name |
677
|
|
|
* @soapproperty |
678
|
|
|
*/ |
679
|
|
|
|
680
|
|
|
EOD; |
681
|
|
|
} |
682
|
|
|
$prop .= "\tpublic $name;"; |
683
|
|
|
return $prop; |
684
|
|
|
} |
685
|
|
|
|
686
|
|
|
/** |
687
|
|
|
* @param array $properties class varibles |
688
|
|
|
* @param string $tablename database table name |
689
|
|
|
* @param string $class php class name |
690
|
|
|
* @return string |
691
|
|
|
*/ |
692
|
|
|
protected function generateClass($properties, $tablename, $class) |
693
|
|
|
{ |
694
|
|
|
$props = implode("\n", $properties); |
695
|
|
|
$date = date('Y-m-d h:i:s'); |
696
|
|
|
return <<<EOD |
697
|
|
|
<?php |
698
|
|
|
/** |
699
|
|
|
* Auto generated by prado-cli.php on $date. |
700
|
|
|
*/ |
701
|
|
|
class $class extends TActiveRecord |
702
|
|
|
{ |
703
|
|
|
const TABLE='$tablename'; |
704
|
|
|
|
705
|
|
|
$props |
706
|
|
|
|
707
|
|
|
public static function finder(\$className=__CLASS__) |
708
|
|
|
{ |
709
|
|
|
return parent::finder(\$className); |
710
|
|
|
} |
711
|
|
|
} |
712
|
|
|
|
713
|
|
|
EOD; |
714
|
|
|
} |
715
|
|
|
} |
716
|
|
|
|
717
|
|
|
/** |
718
|
|
|
* Create active record skeleton for all tables in DB and its relations |
719
|
|
|
* |
720
|
|
|
* @author Matthias Endres <me[at]me23[dot]de> |
721
|
|
|
* @author Daniel Sampedro Bello <darthdaniel85[at]gmail[dot]com> |
722
|
|
|
* @since 3.2 |
723
|
|
|
*/ |
724
|
|
|
class PradoCommandLineActiveRecordGenAll extends PradoCommandLineAction |
725
|
|
|
{ |
726
|
|
|
protected $action = 'generateAll'; |
727
|
|
|
protected $parameters = ['output']; |
728
|
|
|
protected $optional = ['directory', 'soap', 'overwrite', 'prefix', 'postfix']; |
729
|
|
|
protected $description = "Generate Active Record skeleton for all Tables to <output> file using application.xml in [directory]. May also generate [soap] properties.\nGenerated Classes are named like the Table with optional [Prefix] and/or [Postfix]. [Overwrite] is used to overwrite existing Files."; |
730
|
|
|
private $_soap = false; |
731
|
|
|
private $_prefix = ''; |
732
|
|
|
private $_postfix = ''; |
733
|
|
|
private $_overwrite = false; |
734
|
|
|
|
735
|
|
|
/** |
736
|
|
|
* @param array $args parameters |
737
|
|
|
* @return bool |
738
|
|
|
*/ |
739
|
|
|
public function performAction($args) |
740
|
|
|
{ |
741
|
|
|
$app_dir = count($args) > 2 ? $this->getAppDir($args[2]) : $this->getAppDir(); |
742
|
|
|
$this->_soap = count($args) > 3 ? ($args[3] == "soap" || $args[3] == "true" ? true : false) : false; |
743
|
|
|
$this->_overwrite = count($args) > 4 ? ($args[4] == "overwrite" || $args[4] == "true" ? true : false) : false; |
744
|
|
|
$this->_prefix = count($args) > 5 ? $args[5] : ''; |
745
|
|
|
$this->_postfix = count($args) > 6 ? $args[6] : ''; |
746
|
|
|
|
747
|
|
|
if ($app_dir !== false) { |
748
|
|
|
$config = $this->getActiveRecordConfig($app_dir); |
749
|
|
|
|
750
|
|
|
$manager = TActiveRecordManager::getInstance(); |
751
|
|
|
$con = $manager->getDbConnection(); |
752
|
|
|
$con->Active = true; |
753
|
|
|
|
754
|
|
|
switch ($con->getDriverName()) { |
755
|
|
|
case 'mysqli': |
756
|
|
|
case 'mysql': |
757
|
|
|
$command = $con->createCommand("SHOW TABLES"); |
758
|
|
|
break; |
759
|
|
|
case 'sqlite': //sqlite 3 |
760
|
|
|
case 'sqlite2': //sqlite 2 |
761
|
|
|
$command = $con->createCommand("SELECT DISTINCT tbl_name FROM sqlite_master WHERE tbl_name<>'sqlite_sequence'"); |
762
|
|
|
break; |
763
|
|
|
case 'pgsql': |
764
|
|
|
case 'mssql': // Mssql driver on windows hosts |
765
|
|
|
case 'sqlsrv': // sqlsrv driver on windows hosts |
766
|
|
|
case 'dblib': // dblib drivers on linux (and maybe others os) hosts |
767
|
|
|
case 'oci': |
768
|
|
|
// case 'ibm': |
769
|
|
|
default: |
770
|
|
|
echo "\n Sorry, generateAll is not implemented for " . $con->getDriverName() . "\n"; |
771
|
|
|
|
772
|
|
|
} |
773
|
|
|
|
774
|
|
|
$dataReader = $command->query(); |
|
|
|
|
775
|
|
|
$dataReader->bindColumn(1, $table); |
|
|
|
|
776
|
|
|
$tables = []; |
777
|
|
|
while ($dataReader->read() !== false) { |
778
|
|
|
$tables[] = $table; |
779
|
|
|
} |
780
|
|
|
$con->Active = false; |
781
|
|
|
foreach ($tables as $key => $table) { |
782
|
|
|
$output = $args[1] . "." . $this->_prefix . ucfirst($table) . $this->_postfix; |
783
|
|
|
if ($config !== false && $output !== false) { |
784
|
|
|
$this->generate("generate " . $table . " " . $output . " " . $this->_soap . " " . $this->_overwrite); |
785
|
|
|
} |
786
|
|
|
} |
787
|
|
|
} |
788
|
|
|
return true; |
789
|
|
|
} |
790
|
|
|
|
791
|
|
|
/** |
792
|
|
|
* @param string $l commandline |
793
|
|
|
*/ |
794
|
|
|
public function generate($l) |
795
|
|
|
{ |
796
|
|
|
$input = explode(" ", trim($l)); |
797
|
|
|
if (count($input) > 2) { |
798
|
|
|
$app_dir = '.'; |
799
|
|
|
if (Prado::getApplication() !== null) { |
800
|
|
|
$app_dir = dirname(Prado::getApplication()->getBasePath()); |
801
|
|
|
} |
802
|
|
|
$args = [$input[0], $input[1], $input[2], $app_dir]; |
803
|
|
|
if (count($input) > 3) { |
804
|
|
|
$args = [$input[0], $input[1], $input[2], $app_dir, 'soap']; |
805
|
|
|
} |
806
|
|
|
$cmd = new PradoCommandLineActiveRecordGen; |
807
|
|
|
$cmd->performAction($args); |
808
|
|
|
} else { |
809
|
|
|
echo "\n Usage: generate table_name Application.pages.RecordClassName\n"; |
810
|
|
|
} |
811
|
|
|
} |
812
|
|
|
|
813
|
|
|
/** |
814
|
|
|
* @param string $dir application directory |
815
|
|
|
* @return false|string |
816
|
|
|
*/ |
817
|
|
|
protected function getAppDir($dir = ".") |
818
|
|
|
{ |
819
|
|
|
if (is_dir($dir)) { |
820
|
|
|
return realpath($dir); |
821
|
|
|
} |
822
|
|
|
if (false !== ($app_dir = realpath($dir . '/protected/')) && is_dir($app_dir)) { |
823
|
|
|
return $app_dir; |
824
|
|
|
} |
825
|
|
|
echo '** Unable to find directory "' . $dir . "\".\n"; |
826
|
|
|
return false; |
827
|
|
|
} |
828
|
|
|
|
829
|
|
|
/** |
830
|
|
|
* @param string $app_dir application directory |
831
|
|
|
* @return false|string |
832
|
|
|
*/ |
833
|
|
|
protected function getXmlFile($app_dir) |
834
|
|
|
{ |
835
|
|
|
if (false !== ($xml = realpath($app_dir . '/application.xml')) && is_file($xml)) { |
836
|
|
|
return $xml; |
837
|
|
|
} |
838
|
|
|
if (false !== ($xml = realpath($app_dir . '/protected/application.xml')) && is_file($xml)) { |
839
|
|
|
return $xml; |
840
|
|
|
} |
841
|
|
|
echo '** Unable to find application.xml in ' . $app_dir . "\n"; |
842
|
|
|
return false; |
843
|
|
|
} |
844
|
|
|
|
845
|
|
|
/** |
846
|
|
|
* @param string $app_dir application directory |
847
|
|
|
* @return false|string |
848
|
|
|
*/ |
849
|
|
|
protected function getActiveRecordConfig($app_dir) |
850
|
|
|
{ |
851
|
|
|
if (false === ($xml = $this->getXmlFile($app_dir))) { |
852
|
|
|
return false; |
853
|
|
|
} |
854
|
|
|
if (false !== ($app = $this->initializePradoApplication($app_dir))) { |
855
|
|
|
Prado::using('Prado\Data\ActiveRecord\TActiveRecordConfig'); |
856
|
|
|
foreach ($app->getModules() as $module) { |
857
|
|
|
if ($module instanceof TActiveRecordConfig) { |
858
|
|
|
return $module; |
859
|
|
|
} |
860
|
|
|
} |
861
|
|
|
echo '** Unable to find TActiveRecordConfig module in ' . $xml . "\n"; |
862
|
|
|
} |
863
|
|
|
return false; |
864
|
|
|
} |
865
|
|
|
|
866
|
|
|
/** |
867
|
|
|
* @param string $app_dir application directory |
868
|
|
|
* @param string $namespace output file in namespace format |
869
|
|
|
* @return false|string |
870
|
|
|
*/ |
871
|
|
|
protected function getOutputFile($app_dir, $namespace) |
872
|
|
|
{ |
873
|
|
|
if (is_file($namespace) && strpos($namespace, $app_dir) === 0) { |
874
|
|
|
return $namespace; |
875
|
|
|
} |
876
|
|
|
$file = Prado::getPathOfNamespace($namespace, ""); |
877
|
|
|
if ($file !== null && false !== ($path = realpath(dirname($file))) && is_dir($path)) { |
878
|
|
|
if (strpos($path, $app_dir) === 0) { |
879
|
|
|
return $file; |
880
|
|
|
} |
881
|
|
|
} |
882
|
|
|
echo '** Output file ' . $file . ' must be within directory ' . $app_dir . "\n"; |
883
|
|
|
return false; |
884
|
|
|
} |
885
|
|
|
} |
886
|
|
|
|
In PHP, under loose comparison (like
==
, or!=
, orswitch
conditions), values of different types might be equal.For
integer
values, zero is a special case, in particular the following results might be unexpected: