Test Failed
Branch master (206474)
by Fabio
18:24
created

performAction()   F

Complexity

Conditions 24
Paths 5632

Size

Total Lines 51
Code Lines 38

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 24
eloc 38
nc 5632
nop 1
dl 0
loc 51
rs 2.9532
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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/LICENSE
10
 */
11
12
if (!isset($_SERVER['argv']) || php_sapi_name() !== 'cli') {
13
	die('Must be run from the command line');
14
}
15
16
// Locate composer's autoloader
17
if (file_exists($autoloader = realpath(__DIR__ . '/../vendor/autoload.php'))) {
18
	// if we are running inside a prado repo checkout, get out of bin/
19
	include($autoloader);
20
} elseif (file_exists($autoloader = realpath(__DIR__ . '/../../../autoload.php'))) {
21
	// if we are running from inside an application's vendor/ directory, get out of pradosoft/prado/bin/
22
	include($autoloader);
23
}
24
25
use Prado\TApplication;
26
use Prado\Prado;
27
28
//stub application class
29
class PradoShellApplication extends TApplication
30
{
31
	public function run()
32
	{
33
		$this->initApplication();
34
	}
35
}
36
37
restore_exception_handler();
38
39
40
//register action classes
41
PradoCommandLineInterpreter::getInstance()->addActionClass('PradoCommandLineCreateProject');
42
PradoCommandLineInterpreter::getInstance()->addActionClass('PradoCommandLineCreateTests');
43
PradoCommandLineInterpreter::getInstance()->addActionClass('PradoCommandLinePhpShell');
44
PradoCommandLineInterpreter::getInstance()->addActionClass('PradoCommandLineActiveRecordGen');
45
PradoCommandLineInterpreter::getInstance()->addActionClass('PradoCommandLineActiveRecordGenAll');
46
47
//run it;
48
PradoCommandLineInterpreter::getInstance()->run($_SERVER['argv']);
49
50
/**************** END CONFIGURATION **********************/
51
52
/**
53
 * PradoCommandLineInterpreter Class
54
 *
55
 * Command line interface, configures the action classes and dispatches the command actions.
56
 *
57
 * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
58
 * @since 3.0.5
59
 */
60
class PradoCommandLineInterpreter
61
{
62
	/**
63
	 * @var array command action classes
64
	 */
65
	protected $_actions = [];
66
67
	/**
68
	 * @param string $class action class name
69
	 */
70
	public function addActionClass($class)
71
	{
72
		$this->_actions[$class] = new $class;
73
	}
74
75
	/**
76
	 * @return PradoCommandLineInterpreter static instance
77
	 */
78
	public static function getInstance()
79
	{
80
		static $instance;
81
		if ($instance === null) {
82
			$instance = new self;
83
		}
84
		return $instance;
85
	}
86
87
	public static function printGreeting()
88
	{
89
		echo "Command line tools for Prado " . Prado::getVersion() . ".\n";
90
	}
91
92
	/**
93
	 * Dispatch the command line actions.
94
	 * @param array $args command line arguments
95
	 */
96
	public function run($args)
97
	{
98
		if (count($args) > 1) {
99
			array_shift($args);
100
		}
101
		$valid = false;
102
		foreach ($this->_actions as $class => $action) {
103
			if ($action->isValidAction($args)) {
104
				$valid |= $action->performAction($args);
105
				break;
106
			} else {
107
				$valid = false;
108
			}
109
		}
110
		if (!$valid) {
111
			$this->printHelp();
112
		}
113
	}
114
115
	/**
116
	 * Print command line help, default action.
117
	 */
118
	public function printHelp()
119
	{
120
		PradoCommandLineInterpreter::printGreeting();
121
122
		echo "usage: php prado-cli.php action <parameter> [optional]\n";
123
		echo "example: php prado-cli.php -c mysite\n\n";
124
		echo "actions:\n";
125
		foreach ($this->_actions as $action) {
126
			echo $action->renderHelp();
127
		}
128
	}
129
}
130
131
/**
132
 * Base class for command line actions.
133
 *
134
 * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
135
 * @since 3.0.5
136
 */
