Completed
Push — master ( 9aaf17...bab7fd )
by Fabio
13s
created

prado-cli.php ➔ __shell_print_var()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 2
eloc 2
nc 2
nop 2
dl 0
loc 4
rs 10
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
 * @copyright Copyright &copy; 2005-2016 The PRADO Group
9
 * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
10
 */
11
12
if(!isset($_SERVER['argv']) || php_sapi_name()!=='cli')
13
	die('Must be run from the command line');
14
15
$frameworkPath = realpath(dirname(dirname(__FILE__))).DIRECTORY_SEPARATOR.'framework'.DIRECTORY_SEPARATOR;
16
17
require_once($frameworkPath.'prado.php');
18
19
//stub application class
20
class PradoShellApplication extends TApplication
21
{
22
	public function run()
23
	{
24
		$this->initApplication();
25
	}
26
}
27
28
restore_exception_handler();
29
30
//config PHP shell
31
if(count($_SERVER['argv']) > 1 && strtolower($_SERVER['argv'][1])==='shell')
32
{
33
	function __shell_print_var($shell,$var)
0 ignored issues
show
Coding Style introduced by
Function name "__shell_print_var" is invalid; only PHP magic methods should be prefixed with a double underscore
Loading history...
34
	{
35
		if(!$shell->has_semicolon) echo Prado::varDump($var);
36
	}
37
	include_once($frameworkPath.'/3rdParty/PhpShell/php-shell-init.php');
38
}
39
40
41
//register action classes
42
PradoCommandLineInterpreter::getInstance()->addActionClass('PradoCommandLineCreateProject');
43
PradoCommandLineInterpreter::getInstance()->addActionClass('PradoCommandLineCreateTests');
44
PradoCommandLineInterpreter::getInstance()->addActionClass('PradoCommandLinePhpShell');
45
PradoCommandLineInterpreter::getInstance()->addActionClass('PradoCommandLineUnitTest');
46
PradoCommandLineInterpreter::getInstance()->addActionClass('PradoCommandLineActiveRecordGen');
47
PradoCommandLineInterpreter::getInstance()->addActionClass('PradoCommandLineActiveRecordGenAll');
48
49
//run it;
50
PradoCommandLineInterpreter::getInstance()->run($_SERVER['argv']);
51
52
/**************** END CONFIGURATION **********************/
53
54
/**
55
 * PradoCommandLineInterpreter Class
56
 *
57
 * Command line interface, configures the action classes and dispatches the command actions.
58
 *
59
 * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
60
 * @since 3.0.5
61
 */
62
class PradoCommandLineInterpreter
63
{
64
	/**
65
	 * @var array command action classes
66
	 */
67
	protected $_actions=array();
68
69
	/**
70
	 * @param string action class name
71
	 */
72
	public function addActionClass($class)
73
	{
74
		$this->_actions[$class] = new $class;
75
	}
76
77
	/**
78
	 * @return PradoCommandLineInterpreter static instance
79
	 */
80
	public static function getInstance()
81
	{
82
		static $instance;
83
		if($instance === null)
84
			$instance = new self;
85
		return $instance;
86
	}
87
88
	public static function printGreeting()
89
	{
90
		echo "Command line tools for Prado ".Prado::getVersion().".\n";
91
	}
92
93
	/**
94
	 * Dispatch the command line actions.
95
	 * @param array command line arguments
96
	 */
97
	public function run($args)
98
	{
99
		if(count($args) > 1)
100
			array_shift($args);
101
		$valid = false;
102
		foreach($this->_actions as $class => $action)
103
		{
104
			if($action->isValidAction($args))
105
			{
106
				$valid |= $action->performAction($args);
107
				break;
108
			}
109
			else
110
			{
111
				$valid = false;
112
			}
113
		}
114
		if(!$valid)
115
			$this->printHelp();
116
	}
117
118
	/**
119
	 * Print command line help, default action.
120
	 */
121
	public function printHelp()
122
	{
123
		PradoCommandLineInterpreter::printGreeting();
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
124
125
		echo "usage: php prado-cli.php action <parameter> [optional]\n";
126
		echo "example: php prado-cli.php -c mysite\n\n";
127
		echo "actions:\n";
128
		foreach($this->_actions as $action)
129
			echo $action->renderHelp();
130
	}
131
}
132
133
/**
134
 * Base class for command line actions.
135
 *
136
 * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
137
 * @since 3.0.5
138
 */
139
abstract class PradoCommandLineAction
140
{
141
	/**
142
	 * Execute the action.
143
	 * @param array command line parameters
144
	 * @return boolean true if action was handled
145
	 */
146
	public abstract function performAction($args);
0 ignored issues
show
Coding Style introduced by
The abstract declaration must precede the visibility declaration
Loading history...
147
148
	protected function createDirectory($dir, $mask)
149
	{
150
		if(!is_dir($dir))
151
		{
152
			mkdir($dir);
153
			echo "creating $dir\n";
154
		}
155
		if(is_dir($dir))
156
			chmod($dir, $mask);
157
	}
158
159
	protected function createFile($filename, $content)
160
	{
161
		if(!is_file($filename))
162
		{
163
			file_put_contents($filename, $content);
164
			echo "creating $filename\n";
165
		}
166
	}
167
168
	public function isValidAction($args)
169
	{
170
		return strtolower($args[0]) === $this->action &&
0 ignored issues
show
Bug introduced by
The property action does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
171
				count($args)-1 >= count($this->parameters);
0 ignored issues
show
Bug introduced by
The property parameters does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
172
	}
173
174
	public function renderHelp()
175
	{
176
		$params = array();
177
		foreach($this->parameters as $v)
178
			$params[] = '<'.$v.'>';
179
		$parameters = join($params, ' ');
180
		$options = array();
181
		foreach($this->optional as $v)
0 ignored issues
show
Bug introduced by
The property optional does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
182
			$options[] = '['.$v.']';
183
		$optional = (strlen($parameters) ? ' ' : ''). join($options, ' ');
184
		$description='';
185
		foreach(explode("\n", wordwrap($this->description,65)) as $line)
0 ignored issues
show
Bug introduced by
The property description does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
186
			$description .= '    '.$line."\n";
187
		return <<<EOD
188
  {$this->action} {$parameters}{$optional}
189
{$description}
190
191
EOD;
192
	}
193
194
	protected function initializePradoApplication($directory)
195
	{
196
		$app_dir = realpath($directory.'/protected/');
197
		if($app_dir !== false && is_dir($app_dir))
198
		{
199
			if(Prado::getApplication()===null)
200
			{
201
				$app = new PradoShellApplication($app_dir);
202
				$app->run();
203
				$dir = substr(str_replace(realpath('./'),'',$app_dir),1);
204
				$initialized=true;
0 ignored issues
show
Unused Code introduced by
$initialized is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
205
				PradoCommandLineInterpreter::printGreeting();
206
				echo '** Loaded PRADO appplication in directory "'.$dir."\".\n";
207
			}
208
209
			return Prado::getApplication();
210
		}
211
		else
212
		{
213
			PradoCommandLineInterpreter::printGreeting();
214
			echo '+'.str_repeat('-',77)."+\n";
215
			echo '** Unable to load PRADO application in directory "'.$directory."\".\n";
216
			echo '+'.str_repeat('-',77)."+\n";
217
		}
218
		return false;
219
	}
220
221
}
222
223
/**
224
 * Create a Prado project skeleton, including directories and files.
225
 *
226
 * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
227
 * @since 3.0.5
228
 */
