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.

285 lines
8.1KB

  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. * Both APC and OpCache aren't shared between PHP processes so flushing cache from command line has no effect on web.
  33. * Flushing web cache could be either done by:
  34. *
  35. * - Putting a php file under web root and calling it via HTTP
  36. * - Using [Cachetool](http://gordalina.github.io/cachetool/)
  37. *
  38. * @author Alexander Makarov <sam@rmcreative.ru>
  39. * @author Mark Jebri <mark.github@yandex.ru>
  40. * @since 2.0
  41. */
  42. class CacheController extends Controller
  43. {
  44. /**
  45. * Lists the caches that can be flushed.
  46. */
  47. public function actionIndex()
  48. {
  49. $caches = $this->findCaches();
  50. if (!empty($caches)) {
  51. $this->notifyCachesCanBeFlushed($caches);
  52. } else {
  53. $this->notifyNoCachesFound();
  54. }
  55. }
  56. /**
  57. * Flushes given cache components.
  58. * For example,
  59. *
  60. * ```
  61. * # flushes caches specified by their id: "first", "second", "third"
  62. * yii cache/flush first second third
  63. * ```
  64. *
  65. */
  66. public function actionFlush()
  67. {
  68. $cachesInput = func_get_args();
  69. if (empty($cachesInput)) {
  70. throw new Exception('You should specify cache components names');
  71. }
  72. $caches = $this->findCaches($cachesInput);
  73. $cachesInfo = [];
  74. $foundCaches = array_keys($caches);
  75. $notFoundCaches = array_diff($cachesInput, array_keys($caches));
  76. if ($notFoundCaches) {
  77. $this->notifyNotFoundCaches($notFoundCaches);
  78. }
  79. if (!$foundCaches) {
  80. $this->notifyNoCachesFound();
  81. return static::EXIT_CODE_NORMAL;
  82. }
  83. if (!$this->confirmFlush($foundCaches)) {
  84. return static::EXIT_CODE_NORMAL;
  85. }
  86. foreach ($caches as $name => $class) {
  87. $cachesInfo[] = [
  88. 'name' => $name,
  89. 'class' => $class,
  90. 'is_flushed' => Yii::$app->get($name)->flush(),
  91. ];
  92. }
  93. $this->notifyFlushed($cachesInfo);
  94. }
  95. /**
  96. * Flushes all caches registered in the system.
  97. */
  98. public function actionFlushAll()
  99. {
  100. $caches = $this->findCaches();
  101. $cachesInfo = [];
  102. if (empty($caches)) {
  103. $this->notifyNoCachesFound();
  104. return static::EXIT_CODE_NORMAL;
  105. }
  106. foreach ($caches as $name => $class) {
  107. $cachesInfo[] = [
  108. 'name' => $name,
  109. 'class' => $class,
  110. 'is_flushed' => Yii::$app->get($name)->flush(),
  111. ];
  112. }
  113. $this->notifyFlushed($cachesInfo);
  114. }
  115. /**
  116. * Clears DB schema cache for a given connection component.
  117. *
  118. * ```
  119. * # clears cache schema specified by component id: "db"
  120. * yii cache/flush-schema db
  121. * ```
  122. *
  123. * @param string $db id connection component
  124. * @return integer exit code
  125. * @throws Exception
  126. * @throws \yii\base\InvalidConfigException
  127. *
  128. * @since 2.0.1
  129. */
  130. public function actionFlushSchema($db = 'db')
  131. {
  132. $connection = Yii::$app->get($db, false);
  133. if ($connection === null) {
  134. $this->stdout("Unknown component \"$db\".\n", Console::FG_RED);
  135. return self::EXIT_CODE_ERROR;
  136. }
  137. if (!$connection instanceof \yii\db\Connection) {
  138. $this->stdout("\"$db\" component doesn't inherit \\yii\\db\\Connection.\n", Console::FG_RED);
  139. return self::EXIT_CODE_ERROR;
  140. } elseif (!$this->confirm("Flush cache schema for \"$db\" connection?")) {
  141. return static::EXIT_CODE_NORMAL;
  142. }
  143. try {
  144. $schema = $connection->getSchema();
  145. $schema->refresh();
  146. $this->stdout("Schema cache for component \"$db\", was flushed.\n\n", Console::FG_GREEN);
  147. } catch (\Exception $e) {
  148. $this->stdout($e->getMessage() . "\n\n", Console::FG_RED);
  149. }
  150. }
  151. /**
  152. * Notifies user that given caches are found and can be flushed.
  153. * @param array $caches array of cache component classes
  154. */
  155. private function notifyCachesCanBeFlushed($caches)
  156. {
  157. $this->stdout("The following caches were found in the system:\n\n", Console::FG_YELLOW);
  158. foreach ($caches as $name => $class) {
  159. $this->stdout("\t* $name ($class)\n", Console::FG_GREEN);
  160. }
  161. $this->stdout("\n");
  162. }
  163. /**
  164. * Notifies user that there was not found any cache in the system.
  165. */
  166. private function notifyNoCachesFound()
  167. {
  168. $this->stdout("No cache components were found in the system.\n", Console::FG_RED);
  169. }
  170. /**
  171. * Notifies user that given cache components were not found in the system.
  172. * @param array $cachesNames
  173. */
  174. private function notifyNotFoundCaches($cachesNames)
  175. {
  176. $this->stdout("The following cache components were NOT found:\n\n", Console::FG_RED);
  177. foreach ($cachesNames as $name) {
  178. $this->stdout("\t* $name \n", Console::FG_GREEN);
  179. }
  180. $this->stdout("\n");
  181. }
  182. /**
  183. *
  184. * @param array $caches
  185. */
  186. private function notifyFlushed($caches)
  187. {
  188. $this->stdout("The following cache components were processed:\n\n", Console::FG_YELLOW);
  189. foreach ($caches as $cache) {
  190. $this->stdout("\t* " . $cache['name'] .' (' . $cache['class'] . ')', Console::FG_GREEN);
  191. if (!$cache['is_flushed']) {
  192. $this->stdout(" - not flushed\n", Console::FG_RED);
  193. } else {
  194. $this->stdout("\n");
  195. }
  196. }
  197. $this->stdout("\n");
  198. }
  199. /**
  200. * Prompts user with confirmation if caches should be flushed.
  201. * @param array $cachesNames
  202. * @return boolean
  203. */
  204. private function confirmFlush($cachesNames)
  205. {
  206. $this->stdout("The following cache components will be flushed:\n\n", Console::FG_YELLOW);
  207. foreach ($cachesNames as $name) {
  208. $this->stdout("\t* $name \n", Console::FG_GREEN);
  209. }
  210. return $this->confirm("\nFlush above cache components?");
  211. }
  212. /**
  213. * Returns array of caches in the system, keys are cache components names, values are class names.
  214. * @param array $cachesNames caches to be found
  215. * @return array
  216. */
  217. private function findCaches(array $cachesNames = [])
  218. {
  219. $caches = [];
  220. $components = Yii::$app->getComponents();
  221. $findAll = ($cachesNames === []);
  222. foreach ($components as $name => $component) {
  223. if (!$findAll && !in_array($name, $cachesNames)) {
  224. continue;
  225. }
  226. if ($component instanceof Cache) {
  227. $caches[$name] = get_class($component);
  228. } elseif (is_array($component) && isset($component['class']) && $this->isCacheClass($component['class'])) {
  229. $caches[$name] = $component['class'];
  230. } elseif (is_string($component) && $this->isCacheClass($component)) {
  231. $caches[$name] = $component;
  232. }
  233. }
  234. return $caches;
  235. }
  236. /**
  237. * Checks if given class is a Cache class.
  238. * @param string $className class name.
  239. * @return boolean
  240. */
  241. private function isCacheClass($className)
  242. {
  243. return is_subclass_of($className, Cache::className());
  244. }
  245. }