/src/Codeception/Command/Build.php

https://bitbucket.org/d1rk/codeception · PHP · 179 lines · 136 code · 32 blank · 11 comment · 16 complexity · 42283fdb8c822a458bf0fec6bfe502bd MD5 · raw file

  1. <?php
  2. namespace Codeception\Command;
  3. use Symfony\Component\Console\Application;
  4. use Symfony\Component\Console\Input\InputDefinition;
  5. use Symfony\Component\Console\Input\InputOption;
  6. use Symfony\Component\Console\Input\InputArgument;
  7. use Symfony\Component\Console\Input\InputInterface;
  8. use Symfony\Component\Console\Output\OutputInterface;
  9. use Symfony\Component\Yaml\Yaml;
  10. use \Symfony\Component\Console\Helper\DialogHelper;
  11. class Build extends Base
  12. {
  13. protected $template = <<<EOF
  14. <?php
  15. // This class was automatically generated by build task
  16. // You can change it manually, but it will be overwritten on next build
  17. use Codeception\Maybe;
  18. %s
  19. %s %s extends %s
  20. {
  21. %s
  22. }
  23. EOF;
  24. protected $methodTemplate = <<<EOF
  25. /**
  26. %s
  27. * @see %s::%s()
  28. *
  29. * ! This method is generated. DO NOT EDIT. !
  30. * ! Documentation taken from corresponding module !
  31. */
  32. public function %s(%s) {
  33. \$this->scenario->%s('%s', func_get_args());
  34. if (\$this->scenario->running()) {
  35. \$result = \$this->scenario->runStep();
  36. return new Maybe(\$result);
  37. }
  38. return new Maybe();
  39. }
  40. EOF;
  41. protected $inheritedMethodTemplate = ' * @method void %s(%s)';
  42. public function getDescription() {
  43. return 'Generates base classes for all suites';
  44. }
  45. protected function configure()
  46. {
  47. $this->setDefinition(array(
  48. new \Symfony\Component\Console\Input\InputOption('silent', '', InputOption::VALUE_NONE, 'Don\'t ask for rebuild')
  49. ));
  50. parent::configure();
  51. }
  52. protected function execute(InputInterface $input, OutputInterface $output)
  53. {
  54. $config = \Codeception\Configuration::config();
  55. $suites = \Codeception\Configuration::suites();
  56. foreach ($suites as $suite) {
  57. $settings = \Codeception\Configuration::suiteSettings($suite, $config);
  58. $modules = \Codeception\Configuration::modules($settings);
  59. $code = array();
  60. $methodCounter = 0;
  61. $aliases = array();
  62. $methods[] = array();
  63. foreach ($modules as $modulename => $module) {
  64. $className = '\Codeception\\Module\\'.$modulename;
  65. $class = new \ReflectionClass($className);
  66. $aliases[] = 'use ' . ltrim($className, '\\') . ';';
  67. $refMethods = $class->getMethods(\ReflectionMethod::IS_PUBLIC);
  68. foreach ($refMethods as $refMethod) {
  69. if (strpos($refMethod->name, '_') === 0) continue;
  70. if (in_array($refMethod->name, $methods)) continue;
  71. $params = array();
  72. foreach ($refMethod->getParameters() as $param) {
  73. if ($param->isOptional()) {
  74. $params[] = '$' . $param->name.' = null';
  75. } else {
  76. $params[] = '$' . $param->name;
  77. };
  78. }
  79. if (0 === strpos($refMethod->name, 'see')) {
  80. $type = 'assertion';
  81. } elseif (0 === strpos($refMethod->name, 'am')) {
  82. $type = 'condition';
  83. } else {
  84. $type = 'action';
  85. }
  86. $doc = $refMethod->getDocComment();
  87. if (!$doc) {
  88. $interfaces = $class->getInterfaces();
  89. foreach ($interfaces as $interface) {
  90. $i = new \ReflectionClass($interface->name);
  91. if ($i->hasMethod($refMethod->name)) {
  92. $doc = $i->getMethod($refMethod->name)->getDocComment();
  93. break;
  94. }
  95. }
  96. }
  97. if (!$doc) {
  98. $parent = new \ReflectionClass($class->getParentClass()->name);
  99. if ($parent->hasMethod($refMethod->name)) {
  100. $doc = $parent->getMethod($refMethod->name)->getDocComment();
  101. }
  102. }
  103. $doc = str_replace('/**', '', $doc);
  104. $doc = trim(str_replace('*/','',$doc));
  105. if (!$doc) $doc = "*";
  106. $params = implode(', ', $params);
  107. $code[] = sprintf($this->methodTemplate, $doc, $modulename, $refMethod->name, $refMethod->name, $params, $type, $refMethod->name);
  108. $methodCounter++;
  109. $methods[] = $refMethod->name;
  110. }
  111. }
  112. // append PHPDoc for abstractGuy methods
  113. $className = '\Codeception\\AbstractGuy';
  114. $class = new \ReflectionClass($className);
  115. $methods = $class->getMethods(\ReflectionMethod::IS_PUBLIC);
  116. $inherited = array();
  117. foreach ($methods as $method) {
  118. if (strpos($method->name, '_') === 0) continue;
  119. if (in_array($method->name, $methods)) continue;
  120. $params = array();
  121. foreach ($method->getParameters() as $param) {
  122. if ($param->isOptional()) {
  123. $params[] = '$' . $param->name.' = null';
  124. } else {
  125. $params[] = '$' . $param->name;
  126. };
  127. }
  128. $params = implode(', ', $params);
  129. $inherited[] = sprintf($this->inheritedMethodTemplate, $method->name, $params);
  130. }
  131. $aliases[] = "\n/**\n * Inherited methods";
  132. $aliases[] = implode("\n",$inherited);
  133. $aliases[] = '*/';
  134. $contents = sprintf($this->template,
  135. implode("\n", $aliases),
  136. 'class',
  137. $settings['class_name'],
  138. '\Codeception\AbstractGuy',
  139. implode("\n\n ", $code));
  140. file_put_contents($file = $settings['path'].$settings['class_name'].'.php', $contents);
  141. $output->writeln("$file generated sucessfully. $methodCounter methods added");
  142. }
  143. }
  144. }