229
class PradoCommandLineCreateProject extends PradoCommandLineAction
230
{
231
	protected $action = '-c';
232
	protected $parameters = array('directory');
233
	protected $optional = array();
234
	protected $description = 'Creates a Prado project skeleton for the given <directory>.';
235
236
	public function performAction($args)
237
	{
238
		PradoCommandLineInterpreter::printGreeting();
239
		$this->createNewPradoProject($args[1]);
240
		return true;
241
	}
242
243
	/**
244
	 * Functions to create new prado project.
245
	 */
246
	protected function createNewPradoProject($dir)
247
	{
248
		if(strlen(trim($dir)) == 0)
249
			return;
250
251
		$rootPath = realpath(dirname(trim($dir)));
252
253
		if(basename($dir)!=='.')
254
			$basePath = $rootPath.DIRECTORY_SEPARATOR.basename($dir);
255
		else
256
			$basePath = $rootPath;
257
		$appName = basename($basePath);
258
		$assetPath = $basePath.DIRECTORY_SEPARATOR.'assets';
259
		$protectedPath  = $basePath.DIRECTORY_SEPARATOR.'protected';
260
		$runtimePath = $basePath.DIRECTORY_SEPARATOR.'protected'.DIRECTORY_SEPARATOR.'runtime';
261
		$pagesPath = $protectedPath.DIRECTORY_SEPARATOR.'pages';
262
263
		$indexFile = $basePath.DIRECTORY_SEPARATOR.'index.php';
264
		$htaccessFile = $protectedPath.DIRECTORY_SEPARATOR.'.htaccess';
265
		$configFile = $protectedPath.DIRECTORY_SEPARATOR.'application.xml';
266
		$defaultPageFile = $pagesPath.DIRECTORY_SEPARATOR.'Home.page';
267
268
		$this->createDirectory($basePath, 0755);
269
		$this->createDirectory($assetPath,0777);
270
		$this->createDirectory($protectedPath,0755);
271
		$this->createDirectory($runtimePath,0777);
272
		$this->createDirectory($pagesPath,0755);
273
274
		$this->createFile($indexFile, $this->renderIndexFile());
275
		$this->createFile($configFile, $this->renderConfigFile($appName));
276
		$this->createFile($htaccessFile, $this->renderHtaccessFile());
277
		$this->createFile($defaultPageFile, $this->renderDefaultPage());
278
	}
279
280
	protected function renderIndexFile()
281
	{
282
		$framework = realpath(dirname(dirname(__FILE__))).DIRECTORY_SEPARATOR.'framework'.DIRECTORY_SEPARATOR.'prado.php';
283
return '<?php
284
285
$frameworkPath=\''.$framework.'\';
286
287
// The following directory checks may be removed if performance is required
288
$basePath=dirname(__FILE__);
289
$assetsPath=$basePath.\'/assets\';
290
$runtimePath=$basePath.\'/protected/runtime\';
291
292
if(!is_file($frameworkPath))
293
	die("Unable to find prado framework path $frameworkPath.");
294
if(!is_writable($assetsPath))
295
	die("Please make sure that the directory $assetsPath is writable by Web server process.");
296
if(!is_writable($runtimePath))
297
	die("Please make sure that the directory $runtimePath is writable by Web server process.");
298
299
300
require_once($frameworkPath);
301
302
$application=new TApplication;
303
$application->run();
304
';
305
	}
306
307
	protected function renderConfigFile($appName)
308
	{
309
		return <<<EOD
310
<?xml version="1.0" encoding="utf-8"?>
311
312
<application id="$appName" mode="Debug">
313
  <!-- alias definitions and namespace usings
314
  <paths>
315
    <alias id="myalias" path="./lib" />
316
    <using namespace="Application.common.*" />
317
  </paths>
318
  -->
319
320
  <!-- configurations for modules -->
321
  <modules>
322
    <!-- Remove this comment mark to enable caching
323
    <module id="cache" class="System.Caching.TDbCache" />
324
    -->
325
326
    <!-- Remove this comment mark to enable PATH url format
327
    <module id="request" class="THttpRequest" UrlFormat="Path" />
328
    -->
329
330
    <!-- Remove this comment mark to enable logging
331
    <module id="log" class="System.Util.TLogRouter">
332
      <route class="TBrowserLogRoute" Categories="System" />
333
    </module>
334
    -->
335
  </modules>
336
337
  <!-- configuration for available services -->
338
  <services>
339
    <service id="page" class="TPageService" DefaultPage="Home" />
340
  </services>
341
342
  <!-- application parameters
343
  <parameters>
344
    <parameter id="param1" value="value1" />
345
    <parameter id="param2" value="value2" />
346
  </parameters>
347
  -->
348
</application>
349
EOD;
350
	}
351
352
	protected function renderHtaccessFile()
353
	{
354
		return 'deny from all';
355
	}
356
357
358
	protected function renderDefaultPage()
359
	{
360
return <<<EOD
361
<html>
362
<head>
363
  <title>Welcome to PRADO</title>
364
</head>
365
<body>
366
<h1>Welcome to PRADO!</h1>
367
</body>
368
</html>
369
EOD;
370
	}
371
}
372
373
/**
374
 * Creates test fixtures for a Prado application.
375
 *
376
 * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
377
 * @since 3.0.5
378
 */
379
class PradoCommandLineCreateTests extends PradoCommandLineAction
380
{
381
	protected $action = '-t';
382
	protected $parameters = array('directory');
383
	protected $optional = array();
384
	protected $description = 'Create test fixtures in the given <directory>.';
385
386
	public function performAction($args)
387
	{
388
		PradoCommandLineInterpreter::printGreeting();
389
		$this->createTestFixtures($args[1]);
390
		return true;
391
	}
392
393
	protected function createTestFixtures($dir)
394
	{
395
		if(strlen(trim($dir)) == 0)
396
			return;
397
398
		$rootPath = realpath(dirname(trim($dir)));
399
		$basePath = $rootPath.'/'.basename($dir);
400
401
		$tests = $basePath.'/tests';
402
		$unit_tests = $tests.'/unit';
403
		$functional_tests = $tests.'/functional';
404
405
		$this->createDirectory($tests,0755);
406
		$this->createDirectory($unit_tests,0755);
407
		$this->createDirectory($functional_tests,0755);
408
409
		$unit_test_index = $tests.'/unit.php';
410
		$functional_test_index = $tests.'/functional.php';
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $functional_test_index exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
411
412
		$this->createFile($unit_test_index, $this->renderUnitTestFixture());
413
		$this->createFile($functional_test_index, $this->renderFunctionalTestFixture());
414
	}
415
416
	protected function renderUnitTestFixture()
417
	{
418
		$tester = realpath(dirname(dirname(__FILE__))).'/tests/test_tools/unit_tests.php';
419
return '<?php
420
421
include_once \''.$tester.'\';
422
423
$app_directory = "../protected";
424
$test_cases = dirname(__FILE__)."/unit";
425
426
$tester = new PradoUnitTester($test_cases, $app_directory);
427
$tester->run(new HtmlReporter());
428
';
429
	}
430
431
	protected function renderFunctionalTestFixture()
432
	{
433
		$tester = realpath(dirname(dirname(__FILE__))).'/tests/test_tools/functional_tests.php';
434
return '<?php
435
436
include_once \''.$tester.'\';
437
438
$test_cases = dirname(__FILE__)."/functional";
439
440
$tester=new PradoFunctionalTester($test_cases);
441
$tester->run(new SimpleReporter());
442
';
443
	}
444
445
}
446
447
/**
448
 * Creates and run a Prado application in a PHP Shell.
449
 *
450
 * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
451
 * @since 3.0.5
452
 */
453
class PradoCommandLinePhpShell extends PradoCommandLineAction
454
{
455
	protected $action = 'shell';
456
	protected $parameters = array();
457
	protected $optional = array('directory');
458
	protected $description = 'Runs a PHP interactive interpreter. Initializes the Prado application in the given [directory].';
459
460
	public function performAction($args)
461
	{
462
		if(count($args) > 1)
463
			$app = $this->initializePradoApplication($args[1]);
0 ignored issues
show
Unused Code introduced by
$app is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
464
		return true;
465
	}
466
}
467
468
/**
469
 * Runs unit test cases.
470
 *
471
 * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
472
 * @since 3.0.5
473
 */
474
class PradoCommandLineUnitTest extends PradoCommandLineAction
475
{
476
	protected $action = 'test';
477
	protected $parameters = array('directory');
478
	protected $optional = array('testcase ...');
479
	protected $description = 'Runs all unit test cases in the given <directory>. Use [testcase] option to run specific test cases.';
480
481
	protected $matches = array();
482
483
	public function performAction($args)
484
	{
485
		$dir = realpath($args[1]);
486
		if($dir !== false && is_dir($dir))
487
			$this->runUnitTests($dir,$args);
488
		else
489
			echo '** Unable to find directory "'.$args[1]."\".\n";
490
		return true;
491
	}
492
493
	protected function initializeTestRunner()
494
	{
495
		$TEST_TOOLS = realpath(dirname(dirname(__FILE__))).'/tests/test_tools/';
496
497
		require_once($TEST_TOOLS.'/simpletest/unit_tester.php');
498
		require_once($TEST_TOOLS.'/simpletest/web_tester.php');
499
		require_once($TEST_TOOLS.'/simpletest/mock_objects.php');
500
		require_once($TEST_TOOLS.'/simpletest/reporter.php');
501
	}
502
503
	protected function runUnitTests($dir, $args)
504
	{
505
		$app_dir = $this->getAppDir($dir);
506
		if($app_dir !== false)
507
			$this->initializePradoApplication($app_dir.'/../');
508
509
		$this->initializeTestRunner();
510
		$test_dir = $this->getTestDir($dir);
511
		if($test_dir !== false)
512
		{
513
			$test =$this->getUnitTestCases($test_dir,$args);
514
			$running_dir = substr(str_replace(realpath('./'),'',$test_dir),1);
515
			echo 'Running unit tests in directory "'.$running_dir."\":\n";
516
			$test->run(new TextReporter());
517
		}
518
		else
519
		{
520
			$running_dir = substr(str_replace(realpath('./'),'',$dir),1);
521
			echo '** Unable to find test directory "'.$running_dir.'/unit" or "'.$running_dir.'/tests/unit".'."\n";
522
		}
523
	}
524
525
	protected function getAppDir($dir)
526
	{
527
		$app_dir = realpath($dir.'/protected');
528
		if($app_dir !== false && is_dir($app_dir))
529
			return $app_dir;
530
		return realpath($dir.'/../protected');
531
	}
532
533
	protected function getTestDir($dir)
534
	{
535
		$test_dir = realpath($dir.'/unit');
536
		if($test_dir !== false && is_dir($test_dir))
537
			return $test_dir;
538
		return realpath($dir.'/tests/unit/');
539
	}
540
541
	protected function getUnitTestCases($dir,$args)
542
	{
543
		$matches = null;
544
		if(count($args) > 2)
545
			$matches = array_slice($args,2);
546
		$test=new GroupTest(' ');
547
		$this->addTests($test,$dir,true,$matches);
548
		$test->setLabel(implode(' ',$this->matches));
549
		return $test;
550
	}
551
552
	protected function addTests($test,$path,$recursive=true,$match=null)
553
	{
554
		$dir=opendir($path);
555
		while(($entry=readdir($dir))!==false)
556
		{
557
			if(is_file($path.'/'.$entry) && (preg_match('/[^\s]*test[^\s]*\.php/', strtolower($entry))))
558
			{
559
				if($match==null||($match!=null && $this->hasMatch($match,$entry)))
560
					$test->addTestFile($path.'/'.$entry);
561
			}
562
			if($entry!=='.' && $entry!=='..' && is_dir($path.'/'.$entry) && $recursive)
563
				$this->addTests($test,$path.'/'.$entry,$recursive,$match);
564
		}
565
		closedir($dir);
566
	}
567
568
	protected function hasMatch($match,$entry)
569
	{
570
		$file = strtolower(substr($entry,0,strrpos($entry,'.')));
571
		foreach($match as $m)
572
		{
573
			if(strtolower($m) === $file)
574
			{
575
				$this->matches[] = $m;
576
				return true;
577
			}
578
		}
579
		return false;
580
	}
581
}
582
583
/**
584
 * Create active record skeleton
585
 *
586
 * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
587
 * @since 3.1
588
 */
589
class PradoCommandLineActiveRecordGen extends PradoCommandLineAction
590
{
591
	protected $action = 'generate';
592
	protected $parameters = array('table', 'output');
593
	protected $optional = array('directory', 'soap');
594
	protected $description = 'Generate Active Record skeleton for <table> to <output> file using application.xml in [directory]. May also generate [soap] properties.';
595
	private $_soap=false;
596
597
	public function performAction($args)
598
	{
599
		$app_dir = count($args) > 3 ? $this->getAppDir($args[3]) : $this->getAppDir();
600
		$this->_soap = count($args) > 4;
601
		if($app_dir !== false)
602
		{
603
			$config = $this->getActiveRecordConfig($app_dir);
604
			$output = $this->getOutputFile($app_dir, $args[2]);
605
			if(is_file($output))
606
				echo "** File $output already exists, skiping. \n";
607
			else if($config !== false && $output !== false)
608
				$this->generateActiveRecord($config, $args[1], $output);
609
		}
610
		return true;
611
	}
612
613
	protected function getAppDir($dir=".")
614
	{
615
		if(is_dir($dir))
616
			return realpath($dir);
617
		if(false !== ($app_dir = realpath($dir.'/protected/')) && is_dir($app_dir))
618
			return $app_dir;
619
		echo '** Unable to find directory "'.$dir."\".\n";
620
		return false;
621
	}
622
623
	protected function getXmlFile($app_dir)
0 ignored issues
show
Coding Style Naming introduced by
The parameter $app_dir is not named in camelCase.

This check marks parameter names that have not been written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection string becomes databaseConnectionString.

Loading history...
624
	{
625
		if(false !== ($xml = realpath($app_dir.'/application.xml')) && is_file($xml))
626
			return $xml;
627
		if(false !== ($xml = realpath($app_dir.'/protected/application.xml')) && is_file($xml))
628
			return $xml;
629
		echo '** Unable to find application.xml in '.$app_dir."\n";
630
		return false;
631
	}
632
633
	protected function getActiveRecordConfig($app_dir)
0 ignored issues
show
Coding Style Naming introduced by
The parameter $app_dir is not named in camelCase.

This check marks parameter names that have not been written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection string becomes databaseConnectionString.

Loading history...
634
	{
635
		if(false === ($xml=$this->getXmlFile($app_dir)))
636
			return false;
637
		if(false !== ($app=$this->initializePradoApplication($app_dir)))
638
		{
639
			Prado::using('System.Data.ActiveRecord.TActiveRecordConfig');
640
			foreach($app->getModules() as $module)
641
				if($module instanceof TActiveRecordConfig)
642
					return $module;
643
			echo '** Unable to find TActiveRecordConfig module in '.$xml."\n";
644
		}
645
		return false;
646
	}
647
648
	protected function getOutputFile($app_dir, $namespace)
0 ignored issues
show
Coding Style Naming introduced by
The parameter $app_dir is not named in camelCase.

This check marks parameter names that have not been written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection string becomes databaseConnectionString.

Loading history...
649
	{
650
		if(is_file($namespace) && strpos($namespace, $app_dir)===0)
651
				return $namespace;
652
		$file = Prado::getPathOfNamespace($namespace, ".php");
653
		if($file !== null && false !== ($path = realpath(dirname($file))) && is_dir($path))
654
		{
655
			if(strpos($path, $app_dir)===0)
656
				return $file;
657
		}
658
		echo '** Output file '.$file.' must be within directory '.$app_dir."\n";
659
		return false;
660
	}
661
662
	protected function generateActiveRecord($config, $tablename, $output)
663
	{
664
		$manager = TActiveRecordManager::getInstance();
665
		if($connection = $manager->getDbConnection()) {
0 ignored issues
show
Unused Code introduced by
$connection is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
666
			$gateway = $manager->getRecordGateway();
667
			$tableInfo = $gateway->getTableInfo($manager->getDbConnection(), $tablename);
668
			if(count($tableInfo->getColumns()) === 0)
669
			{
670
				echo '** Unable to find table or view "'.$tablename.'" in "'.$manager->getDbConnection()->getConnectionString()."\".\n";
671
				return false;
672
			}
673
			else
674
			{
675
				$properties = array();
676
				foreach($tableInfo->getColumns() as $field=>$column)
677
					$properties[] = $this->generateProperty($field,$column);
678
			}
679
680
			$classname = basename($output, '.php');
681
			$class = $this->generateClass($properties, $tablename, $classname);
682
			echo "  Writing class $classname to file $output\n";
683
			file_put_contents($output, $class);
684
		} else {
685
			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";
686
		}
687
	}
688
689
	protected function generateProperty($field,$column)
690
	{
691
		$prop = '';
692
		$name = '$'.$field;
693
		$type = $column->getPHPType();
694
		if($this->_soap)
695
		{
696
			$prop .= <<<EOD
697
698
	/**
699
	 * @var $type $name
700
	 * @soapproperty
701
	 */
702
703
EOD;
704
		}
705
		$prop .= "\tpublic $name;";
706
		return $prop;
707
	}
708
709
	protected function generateClass($properties, $tablename, $class)
710
	{
711
		$props = implode("\n", $properties);
712
		$date = date('Y-m-d h:i:s');
713
return <<<EOD
714
<?php
715
/**
716
 * Auto generated by prado-cli.php on $date.
717
 */
718
class $class extends TActiveRecord
719
{
720
	const TABLE='$tablename';
721
722
$props
723
724
	public static function finder(\$className=__CLASS__)
725
	{
726
		return parent::finder(\$className);
727
	}
728
}
729
730
EOD;
731
	}
732
}
733
734
/**
735
 * Create active record skeleton for all tables in DB and its relations
736
 *
737
 * @author Matthias Endres <me[at]me23[dot]de>
738
 * @author Daniel Sampedro Bello <darthdaniel85[at]gmail[dot]com>
739
 * @since 3.2
740
 */
