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.

280 line
7.8KB

  1. <?php
  2. /**
  3. * @link http://www.yiiframework.com/
  4. * @copyright Copyright (c) 2008 Yii Software LLC
  5. * @license http://www.yiiframework.com/license/
  6. */
  7. namespace yii\console\controllers;
  8. use Yii;
  9. use yii\console\Controller;
  10. use yii\caching\Cache;
  11. use yii\helpers\Console;
  12. use yii\console\Exception;
  13. /**
  14. * Allows you to flush cache.
  15. *
  16. * see list of available components to flush:
  17. *
  18. * yii cache
  19. *
  20. * flush particular components specified by their names:
  21. *
  22. * yii cache/flush first second third
  23. *
  24. * flush all cache components that can be found in the system
  25. *
  26. * yii cache/flush-all
  27. *
  28. * Note that the command uses cache components defined in your console application configuration file. If components
  29. * configured are different from web application, web application cache won't be cleared. In order to fix it please
  30. * duplicate web application cache components in console config. You can use any component names.
  31. *
  32. * @author Alexander Makarov <sam@rmcreative.ru>
  33. * @author Mark Jebri <mark.github@yandex.ru>
  34. * @since 2.0
  35. */
  36. class CacheController extends Controller
  37. {
  38. /**
  39. * Lists the caches that can be flushed.
  40. */
  41. public function actionIndex()
  42. {
  43. $caches = $this->findCaches();
  44. if (!empty($caches)) {
  45. $this->notifyCachesCanBeFlushed($caches);
  46. } else {
  47. $this->notifyNoCachesFound();
  48. }
  49. }
  50. /**
  51. * Flushes given cache components.
  52. * For example,
  53. *
  54. * ~~~
  55. * # flushes caches specified by their id: "first", "second", "third"
  56. * yii cache/flush first second third
  57. * ~~~
  58. *
  59. */
  60. public function actionFlush()
  61. {
  62. $cachesInput = func_get_args();
  63. if (empty($cachesInput)) {
  64. throw new Exception("You should specify cache components names");
  65. }
  66. $caches = $this->findCaches($cachesInput);
  67. $cachesInfo = [];
  68. $foundCaches = array_keys($caches);
  69. $notFoundCaches = array_diff($cachesInput, array_keys($caches));
  70. if ($notFoundCaches) {
  71. $this->notifyNotFoundCaches($notFoundCaches);
  72. }
  73. if (!$foundCaches) {
  74. $this->notifyNoCachesFound();
  75. return static::EXIT_CODE_NORMAL;
  76. }
  77. if (!$this->confirmFlush($foundCaches)) {
  78. return static::EXIT_CODE_NORMAL;
  79. }
  80. foreach ($caches as $name => $class) {
  81. $cachesInfo[] = [
  82. 'name' => $name,
  83. 'class' => $class,
  84. 'is_flushed' => Yii::$app->get($name)->flush(),
  85. ];
  86. }
  87. $this->notifyFlushed($cachesInfo);
  88. }
  89. /**
  90. * Flushes all caches registered in the system.
  91. */
  92. public function actionFlushAll()
  93. {
  94. $caches = $this->findCaches();
  95. $cachesInfo = [];
  96. if (empty($caches)) {
  97. $this->notifyNoCachesFound();
  98. return static::EXIT_CODE_NORMAL;
  99. }
  100. foreach ($caches as $name => $class) {
  101. $cachesInfo[] = [
  102. 'name' => $name,
  103. 'class' => $class,
  104. 'is_flushed' => Yii::$app->get($name)->flush(),
  105. ];
  106. }
  107. $this->notifyFlushed($cachesInfo);
  108. }
  109. /**
  110. * Clears DB schema cache for a given connection component.
  111. *
  112. * ~~~
  113. * # clears cache schema specified by component id: "db"
  114. * yii cache/flush-schema db
  115. * ~~~
  116. *
  117. * @param string $db id connection component
  118. * @return int exit code
  119. * @throws Exception
  120. * @throws \yii\base\InvalidConfigException
  121. *
  122. * @since 2.0.1
  123. */
  124. public function actionFlushSchema($db = 'db')
  125. {
  126. $connection = Yii::$app->get($db, false);
  127. if ($connection === null) {
  128. $this->stdout("Unknown component \"$db\".\n", Console::FG_RED);
  129. return self::EXIT_CODE_ERROR;
  130. }
  131. if (!$connection instanceof \yii\db\Connection) {
  132. $this->stdout("\"$db\" component doesn't inherit \\yii\\db\\Connection.\n", Console::FG_RED);
  133. return self::EXIT_CODE_ERROR;
  134. } else if (!$this->confirm("Flush cache schema for \"$db\" connection?")) {
  135. return static::EXIT_CODE_NORMAL;
  136. }
  137. try {
  138. $schema = $connection->getSchema();
  139. $schema->refresh();
  140. $this->stdout("Schema cache for component \"$db\", was flushed.\n\n", Console::FG_GREEN);
  141. } catch (\Exception $e) {
  142. $this->stdout($e->getMessage() . "\n\n", Console::FG_RED);
  143. }
  144. }
  145. /**
  146. * Notifies user that given caches are found and can be flushed.
  147. * @param array $caches array of cache component classes
  148. */
  149. private function notifyCachesCanBeFlushed($caches)
  150. {
  151. $this->stdout("The following caches were found in the system:\n\n", Console::FG_YELLOW);
  152. foreach ($caches as $name => $class) {
  153. $this->stdout("\t* $name ($class)\n", Console::FG_GREEN);
  154. }
  155. $this->stdout("\n");
  156. }
  157. /**
  158. * Notifies user that there was not found any cache in the system.
  159. */
  160. private function notifyNoCachesFound()
  161. {
  162. $this->stdout("No cache components were found in the system.\n", Console::FG_RED);
  163. }
  164. /**
  165. * Notifies user that given cache components were not found in the system.
  166. * @param array $cachesNames
  167. */
  168. private function notifyNotFoundCaches($cachesNames)
  169. {
  170. $this->stdout("The following cache components were NOT found:\n\n", Console::FG_RED);
  171. foreach ($cachesNames as $name) {
  172. $this->stdout("\t* $name \n", Console::FG_GREEN);
  173. }
  174. $this->stdout("\n");
  175. }
  176. /**
  177. *
  178. * @param array $caches
  179. */
  180. private function notifyFlushed($caches)
  181. {
  182. $this->stdout("The following cache components were processed:\n\n", Console::FG_YELLOW);
  183. foreach ($caches as $cache) {
  184. $this->stdout("\t* " . $cache['name'] ." (" . $cache['class'] . ")", Console::FG_GREEN);
  185. if (!$cache['is_flushed']) {
  186. $this->stdout(" - not flushed\n", Console::FG_RED);
  187. } else {
  188. $this->stdout("\n");
  189. }
  190. }
  191. $this->stdout("\n");
  192. }
  193. /**
  194. * Prompts user with confirmation if caches should be flushed.
  195. * @param array $cachesNames
  196. * @return boolean
  197. */
  198. private function confirmFlush($cachesNames)
  199. {
  200. $this->stdout("The following cache components will be flushed:\n\n", Console::FG_YELLOW);
  201. foreach ($cachesNames as $name) {
  202. $this->stdout("\t* $name \n", Console::FG_GREEN);
  203. }
  204. return $this->confirm("\nFlush above cache components?");
  205. }
  206. /**
  207. * Returns array of caches in the system, keys are cache components names, values are class names.
  208. * @param array $cachesNames caches to be found
  209. * @return array
  210. */
  211. private function findCaches(array $cachesNames = [])
  212. {
  213. $caches = [];
  214. $components = Yii::$app->getComponents();
  215. $findAll = ($cachesNames == []);
  216. foreach ($components as $name => $component) {
  217. if (!$findAll && !in_array($name, $cachesNames)) {
  218. continue;
  219. }
  220. if ($component instanceof Cache) {
  221. $caches[$name] = get_class($component);
  222. } elseif (is_array($component) && isset($component['class']) && $this->isCacheClass($component['class'])) {
  223. $caches[$name] = $component['class'];
  224. } elseif (is_string($component) && $this->isCacheClass($component)) {
  225. $caches[$name] = $component;
  226. }
  227. }
  228. return $caches;
  229. }
  230. /**
  231. * Checks if given class is a Cache class.
  232. * @param string $className class name.
  233. * @return boolean
  234. */
  235. private function isCacheClass($className)
  236. {
  237. return is_subclass_of($className, Cache::className());
  238. }
  239. }