1 <?php
2
3 /*
4 * This file is part of the Icybee package.
5 *
6 * (c) Olivier Laviale <olivier.laviale@gmail.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12 namespace Icybee\Modules\Sites;
13
14 use ICanBoogie\Core;
15 use ICanBoogie\Errors;
16 use ICanBoogie\HTTP\Dispatcher;
17 use ICanBoogie\HTTP\RedirectResponse;
18 use ICanBoogie\HTTP\Request;
19 use ICanBoogie\Routing;
20
21 class Hooks
22 {
23 /**
24 * Initializes the {@link Core::$site}, {@link Core::$locale} and {@link Core::$timezone}
25 * properties of the core object. The {@link Core::$timezone} property is only initialized is
26 * it is defined be the site.
27 *
28 * If the current site has a path, the {@link Routing\contextualize()} and
29 * {@link Routing\decontextualize()} helpers are patched.
30 *
31 * @param Core\RunEvent $event
32 * @param Core $target
33 */
34 static public function on_core_run(Core\RunEvent $event, Core $target)
35 {
36 #
37 # If the ICanBoogie\ActiveRecord\StatementInvalid is raised it might be becuase the
38 # module is not installed, in that case we silently return, otherwise we re-throw the
39 # exception.
40 #
41
42 try
43 {
44 $target->site = $site = Model::find_by_request($event->request);
45 }
46 catch (\ICanBoogie\ActiveRecord\StatementInvalid $e)
47 {
48 global $core;
49
50 if (!$core->models['sites']->is_installed(new Errors()))
51 {
52 return;
53 }
54
55 throw $e;
56 }
57
58 $target->locale = $site->language;
59
60 if ($site->timezone)
61 {
62 $target->timezone = $site->timezone;
63 }
64
65 $path = $site->path;
66
67 if ($path)
68 {
69 Routing\Helpers::patch('contextualize', function ($str) use ($path)
70 {
71 return $path . $str;
72 });
73
74 Routing\Helpers::patch('decontextualize', function ($str) use ($path)
75 {
76 if (strpos($str, $path . '/') === 0)
77 {
78 $str = substr($str, strlen($path));
79 }
80
81 return $str;
82 });
83 }
84 }
85
86 /**
87 * Redirects the request to the first available website to the user if the request matches
88 * none.
89 *
90 * Only online websites are used if the user is a guest or a member.
91 *
92 * @param Dispatcher\BeforeDispatchEvent $event
93 * @param Dispatcher $target
94 */
95 static public function before_http_dispatcher_dispatch(Dispatcher\BeforeDispatchEvent $event, Dispatcher $target)
96 {
97 global $core;
98
99 if ($core->site_id)
100 {
101 return;
102 }
103
104 $request = $event->request;
105
106 if (!in_array($request->method, array(Request::METHOD_ANY, Request::METHOD_GET, Request::METHOD_HEAD)))
107 {
108 return;
109 }
110
111 $path = \ICanBoogie\normalize_url_path(\ICanBoogie\Routing\decontextualize($request->path));
112
113 if (strpos($path, '/api/') === 0)
114 {
115 return;
116 }
117
118 try
119 {
120 $query = $core->models['sites']->order('weight');
121 $user = $core->user;
122
123 if ($user->is_guest || $user instanceof \Icybee\Modules\Members\Member)
124 {
125 $query->filter_by_status(Site::STATUS_OK);
126 }
127
128 $site = $query->one;
129
130 if ($site)
131 {
132 $request_url = \ICanBoogie\normalize_url_path($core->site->url . $request->path);
133 $location = \ICanBoogie\normalize_url_path($site->url . $path);
134
135 #
136 # we don't redirect if the redirect location is the same as the request URL.
137 #
138
139 if ($request_url != $location)
140 {
141 $query_string = $request->query_string;
142
143 if ($query_string)
144 {
145 $location .= '?' . $query_string;
146 }
147
148 $event->response = new RedirectResponse
149 (
150 $location, 302, array
151 (
152 'Icybee-Redirected-By' => __CLASS__ . '::' . __FUNCTION__
153 )
154 );
155
156 return;
157 }
158 }
159 }
160 catch (\Exception $e) { }
161
162 \ICanBoogie\log_error('You are on a dummy website. You should check which websites are available or create one if none are.');
163 }
164
165 /**
166 * Returns the site active record associated to the node.
167 *
168 * This is the getter for the nodes' `site` magic property.
169 *
170 * <pre>
171 * <?php
172 *
173 * $core->models['nodes']->one->site;
174 * </pre>
175 *
176 * @param \Icybee\Modules\Nodes\Node $node
177 *
178 * @return Site|null The site active record associate with the node,
179 * or null if the node is not associated to a specific site.
180 */
181 static public function get_node_site(\Icybee\Modules\Nodes\Node $node)
182 {
183 global $core;
184
185 if (!$node->siteid)
186 {
187 return;
188 }
189
190 return $core->site_id == $node->siteid ? $core->site : $core->models['sites'][$node->siteid];
191 }
192
193 /**
194 * Returns the active record for the current site.
195 *
196 * This is the getter for the core's {@link Core::$site} magic property.
197 *
198 * <pre>
199 * <?php
200 *
201 * $core->site;
202 * </pre>
203 *
204 * @return Site
205 */
206 static public function get_core_site(Core $core)
207 {
208 return Model::find_by_request($core->request ?: $core->initial_request);
209 }
210
211 /**
212 * Returns the key of the current site.
213 *
214 * This is the getter for the core's {@link Site::site_id} magic
215 * property.
216 *
217 * <pre>
218 * <?php
219 *
220 * $core->site_id;
221 * </pre>
222 *
223 * @param Core $core
224 *
225 * @return int
226 */
227 static public function get_core_site_id(Core $core)
228 {
229 $site = self::get_core_site($core);
230
231 return $site ? $site->siteid : null;
232 }
233
234 /**
235 * Returns the site active record for a request.
236 *
237 * This is the getter for the {@link \ICanBoogie\HTTP\Request\Context::site} magic property.
238 *
239 * <pre>
240 * <?php
241 *
242 * $core->request->context->site;
243 * </pre>
244 *
245 * @return Site
246 */
247 static public function get_site_for_request_context(Request\Context $context)
248 {
249 return Model::find_by_request($context->request);
250 }
251
252 /**
253 * Returns the identifier of the site for a request.
254 *
255 * This is the getter for the {@link \ICanBoogie\HTTP\Request\Context::site_id} magic property.
256 *
257 * <pre>
258 * <?php
259 *
260 * $core->request->context->site_id;
261 * </pre>
262 *
263 * @return int
264 */
265 static public function get_site_id_for_request_context(Request\Context $context)
266 {
267 return $context->site ? $context->site->siteid : null;
268 }
269 }