741
class PradoCommandLineActiveRecordGenAll extends PradoCommandLineAction {
742
743
    protected $action = 'generateAll';
744
    protected $parameters = array('output');
745
    protected $optional = array('directory', 'soap', 'overwrite', 'prefix', 'postfix');
746
    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.";
747
    private $_soap = false;
748
    private $_prefix = '';
749
    private $_postfix = '';
750
    private $_overwrite = false;
751
752
    public function performAction($args) {
753
        $app_dir = count($args) > 2 ? $this->getAppDir($args[2]) : $this->getAppDir();
754
        $this->_soap = count($args) > 3 ? ($args[3] == "soap" || $args[3] == "true" ? true : false) : false;
755
        $this->_overwrite = count($args) > 4 ? ($args[4] == "overwrite" || $args[4] == "true" ? true : false) : false;
756
        $this->_prefix = count($args) > 5 ? $args[5] : '';
757
        $this->_postfix = count($args) > 6 ? $args[6] : '';
758
759
        if ($app_dir !== false) {
760
            $config = $this->getActiveRecordConfig($app_dir);
761
762
            $manager = TActiveRecordManager::getInstance();
763
            $con = $manager->getDbConnection();
764
            $con->Active = true;
0 ignored issues
show
Bug introduced by
The property Active does not seem to exist. Did you mean _active?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
765
            $command = $con->createCommand("Show Tables");
766
            $dataReader = $command->query();
767
            $dataReader->bindColumn(1, $table);
768
            $generator = new PHP_Shell_Extensions_ActiveRecord();
769
            $tables = array();
770
            while ($dataReader->read() !== false) {
771
                $tables[] = $table;
772
            }
773
            $con->Active = False;
0 ignored issues
show
Bug introduced by
The property Active does not seem to exist. Did you mean _active?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
774
            foreach ($tables as $key => $table) {
775
                $output = $args[1] . "." . $this->_prefix . ucfirst($table) . $this->_postfix;
776
                if ($config !== false && $output !== false) {
777
                    $generator->generate("generate " . $table . " " . $output . " " . $this->_soap . " " . $this->_overwrite);
778
                }
779
            }
780
        }
781
        return true;
782
    }
783
784
    protected function getAppDir($dir=".") {
785
        if (is_dir($dir))
786
            return realpath($dir);
787
        if (false !== ($app_dir = realpath($dir . '/protected/')) && is_dir($app_dir))
788
            return $app_dir;
789
        echo '** Unable to find directory "' . $dir . "\".\n";
790
        return false;
791
    }
792
793
    protected function getXmlFile($app_dir) {
0 ignored issues
show
Coding Style Naming introduced by
The parameter $app_dir is not named in camelCase.

This check marks parameter names that have not been written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection string becomes databaseConnectionString.

Loading history...
794
        if (false !== ($xml = realpath($app_dir . '/application.xml')) && is_file($xml))
795
            return $xml;
796
        if (false !== ($xml = realpath($app_dir . '/protected/application.xml')) && is_file($xml))
797
            return $xml;
798
        echo '** Unable to find application.xml in ' . $app_dir . "\n";
799
        return false;
800
    }
801
802
    protected function getActiveRecordConfig($app_dir) {
0 ignored issues
show
Coding Style Naming introduced by
The parameter $app_dir is not named in camelCase.

This check marks parameter names that have not been written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection string becomes databaseConnectionString.

Loading history...
803
        if (false === ($xml = $this->getXmlFile($app_dir)))
804
            return false;
805
        if (false !== ($app = $this->initializePradoApplication($app_dir))) {
806
            Prado::using('System.Data.ActiveRecord.TActiveRecordConfig');
807
            foreach ($app->getModules() as $module)
808
                if ($module instanceof TActiveRecordConfig)
809
                    return $module;
810
            echo '** Unable to find TActiveRecordConfig module in ' . $xml . "\n";
811
        }
812
        return false;
813
    }
814
815
    protected function getOutputFile($app_dir, $namespace) {
0 ignored issues
show
Coding Style Naming introduced by
The parameter $app_dir is not named in camelCase.

This check marks parameter names that have not been written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection string becomes databaseConnectionString.

Loading history...
816
        if (is_file($namespace) && strpos($namespace, $app_dir) === 0)
817
            return $namespace;
818
        $file = Prado::getPathOfNamespace($namespace, "");
819
        if ($file !== null && false !== ($path = realpath(dirname($file))) && is_dir($path)) {
820
            if (strpos($path, $app_dir) === 0)
821
                return $file;
822
        }
823
        echo '** Output file ' . $file . ' must be within directory ' . $app_dir . "\n";
824
        return false;
825
    }
826
827
}
828
829
//run PHP shell
830
if(class_exists('PHP_Shell_Commands', false))
831
{
832
	class PHP_Shell_Extensions_ActiveRecord implements PHP_Shell_Extension {
0 ignored issues
show
Coding Style introduced by
This class is not in CamelCase format.

Classes in PHP are usually named in CamelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. The whole name starts with a capital letter as well.

Thus the name database provider becomes DatabaseProvider.

Loading history...
833
	    public function register()
834
	    {
835
836
	        $cmd = PHP_Shell_Commands::getInstance();
837
			if(Prado::getApplication() !== null)
838
			{
839
		        $cmd->registerCommand('#^generate#', $this, 'generate', 'generate <table> <output> [soap]',
840
		            'Generate Active Record skeleton for <table> to <output> file using'.PHP_EOL.
841
		            '    application.xml in [directory]. May also generate [soap] properties.');
842
			}
843
	    }
844
845
	    public function generate($l)
846
	    {
847
			$input = explode(" ", trim($l));
848
			if(count($input) > 2)
849
			{
850
				$app_dir = '.';
851
				if(Prado::getApplication()!==null)
852
					$app_dir = dirname(Prado::getApplication()->getBasePath());
853
				$args = array($input[0],$input[1], $input[2],$app_dir);
854
				if(count($input)>3)
855
					$args = array($input[0],$input[1], $input[2],$app_dir,'soap');
856
				$cmd = new PradoCommandLineActiveRecordGen;
857
				$cmd->performAction($args);
858
			}
859
			else
860
			{
861
				echo "\n    Usage: generate table_name Application.pages.RecordClassName\n";
862
			}
863
	    }
864
	}
865
866
	$__shell_exts = PHP_Shell_Extensions::getInstance();
867
	$__shell_exts->registerExtensions(array(
868
		    "active-record"        => new PHP_Shell_Extensions_ActiveRecord)); /* the :set command */
869
870
	include_once(realpath(dirname(dirname(__FILE__))).'/framework/3rdParty/PhpShell/php-shell-cmd.php');
871
}
872