137
abstract class PradoCommandLineAction
138
{
139
	/**
140
	 * Execute the action.
141
	 * @param array $args command line parameters
142
	 * @return bool true if action was handled
143
	 */
144
	abstract public function performAction($args);
145
146
	protected function createDirectory($dir, $mask)
147
	{
148
		if (!is_dir($dir)) {
149
			mkdir($dir);
150
			echo "creating $dir\n";
151
		}
152
		if (is_dir($dir)) {
153
			chmod($dir, $mask);
154
		}
155
	}
156
157
	protected function createFile($filename, $content)
158
	{
159
		if (!is_file($filename)) {
160
			file_put_contents($filename, $content);
161
			echo "creating $filename\n";
162
		}
163
	}
164
165
	public function isValidAction($args)
166
	{
167
		return 0 == strcasecmp($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...
168
			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...
169
	}
170
171
	public function renderHelp()
172
	{
173
		$params = [];
174
		foreach ($this->parameters as $v) {
175
			$params[] = '<' . $v . '>';
176
		}
177
		$parameters = implode($params, ' ');
178
		$options = [];
179
		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...
180
			$options[] = '[' . $v . ']';
181
		}
182
		$optional = (strlen($parameters) ? ' ' : '') . implode($options, ' ');
183
		$description = '';
184
		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...
185
			$description .= '    ' . $line . "\n";
186
		}
187
		return <<<EOD
188
  {$this->action} {$parameters}{$optional}
189
{$description}
190
191
EOD;
192
	}
193
194
	protected function initializePradoApplication($directory)
0 ignored issues
show
Coding Style introduced by
initializePradoApplication uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
195
	{
196
		$_SERVER['SCRIPT_FILENAME'] = $directory . '/index.php';
197
		$app_dir = realpath($directory . '/protected/');
198
		if ($app_dir !== false && is_dir($app_dir)) {
199
			if (Prado::getApplication() === null) {
200
				$app = new PradoShellApplication($app_dir);
201
				$app->run();
202
				$dir = substr(str_replace(realpath('./'), '', $app_dir), 1);
203
				PradoCommandLineInterpreter::printGreeting();
204
				echo '** Loaded PRADO appplication in directory "' . $dir . "\".\n";
205
			}
206
207
			return Prado::getApplication();
208
		} else {
209
			PradoCommandLineInterpreter::printGreeting();
210
			echo '+' . str_repeat('-', 77) . "+\n";
211
			echo '** Unable to load PRADO application in directory "' . $directory . "\".\n";
212
			echo '+' . str_repeat('-', 77) . "+\n";
213
		}
214
		return false;
215
	}
216
}
217
218
/**
219
 * Create a Prado project skeleton, including directories and files.
220
 *
221
 * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
222
 * @since 3.0.5
223
 */
224
class PradoCommandLineCreateProject extends PradoCommandLineAction
225
{
226
	protected $action = '-c';
227
	protected $parameters = ['directory'];
228
	protected $optional = [];
229
	protected $description = 'Creates a Prado project skeleton for the given <directory>.';
230
231
	public function performAction($args)
232
	{
233
		PradoCommandLineInterpreter::printGreeting();
234
		$this->createNewPradoProject($args[1]);
235
		return true;
236
	}
237
238
	/**
239
	 * Functions to create new prado project.
240
	 * @param mixed $dir
241
	 */
242
	protected function createNewPradoProject($dir)
243
	{
244
		if (strlen(trim($dir)) == 0) {
245
			return;
246
		}
247
248
		$rootPath = realpath(dirname(trim($dir)));
249
250
		if (basename($dir) !== '.') {
251
			$basePath = $rootPath . DIRECTORY_SEPARATOR . basename($dir);
252
		} else {
253
			$basePath = $rootPath;
254
		}
255
		$appName = basename($basePath);
256
		$assetPath = $basePath . DIRECTORY_SEPARATOR . 'assets';
257
		$protectedPath = $basePath . DIRECTORY_SEPARATOR . 'protected';
258
		$runtimePath = $basePath . DIRECTORY_SEPARATOR . 'protected' . DIRECTORY_SEPARATOR . 'runtime';
259
		$pagesPath = $protectedPath . DIRECTORY_SEPARATOR . 'pages';
260
261
		$indexFile = $basePath . DIRECTORY_SEPARATOR . 'index.php';
262
		$htaccessFile = $protectedPath . DIRECTORY_SEPARATOR . '.htaccess';
263
		$configFile = $protectedPath . DIRECTORY_SEPARATOR . 'application.xml';
264
		$defaultPageFile = $pagesPath . DIRECTORY_SEPARATOR . 'Home.page';
265
266
		$this->createDirectory($basePath, 0755);
267
		$this->createDirectory($assetPath, 0777);
268
		$this->createDirectory($protectedPath, 0755);
269
		$this->createDirectory($runtimePath, 0777);
270
		$this->createDirectory($pagesPath, 0755);
271
272
		$this->createFile($indexFile, $this->renderIndexFile());
273
		$this->createFile($configFile, $this->renderConfigFile($appName));
274
		$this->createFile($htaccessFile, $this->renderHtaccessFile());
275
		$this->createFile($defaultPageFile, $this->renderDefaultPage());
276
	}
277
278
	protected function renderIndexFile()
279
	{
280
		$framework = realpath(dirname(__DIR__)) . DIRECTORY_SEPARATOR . 'framework' . DIRECTORY_SEPARATOR . 'prado.php';
281
		return '<?php
282
283
$frameworkPath=\'' . $framework . '\';
284
285
// The following directory checks may be removed if performance is required
286
$basePath=dirname(__FILE__);
287
$assetsPath=$basePath.\'/assets\';
288
$runtimePath=$basePath.\'/protected/runtime\';
289
290
if(!is_file($frameworkPath))
291
	die("Unable to find prado framework path $frameworkPath.");
292
if(!is_writable($assetsPath))
293
	die("Please make sure that the directory $assetsPath is writable by Web server process.");
294
if(!is_writable($runtimePath))
295
	die("Please make sure that the directory $runtimePath is writable by Web server process.");
296
297
298
require_once($frameworkPath);
299
300
$application=new TApplication;
301
$application->run();
302
';
303
	}
304
305
	protected function renderConfigFile($appName)
306
	{
307
		return <<<EOD
308
<?xml version="1.0" encoding="utf-8"?>
309
310
<application id="$appName" mode="Debug">
311
  <!-- alias definitions and namespace usings
312
  <paths>
313
    <alias id="myalias" path="./lib" />
314
    <using namespace="Application.common.*" />
315
  </paths>
316
  -->
317
318
  <!-- configurations for modules -->
319
  <modules>
320
    <!-- Remove this comment mark to enable caching
321
    <module id="cache" class="System.Caching.TDbCache" />
322
    -->
323
324
    <!-- Remove this comment mark to enable PATH url format
325
    <module id="request" class="THttpRequest" UrlFormat="Path" />
326
    -->
327
328
    <!-- Remove this comment mark to enable logging
329
    <module id="log" class="System.Util.TLogRouter">
330
      <route class="TBrowserLogRoute" Categories="System" />
331
    </module>
332
    -->
333
  </modules>
334
335
  <!-- configuration for available services -->
336
  <services>
337
    <service id="page" class="TPageService" DefaultPage="Home" />
338
  </services>
339
340
  <!-- application parameters
341
  <parameters>
342
    <parameter id="param1" value="value1" />
343
    <parameter id="param2" value="value2" />
344
  </parameters>
345
  -->
346
</application>
347
EOD;
348
	}
349
350
	protected function renderHtaccessFile()
351
	{
352
		return 'deny from all';
353
	}
354
355
356
	protected function renderDefaultPage()
357
	{
358
		return <<<EOD
359
<html>
360
<head>
361
  <title>Welcome to PRADO</title>
362
</head>
363
<body>
364
<h1>Welcome to PRADO!</h1>
365
</body>
366
</html>
367
EOD;
368
	}
369
}
370
371
/**
372
 * Creates test fixtures for a Prado application.
373
 *
374
 * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
375
 * @since 3.0.5
376
 */
377
class PradoCommandLineCreateTests extends PradoCommandLineAction
378
{
379
	protected $action = '-t';
380
	protected $parameters = ['directory'];
381
	protected $optional = [];
382
	protected $description = 'Create test fixtures in the given <directory>.';
383
384
	public function performAction($args)
385
	{
386
		PradoCommandLineInterpreter::printGreeting();
387
		$this->createTestFixtures($args[1]);
388
		return true;
389
	}
390
391
	protected function createTestFixtures($dir)
392
	{
393
		if (strlen(trim($dir)) == 0) {
394
			return;
395
		}
396
397
		$rootPath = realpath(dirname(trim($dir)));
398
		$basePath = $rootPath . '/' . basename($dir);
399
400
		$tests = $basePath . '/tests';
401
		$unit_tests = $tests . '/unit';
402
		$functional_tests = $tests . '/functional';
403
404
		$this->createDirectory($tests, 0755);
405
		$this->createDirectory($unit_tests, 0755);
406
		$this->createDirectory($functional_tests, 0755);
407
408
		$unit_test_index = $tests . '/unit.php';
409
		$functional_test_index = $tests . '/functional.php';
410
411
		$this->createFile($unit_test_index, $this->renderUnitTestFixture());
412
		$this->createFile($functional_test_index, $this->renderFunctionalTestFixture());
413
	}
414
415
	protected function renderUnitTestFixture()
416
	{
417
		$tester = realpath(dirname(__DIR__)) . '/tests/test_tools/unit_tests.php';
418
		return '<?php
419
420
include_once \'' . $tester . '\';
421
422
$app_directory = "../protected";
423
$test_cases = dirname(__FILE__)."/unit";
424
425
$tester = new PradoUnitTester($test_cases, $app_directory);
426
$tester->run(new HtmlReporter());
427
';
428
	}
429
430
	protected function renderFunctionalTestFixture()
431
	{
432
		$tester = realpath(dirname(__DIR__)) . '/tests/test_tools/functional_tests.php';
433
		return '<?php
434
435
include_once \'' . $tester . '\';
436
437
$test_cases = dirname(__FILE__)."/functional";
438
439
$tester=new PradoFunctionalTester($test_cases);
440
$tester->run(new SimpleReporter());
441
';
442
	}
443
}
444
445
/**
446
 * Creates and run a Prado application in a PHP Shell.
447
 *
448
 * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
449
 * @since 3.0.5
450
 */
451
class PradoCommandLinePhpShell extends PradoCommandLineAction
452
{
453
	protected $action = 'shell';
454
	protected $parameters = [];
455
	protected $optional = ['directory'];
456
	protected $description = 'Runs a PHP interactive interpreter. Initializes the Prado application in the given [directory].';
457
458
	public function performAction($args)
459
	{
460
		if (count($args) > 1) {
461
			$this->initializePradoApplication($args[1]);
462
		}
463
464
		\Psy\debug([], Prado::getApplication());
465
		return true;
466
	}
467
}
468
469
/**
470
 * Create active record skeleton
471
 *
472
 * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
473
 * @since 3.1
474
 */
