1: <?php
2: /**
3: * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
4: * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
5: *
6: * Licensed under The MIT License
7: * For full copyright and license information, please see the LICENSE.txt
8: * Redistributions of files must retain the above copyright notice.
9: *
10: * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
11: * @link https://cakephp.org CakePHP(tm) Project
12: * @since 3.0.0
13: * @license https://opensource.org/licenses/mit-license.php MIT License
14: */
15: namespace Cake\Controller\Component;
16:
17: use Cake\Controller\Component;
18: use Cake\Controller\ComponentRegistry;
19: use Cake\Http\Exception\InternalErrorException;
20: use Cake\Utility\Inflector;
21: use Exception;
22:
23: /**
24: * The CakePHP FlashComponent provides a way for you to write a flash variable
25: * to the session from your controllers, to be rendered in a view with the
26: * FlashHelper.
27: *
28: * @method void success(string $message, array $options = []) Set a message using "success" element
29: * @method void error(string $message, array $options = []) Set a message using "error" element
30: */
31: class FlashComponent extends Component
32: {
33: /**
34: * The Session object instance
35: *
36: * @var \Cake\Http\Session
37: * @deprecated 3.7.5 This property will be removed in 4.0.0 in favor of `getSession()` method.
38: */
39: protected $_session;
40:
41: /**
42: * Default configuration
43: *
44: * @var array
45: */
46: protected $_defaultConfig = [
47: 'key' => 'flash',
48: 'element' => 'default',
49: 'params' => [],
50: 'clear' => false,
51: 'duplicate' => true
52: ];
53:
54: /**
55: * Constructor
56: *
57: * @param \Cake\Controller\ComponentRegistry $registry A ComponentRegistry for this component
58: * @param array $config Array of config.
59: */
60: public function __construct(ComponentRegistry $registry, array $config = [])
61: {
62: parent::__construct($registry, $config);
63: $this->_session = $registry->getController()->getRequest()->getSession();
64: }
65:
66: /**
67: * Used to set a session variable that can be used to output messages in the view.
68: * If you make consecutive calls to this method, the messages will stack (if they are
69: * set with the same flash key)
70: *
71: * In your controller: $this->Flash->set('This has been saved');
72: *
73: * ### Options:
74: *
75: * - `key` The key to set under the session's Flash key
76: * - `element` The element used to render the flash message. Default to 'default'.
77: * - `params` An array of variables to make available when using an element
78: * - `clear` A bool stating if the current stack should be cleared to start a new one
79: * - `escape` Set to false to allow templates to print out HTML content
80: *
81: * @param string|\Exception $message Message to be flashed. If an instance
82: * of \Exception the exception message will be used and code will be set
83: * in params.
84: * @param array $options An array of options
85: * @return void
86: */
87: public function set($message, array $options = [])
88: {
89: $options += (array)$this->getConfig();
90:
91: if ($message instanceof Exception) {
92: if (!isset($options['params']['code'])) {
93: $options['params']['code'] = $message->getCode();
94: }
95: $message = $message->getMessage();
96: }
97:
98: if (isset($options['escape']) && !isset($options['params']['escape'])) {
99: $options['params']['escape'] = $options['escape'];
100: }
101:
102: list($plugin, $element) = pluginSplit($options['element']);
103:
104: if ($plugin) {
105: $options['element'] = $plugin . '.Flash/' . $element;
106: } else {
107: $options['element'] = 'Flash/' . $element;
108: }
109:
110: $messages = [];
111: if (!$options['clear']) {
112: $messages = (array)$this->getSession()->read('Flash.' . $options['key']);
113: }
114:
115: if (!$options['duplicate']) {
116: foreach ($messages as $existingMessage) {
117: if ($existingMessage['message'] === $message) {
118: return;
119: }
120: }
121: }
122:
123: $messages[] = [
124: 'message' => $message,
125: 'key' => $options['key'],
126: 'element' => $options['element'],
127: 'params' => $options['params']
128: ];
129:
130: $this->getSession()->write('Flash.' . $options['key'], $messages);
131: }
132:
133: /**
134: * Magic method for verbose flash methods based on element names.
135: *
136: * For example: $this->Flash->success('My message') would use the
137: * success.ctp element under `src/Template/Element/Flash` for rendering the
138: * flash message.
139: *
140: * If you make consecutive calls to this method, the messages will stack (if they are
141: * set with the same flash key)
142: *
143: * Note that the parameter `element` will be always overridden. In order to call a
144: * specific element from a plugin, you should set the `plugin` option in $args.
145: *
146: * For example: `$this->Flash->warning('My message', ['plugin' => 'PluginName'])` would
147: * use the warning.ctp element under `plugins/PluginName/src/Template/Element/Flash` for
148: * rendering the flash message.
149: *
150: * @param string $name Element name to use.
151: * @param array $args Parameters to pass when calling `FlashComponent::set()`.
152: * @return void
153: * @throws \Cake\Http\Exception\InternalErrorException If missing the flash message.
154: */
155: public function __call($name, $args)
156: {
157: $element = Inflector::underscore($name);
158:
159: if (count($args) < 1) {
160: throw new InternalErrorException('Flash message missing.');
161: }
162:
163: $options = ['element' => $element];
164:
165: if (!empty($args[1])) {
166: if (!empty($args[1]['plugin'])) {
167: $options = ['element' => $args[1]['plugin'] . '.' . $element];
168: unset($args[1]['plugin']);
169: }
170: $options += (array)$args[1];
171: }
172:
173: $this->set($args[0], $options);
174: }
175:
176: /**
177: * Returns current session object from a controller request.
178: *
179: * @return \Cake\Http\Session
180: */
181: protected function getSession()
182: {
183: return $this->getController()->getRequest()->getSession();
184: }
185: }
186: