Teknik is a suite of services with attractive and functional interfaces. https://www.teknik.io/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Development.php 6.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. <?php
  2. /**
  3. * Piwik - free/libre analytics platform
  4. *
  5. * @link http://piwik.org
  6. * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
  7. *
  8. */
  9. namespace Piwik;
  10. use Exception;
  11. /**
  12. * Development related checks and tools. You can enable/disable development using `./console development:enable` and
  13. * `./console development:disable`. The intention of the development mode and this class is to support the developer
  14. * as much as possible by doing some additional checks if the development mode is enabled. For instance if a developer
  15. * has to register any class/method we can make sure whether they actually exist and if not display a useful error
  16. * message. This helps the user to find for instance simple typos and makes sure it will actually work even if he
  17. * forgets to test it.
  18. */
  19. class Development
  20. {
  21. private static $isEnabled = null;
  22. /**
  23. * Returns `true` if development mode is enabled and `false` otherwise.
  24. *
  25. * @return bool
  26. */
  27. public static function isEnabled()
  28. {
  29. if (is_null(self::$isEnabled)) {
  30. self::$isEnabled = (bool) Config::getInstance()->Development['enabled'];
  31. }
  32. return self::$isEnabled;
  33. }
  34. /**
  35. * Verifies whether a className of object implements the given method. It does not check whether the given method
  36. * is actually callable (public).
  37. *
  38. * @param string|object $classOrObject
  39. * @param string $method
  40. *
  41. * @return bool true if the method exists, false otherwise.
  42. */
  43. public static function methodExists($classOrObject, $method)
  44. {
  45. if (is_string($classOrObject)) {
  46. return class_exists($classOrObject) && method_exists($classOrObject, $method);
  47. }
  48. return method_exists($classOrObject, $method);
  49. }
  50. /**
  51. * Formats a method call depending on the given class/object and method name. It does not perform any checks whether
  52. * does actually exists.
  53. *
  54. * @param string|object $classOrObject
  55. * @param string $method
  56. *
  57. * @return string Formatted method call. Example: "MyNamespace\MyClassname::methodName()"
  58. */
  59. public static function formatMethodCall($classOrObject, $method)
  60. {
  61. if (is_object($classOrObject)) {
  62. $classOrObject = get_class($classOrObject);
  63. }
  64. return $classOrObject . '::' . $method . '()';
  65. }
  66. /**
  67. * Checks whether the given method is actually callable on the given class/object if the development mode is
  68. * enabled. En error will be triggered if the method does not exist or is not callable (public) containing a useful
  69. * error message for the developer.
  70. *
  71. * @param string|object $classOrObject
  72. * @param string $method
  73. * @param string $prefixMessageIfError You can prepend any string to the error message in case the method is not
  74. * callable.
  75. */
  76. public static function checkMethodIsCallable($classOrObject, $method, $prefixMessageIfError)
  77. {
  78. if (!self::isEnabled()) {
  79. return;
  80. }
  81. self::checkMethodExists($classOrObject, $method, $prefixMessageIfError);
  82. if (!self::isCallableMethod($classOrObject, $method)) {
  83. self::error($prefixMessageIfError . ' "' . self::formatMethodCall($classOrObject, $method) . '" is not callable. Please make sure to method is public');
  84. }
  85. }
  86. /**
  87. * Checks whether the given method is actually callable on the given class/object if the development mode is
  88. * enabled. En error will be triggered if the method does not exist or is not callable (public) containing a useful
  89. * error message for the developer.
  90. *
  91. * @param string|object $classOrObject
  92. * @param string $method
  93. * @param string $prefixMessageIfError You can prepend any string to the error message in case the method is not
  94. * callable.
  95. */
  96. public static function checkMethodExists($classOrObject, $method, $prefixMessageIfError)
  97. {
  98. if (!self::isEnabled()) {
  99. return;
  100. }
  101. if (!self::methodExists($classOrObject, $method)) {
  102. self::error($prefixMessageIfError . ' "' . self::formatMethodCall($classOrObject, $method) . '" does not exist. Please make sure to define such a method.');
  103. }
  104. }
  105. /**
  106. * Verify whether the given method actually exists and is callable (public).
  107. *
  108. * @param string|object $classOrObject
  109. * @param string $method
  110. * @return bool
  111. */
  112. public static function isCallableMethod($classOrObject, $method)
  113. {
  114. if (!self::methodExists($classOrObject, $method)) {
  115. return false;
  116. }
  117. $reflection = new \ReflectionMethod($classOrObject, $method);
  118. return $reflection->isPublic();
  119. }
  120. /**
  121. * Triggers an error if the development mode is enabled. Depending on the current environment / mode it will either
  122. * log the given message or throw an exception to make sure it will be displayed in the Piwik UI.
  123. *
  124. * @param string $message
  125. * @throws Exception
  126. */
  127. public static function error($message)
  128. {
  129. if (!self::isEnabled()) {
  130. return;
  131. }
  132. $message .= ' (This error is only shown in development mode)';
  133. if (SettingsServer::isTrackerApiRequest()
  134. || Common::isPhpCliMode()) {
  135. Log::error($message);
  136. } else {
  137. throw new Exception($message);
  138. }
  139. }
  140. public static function getMethodSourceCode($className, $methodName)
  141. {
  142. $method = new \ReflectionMethod($className, $methodName);
  143. $file = new \SplFileObject($method->getFileName());
  144. $offset = $method->getStartLine() - 1;
  145. $count = $method->getEndLine() - $method->getStartLine() + 1;
  146. $fileIterator = new \LimitIterator($file, $offset, $count);
  147. $methodCode = "\n " . $method->getDocComment() . "\n";
  148. foreach($fileIterator as $line) {
  149. $methodCode .= $line;
  150. }
  151. $methodCode .= "\n";
  152. return $methodCode;
  153. }
  154. public static function getUseStatements($className)
  155. {
  156. $class = new \ReflectionClass($className);
  157. $file = new \SplFileObject($class->getFileName());
  158. $fileIterator = new \LimitIterator($file, 0, $class->getStartLine());
  159. $uses = array();
  160. foreach($fileIterator as $line) {
  161. if (preg_match('/(\s*)use (.+)/', $line, $match)) {
  162. $uses[] = trim($match[2]);
  163. }
  164. }
  165. return $uses;
  166. }
  167. }