475
class PradoCommandLineActiveRecordGen extends PradoCommandLineAction
476
{
477
	protected $action = 'generate';
478
	protected $parameters = ['table', 'output'];
479
	protected $optional = ['directory', 'soap'];
480
	protected $description = 'Generate Active Record skeleton for <table> to <output> file using application.xml in [directory]. May also generate [soap] properties.';
481
	private $_soap = false;
482
483
	public function performAction($args)
484
	{
485
		$app_dir = count($args) > 3 ? $this->getAppDir($args[3]) : $this->getAppDir();
486
		$this->_soap = count($args) > 4;
487
		if ($app_dir !== false) {
488
			$config = $this->getActiveRecordConfig($app_dir);
489
			$output = $this->getOutputFile($app_dir, $args[2]);
490
			if (is_file($output)) {
491
				echo "** File $output already exists, skiping. \n";
492
			} elseif ($config !== false && $output !== false) {
493
				$this->generateActiveRecord($config, $args[1], $output);
494
			}
495
		}
496
		return true;
497
	}
498
499 View Code Duplication
	protected function getAppDir($dir = ".")
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
500
	{
501
		if (is_dir($dir)) {
502
			return realpath($dir);
503
		}
504
		if (false !== ($app_dir = realpath($dir . '/protected/')) && is_dir($app_dir)) {
505
			return $app_dir;
506
		}
507
		echo '** Unable to find directory "' . $dir . "\".\n";
508
		return false;
509
	}
510
511 View Code Duplication
	protected function getXmlFile($app_dir)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
512
	{
513
		if (false !== ($xml = realpath($app_dir . '/application.xml')) && is_file($xml)) {
514
			return $xml;
515
		}
516
		if (false !== ($xml = realpath($app_dir . '/protected/application.xml')) && is_file($xml)) {
517
			return $xml;
518
		}
519
		echo '** Unable to find application.xml in ' . $app_dir . "\n";
520
		return false;
521
	}
522
523 View Code Duplication
	protected function getActiveRecordConfig($app_dir)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
524
	{
525
		if (false === ($xml = $this->getXmlFile($app_dir))) {
526
			return false;
527
		}
528
		if (false !== ($app = $this->initializePradoApplication($app_dir))) {
529
			Prado::using('System.Data.ActiveRecord.TActiveRecordConfig');
530
			foreach ($app->getModules() as $module) {
531
				if ($module instanceof TActiveRecordConfig) {
0 ignored issues
show
Bug introduced by
The class TActiveRecordConfig does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
532
					return $module;
533
				}
534
			}
535
			echo '** Unable to find TActiveRecordConfig module in ' . $xml . "\n";
536
		}
537
		return false;
538
	}
539
540 View Code Duplication
	protected function getOutputFile($app_dir, $namespace)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
541
	{
542
		if (is_file($namespace) && strpos($namespace, $app_dir) === 0) {
543
			return $namespace;
544
		}
545
		$file = Prado::getPathOfNamespace($namespace, ".php");
546
		if ($file !== null && false !== ($path = realpath(dirname($file))) && is_dir($path)) {
547
			if (strpos($path, $app_dir) === 0) {
548
				return $file;
549
			}
550
		}
551
		echo '** Output file ' . $file . ' must be within directory ' . $app_dir . "\n";
552
		return false;
553
	}
554
555
	protected function generateActiveRecord($config, $tablename, $output)
556
	{
557
		$manager = TActiveRecordManager::getInstance();
558
		if ($manager->getDbConnection()) {
559
			$gateway = $manager->getRecordGateway();
560
			$tableInfo = $gateway->getTableInfo($manager->getDbConnection(), $tablename);
561
			if (count($tableInfo->getColumns()) === 0) {
562
				echo '** Unable to find table or view "' . $tablename . '" in "' . $manager->getDbConnection()->getConnectionString() . "\".\n";
563
				return false;
564
			} else {
565
				$properties = [];
566
				foreach ($tableInfo->getColumns() as $field => $column) {
567
					$properties[] = $this->generateProperty($field, $column);
568
				}
569
			}
570
571
			$classname = basename($output, '.php');
572
			$class = $this->generateClass($properties, $tablename, $classname);
573
			echo "  Writing class $classname to file $output\n";
574
			file_put_contents($output, $class);
575
		} else {
576
			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";
577
		}
578
	}
579
580
	protected function generateProperty($field, $column)
581
	{
582
		$prop = '';
583
		$name = '$' . $field;
584
		$type = $column->getPHPType();
585
		if ($this->_soap) {
586
			$prop .= <<<EOD
587
588
	/**
589
	 * @var $type $name
590
	 * @soapproperty
591
	 */
592
593
EOD;
594
		}
595
		$prop .= "\tpublic $name;";
596
		return $prop;
597
	}
598
599
	protected function generateClass($properties, $tablename, $class)
600
	{
601
		$props = implode("\n", $properties);
602
		$date = date('Y-m-d h:i:s');
603
		return <<<EOD
604
<?php
605
/**
606
 * Auto generated by prado-cli.php on $date.
607
 */
608
class $class extends TActiveRecord
609
{
610
	const TABLE='$tablename';
611
612
$props
613
614
	public static function finder(\$className=__CLASS__)
615
	{
616
		return parent::finder(\$className);
617
	}
618
}
619
620
EOD;
621
	}
622
}
623
624
/**
625
 * Create active record skeleton for all tables in DB and its relations
626
 *
627
 * @author Matthias Endres <me[at]me23[dot]de>
628
 * @author Daniel Sampedro Bello <darthdaniel85[at]gmail[dot]com>
629
 * @since 3.2
630
 */
631
class PradoCommandLineActiveRecordGenAll extends PradoCommandLineAction
632
{
633
	protected $action = 'generateAll';
634
	protected $parameters = ['output'];
635
	protected $optional = ['directory', 'soap', 'overwrite', 'prefix', 'postfix'];
636
	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.";
637
	private $_soap = false;
638
	private $_prefix = '';
639
	private $_postfix = '';
640
	private $_overwrite = false;
641
642
	public function performAction($args)
643
	{
644
		$app_dir = count($args) > 2 ? $this->getAppDir($args[2]) : $this->getAppDir();
645
		$this->_soap = count($args) > 3 ? ($args[3] == "soap" || $args[3] == "true" ? true : false) : false;
646
		$this->_overwrite = count($args) > 4 ? ($args[4] == "overwrite" || $args[4] == "true" ? true : false) : false;
647
		$this->_prefix = count($args) > 5 ? $args[5] : '';
648
		$this->_postfix = count($args) > 6 ? $args[6] : '';
649
650
		if ($app_dir !== false) {
651
			$config = $this->getActiveRecordConfig($app_dir);
652
653
			$manager = TActiveRecordManager::getInstance();
654
			$con = $manager->getDbConnection();
655
			$con->Active = true;
656
657
			switch ($con->getDriverName()) {
658
				case 'mysqli':
659
				case 'mysql':
660
					$command = $con->createCommand("SHOW TABLES");
661
					break;
662
				case 'sqlite': //sqlite 3
663
				case 'sqlite2': //sqlite 2
664
					$command = $con->createCommand("SELECT DISTINCT tbl_name FROM sqlite_master WHERE tbl_name<>'sqlite_sequence'");
665
					break;
666
				case 'pgsql':
667
				case 'mssql': // Mssql driver on windows hosts
668
				case 'sqlsrv': // sqlsrv driver on windows hosts
669
				case 'dblib': // dblib drivers on linux (and maybe others os) hosts
670
				case 'oci':
671
//				case 'ibm':
672
				default:
673
					echo "\n    Sorry, generateAll is not implemented for " . $con->getDriverName() . "\n";
674
675
			   }
676
677
			$dataReader = $command->query();
0 ignored issues
show
Bug introduced by
The variable $command does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
678
			$dataReader->bindColumn(1, $table);
0 ignored issues
show
Bug introduced by
The variable $table seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
679
			$tables = [];
680
			while ($dataReader->read() !== false) {
681
				$tables[] = $table;
0 ignored issues
show
Bug introduced by
The variable $table seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
682
			}
683
			$con->Active = false;
684
			foreach ($tables as $key => $table) {
685
				$output = $args[1] . "." . $this->_prefix . ucfirst($table) . $this->_postfix;
686
				if ($config !== false && $output !== false) {
687
					$this->generate("generate " . $table . " " . $output . " " . $this->_soap . " " . $this->_overwrite);
688
				}
689
			}
690
		}
691
		return true;
692
	}
693
694
	public function generate($l)
695
	{
696
		$input = explode(" ", trim($l));
697
		if (count($input) > 2) {
698
			$app_dir = '.';
699
			if (Prado::getApplication() !== null) {
700
				$app_dir = dirname(Prado::getApplication()->getBasePath());
701
			}
702
			$args = [$input[0], $input[1], $input[2], $app_dir];
703
			if (count($input) > 3) {
704
				$args = [$input[0], $input[1], $input[2], $app_dir, 'soap'];
705
			}
706
			$cmd = new PradoCommandLineActiveRecordGen;
707
			$cmd->performAction($args);
708
		} else {
709
			echo "\n    Usage: generate table_name Application.pages.RecordClassName\n";
710
		}
711
	}
712
713 View Code Duplication
	protected function getAppDir($dir = ".")
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
714
	{
715
		if (is_dir($dir)) {
716
			return realpath($dir);
717
		}
718
		if (false !== ($app_dir = realpath($dir . '/protected/')) && is_dir($app_dir)) {
719
			return $app_dir;
720
		}
721
		echo '** Unable to find directory "' . $dir . "\".\n";
722
		return false;
723
	}
724
725 View Code Duplication
	protected function getXmlFile($app_dir)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
726
	{
727
		if (false !== ($xml = realpath($app_dir . '/application.xml')) && is_file($xml)) {
728
			return $xml;
729
		}
730
		if (false !== ($xml = realpath($app_dir . '/protected/application.xml')) && is_file($xml)) {
731
			return $xml;
732
		}
733
		echo '** Unable to find application.xml in ' . $app_dir . "\n";
734
		return false;
735
	}
736
737 View Code Duplication
	protected function getActiveRecordConfig($app_dir)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
738
	{
739
		if (false === ($xml = $this->getXmlFile($app_dir))) {
740
			return false;
741
		}
742
		if (false !== ($app = $this->initializePradoApplication($app_dir))) {
743
			Prado::using('System.Data.ActiveRecord.TActiveRecordConfig');
744
			foreach ($app->getModules() as $module) {
745
				if ($module instanceof TActiveRecordConfig) {
0 ignored issues
show
Bug introduced by
The class TActiveRecordConfig does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
746
					return $module;
747
				}
748
			}
749
			echo '** Unable to find TActiveRecordConfig module in ' . $xml . "\n";
750
		}
751
		return false;
752
	}
753
754 View Code Duplication
	protected function getOutputFile($app_dir, $namespace)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
755
	{
756
		if (is_file($namespace) && strpos($namespace, $app_dir) === 0) {
757
			return $namespace;
758
		}
759
		$file = Prado::getPathOfNamespace($namespace, "");
760
		if ($file !== null && false !== ($path = realpath(dirname($file))) && is_dir($path)) {
761
			if (strpos($path, $app_dir) === 0) {
762
				return $file;
763
			}
764
		}
765
		echo '** Output file ' . $file . ' must be within directory ' . $app_dir . "\n";
766
		return false;
767
	}
768
}
769