flack /
openpsa
| 1 | <?php |
||||
| 2 | /** |
||||
| 3 | * @package midcom |
||||
| 4 | * @author The Midgard Project, http://www.midgard-project.org |
||||
| 5 | * @copyright The Midgard Project, http://www.midgard-project.org |
||||
| 6 | * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License |
||||
| 7 | */ |
||||
| 8 | |||||
| 9 | use Symfony\Component\HttpFoundation\Request; |
||||
| 10 | use Symfony\Component\HttpKernel\HttpKernelInterface; |
||||
| 11 | use Symfony\Component\HttpKernel\Kernel; |
||||
| 12 | use Symfony\Component\Config\Loader\LoaderInterface; |
||||
| 13 | use Symfony\Component\DependencyInjection\ContainerBuilder; |
||||
| 14 | use midcom\bundle\midcomBundle; |
||||
| 15 | use Symfony\Component\HttpFoundation\Response; |
||||
| 16 | |||||
| 17 | /** |
||||
| 18 | * Main controlling instance of the MidCOM Framework |
||||
| 19 | * |
||||
| 20 | * @property midcom_services_i18n $i18n |
||||
| 21 | * @property midcom_helper__componentloader $componentloader |
||||
| 22 | * @property midcom_services_dbclassloader $dbclassloader |
||||
| 23 | * @property midcom_helper__dbfactory $dbfactory |
||||
| 24 | * @property midcom_helper_head $head |
||||
| 25 | * @property midcom_helper_style $style |
||||
| 26 | * @property midcom_services_auth $auth |
||||
| 27 | * @property midcom_services_permalinks $permalinks |
||||
| 28 | * @property midcom_services_toolbars $toolbars |
||||
| 29 | * @property midcom_services_uimessages $uimessages |
||||
| 30 | * @property midcom_services_metadata $metadata |
||||
| 31 | * @property midcom_services_rcs $rcs |
||||
| 32 | * @property midcom_services__sessioning $session |
||||
| 33 | * @property midcom_services_indexer $indexer |
||||
| 34 | * @property midcom_config $config |
||||
| 35 | * @property midcom_services_cache $cache |
||||
| 36 | * @property Symfony\Component\EventDispatcher\EventDispatcher $dispatcher |
||||
| 37 | * @property midcom_debug $debug |
||||
| 38 | * @package midcom |
||||
| 39 | */ |
||||
| 40 | class midcom_application extends Kernel |
||||
| 41 | { |
||||
| 42 | private ?Request $request = null; |
||||
| 43 | |||||
| 44 | /** |
||||
| 45 | * Set this variable to true during the handle phase of your component to |
||||
| 46 | * not show the site's style around the component output. This is mainly |
||||
| 47 | * targeted at XML output like RSS feeds and similar things. The output |
||||
| 48 | * handler of the site, excluding the style-init/-finish tags will be executed |
||||
| 49 | * immediately after the handle phase |
||||
| 50 | * |
||||
| 51 | * Changing this flag after the handle phase or for dynamically loaded |
||||
| 52 | * components won't change anything. |
||||
| 53 | */ |
||||
| 54 | public bool $skip_page_style = false; |
||||
| 55 | |||||
| 56 | private ?string $project_dir = null; |
||||
| 57 | |||||
| 58 | private midcom_config $cfg; |
||||
| 59 | |||||
| 60 | public function __construct(string $environment, bool $debug) |
||||
| 61 | { |
||||
| 62 | $this->cfg = new midcom_config; |
||||
| 63 | parent::__construct($environment, $debug); |
||||
| 64 | } |
||||
| 65 | |||||
| 66 | 44 | private function get_request() : Request |
|||
| 67 | { |
||||
| 68 | 44 | return $this->request ??= Request::createFromGlobals(); |
|||
| 69 | } |
||||
| 70 | |||||
| 71 | public function registerContainerConfiguration(LoaderInterface $loader) : void |
||||
| 72 | { |
||||
| 73 | if (file_exists($this->getProjectDir() . '/config/services.yml')) { |
||||
| 74 | $loader->load($this->getProjectDir() . '/config/services.yml'); |
||||
| 75 | } |
||||
| 76 | if ($classes = midcom::get_registered_service_classes()) { |
||||
| 77 | $loader->load(function (ContainerBuilder $container) use ($classes) { |
||||
| 78 | foreach ($classes as $id => $class) { |
||||
| 79 | $container->findDefinition($id)->setClass($class); |
||||
| 80 | } |
||||
| 81 | }); |
||||
| 82 | } |
||||
| 83 | } |
||||
| 84 | |||||
| 85 | protected function initializeContainer() : void |
||||
| 86 | { |
||||
| 87 | parent::initializeContainer(); |
||||
| 88 | $this->container->set('config', $this->cfg); |
||||
| 89 | } |
||||
| 90 | |||||
| 91 | protected function buildContainer() : ContainerBuilder |
||||
| 92 | { |
||||
| 93 | $container = parent::buildContainer(); |
||||
| 94 | $this->cfg->export_to($container); |
||||
| 95 | return $container; |
||||
| 96 | } |
||||
| 97 | |||||
| 98 | public function registerBundles() : iterable |
||||
| 99 | { |
||||
| 100 | return [new midcomBundle]; |
||||
| 101 | } |
||||
| 102 | |||||
| 103 | 2 | public function getProjectDir() : string |
|||
| 104 | { |
||||
| 105 | 2 | if ($this->project_dir === null) { |
|||
| 106 | if (basename(dirname(__DIR__, 4)) === 'vendor') { |
||||
| 107 | // this is the case where we're installed as a dependency |
||||
| 108 | $this->project_dir = dirname(__DIR__, 5); |
||||
| 109 | } else { |
||||
| 110 | $this->project_dir = dirname(__DIR__, 2); |
||||
| 111 | } |
||||
| 112 | } |
||||
| 113 | 2 | return $this->project_dir; |
|||
| 114 | } |
||||
| 115 | |||||
| 116 | 367 | public function getCacheDir() : string |
|||
| 117 | { |
||||
| 118 | 367 | return $this->cfg->get('cache_base_directory') ?: parent::getCacheDir(); |
|||
| 119 | } |
||||
| 120 | |||||
| 121 | /** |
||||
| 122 | * Magic getter for service loading |
||||
| 123 | */ |
||||
| 124 | 734 | public function __get($key) |
|||
| 125 | { |
||||
| 126 | 734 | if (!$this->booted) { |
|||
| 127 | $this->boot(); |
||||
| 128 | } |
||||
| 129 | 734 | return $this->getContainer()->get($key); |
|||
| 130 | } |
||||
| 131 | |||||
| 132 | /** |
||||
| 133 | * Magic setter |
||||
| 134 | */ |
||||
| 135 | public function __set($key, $value) |
||||
| 136 | { |
||||
| 137 | if (!$this->booted) { |
||||
| 138 | $this->boot(); |
||||
| 139 | } |
||||
| 140 | $this->getContainer()->set($key, $value); |
||||
| 141 | } |
||||
| 142 | |||||
| 143 | /* ************************************************************************* |
||||
| 144 | * Control framework: |
||||
| 145 | * codeinit - Handle the current request |
||||
| 146 | * dynamic_load - Dynamically load and execute a URL |
||||
| 147 | * finish - Cleanup Work |
||||
| 148 | */ |
||||
| 149 | |||||
| 150 | /** |
||||
| 151 | * Initialize the URL parser and process the request. |
||||
| 152 | * |
||||
| 153 | * This function must be called before any output starts. |
||||
| 154 | */ |
||||
| 155 | public function codeinit() |
||||
| 156 | { |
||||
| 157 | $request = $this->get_request(); |
||||
| 158 | try { |
||||
| 159 | $response = $this->handle($request); |
||||
| 160 | $response->send(); |
||||
| 161 | $this->terminate($request, $response); |
||||
| 162 | } catch (Error $e) { |
||||
| 163 | $this->getHttpKernel()->terminateWithException($e); |
||||
|
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||||
| 164 | } |
||||
| 165 | } |
||||
| 166 | |||||
| 167 | /** |
||||
| 168 | * Dynamically execute a subrequest and insert its output in place of the |
||||
| 169 | * function call. |
||||
| 170 | * |
||||
| 171 | * It tries to load the component referenced with the URL $url and executes |
||||
| 172 | * it as if it was used as primary component. |
||||
| 173 | * |
||||
| 174 | * This is only possible if the system is in the Page-Style output phase. It |
||||
| 175 | * cannot be used within code-init or during the output phase of another |
||||
| 176 | * component. |
||||
| 177 | * |
||||
| 178 | * Example code, executed on a site's homepage, it will load the news listing from |
||||
| 179 | * the given URL and display it using a substyle of the node style that is assigned |
||||
| 180 | * to the loaded one: |
||||
| 181 | * |
||||
| 182 | * <code> |
||||
| 183 | * $blog = '/blog/latest/3/'; |
||||
| 184 | * $substyle = 'homepage'; |
||||
| 185 | * midcom::get()->dynamic_load("/midcom-substyle-{$substyle}/{$blog}"); |
||||
| 186 | * </code> |
||||
| 187 | * |
||||
| 188 | * Results of dynamic_loads are cached with the system cache strategy |
||||
| 189 | * |
||||
| 190 | * @param string $url The URL, relative to the Midgard Page, that is to be requested. |
||||
| 191 | */ |
||||
| 192 | 17 | public function dynamic_load(string $url, string $substyle = '') |
|||
| 193 | { |
||||
| 194 | 17 | debug_add("Dynamic load of URL {$url}"); |
|||
| 195 | 17 | $url = midcom_connection::get_url('prefix') . $url; |
|||
| 196 | |||||
| 197 | // Determine new Context ID and set current context, |
||||
| 198 | // enter that context and prepare its data structure. |
||||
| 199 | 17 | $oldcontext = midcom_core_context::get(); |
|||
| 200 | 17 | $context = midcom_core_context::enter($url, $oldcontext->get_key(MIDCOM_CONTEXT_ROOTTOPIC)); |
|||
|
0 ignored issues
–
show
It seems like
$oldcontext->get_key(MIDCOM_CONTEXT_ROOTTOPIC) can also be of type false; however, parameter $topic of midcom_core_context::enter() does only seem to accept midcom_db_topic|null, maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
| 201 | 17 | if ($substyle) { |
|||
| 202 | $context->set_key(MIDCOM_CONTEXT_SUBSTYLE, $substyle); |
||||
| 203 | } |
||||
| 204 | |||||
| 205 | 17 | $request = $this->get_request()->duplicate([], attributes: []); |
|||
| 206 | 17 | $request->attributes->set('context', $context); |
|||
| 207 | |||||
| 208 | 17 | $backup = $this->skip_page_style; |
|||
| 209 | 17 | $this->skip_page_style = true; |
|||
| 210 | try { |
||||
| 211 | 17 | $response = $this->handle($request, HttpKernelInterface::SUB_REQUEST, false); |
|||
| 212 | 4 | echo $response->getContent(); |
|||
| 213 | 15 | } catch (midcom_error_notfound | midcom_error_forbidden $e) { |
|||
| 214 | 15 | $e->log(); |
|||
| 215 | } finally { |
||||
| 216 | 17 | $this->skip_page_style = $backup; |
|||
| 217 | 17 | midcom_core_context::leave(); |
|||
| 218 | } |
||||
| 219 | } |
||||
| 220 | |||||
| 221 | /** |
||||
| 222 | * Stop the PHP process |
||||
| 223 | * |
||||
| 224 | * @deprecated |
||||
| 225 | */ |
||||
| 226 | public function finish() |
||||
| 227 | { |
||||
| 228 | _midcom_stop_request(); |
||||
| 229 | } |
||||
| 230 | |||||
| 231 | /* ************************************************************************* |
||||
| 232 | * Framework Access Helper functions |
||||
| 233 | */ |
||||
| 234 | |||||
| 235 | /** |
||||
| 236 | * Retrieves the name of the current host, fully qualified with protocol and |
||||
| 237 | * port (http[s]://www.my.domain.com[:1234]) |
||||
| 238 | */ |
||||
| 239 | 29 | function get_host_name() : string |
|||
|
0 ignored issues
–
show
|
|||||
| 240 | { |
||||
| 241 | 29 | return $this->get_request()->getSchemeAndHttpHost(); |
|||
| 242 | } |
||||
| 243 | |||||
| 244 | /** |
||||
| 245 | * Return the prefix required to build relative links on the current site. |
||||
| 246 | * This includes the http[s] prefix, the hosts port (if necessary) and the |
||||
| 247 | * base url of the Midgard Page. Be aware, that this does *not* point to the |
||||
| 248 | * base host of the site. |
||||
| 249 | * |
||||
| 250 | * e.g. something like http[s]://www.domain.com[:8080]/host_prefix/page_prefix/ |
||||
| 251 | */ |
||||
| 252 | function get_page_prefix() : string |
||||
|
0 ignored issues
–
show
|
|||||
| 253 | { |
||||
| 254 | return $this->get_host_name() . midcom_connection::get_url('self'); |
||||
| 255 | } |
||||
| 256 | |||||
| 257 | /** |
||||
| 258 | * Return the prefix required to build relative links on the current site. |
||||
| 259 | * This includes the http[s] prefix, the hosts port (if necessary) and the |
||||
| 260 | * base url of the main host. This is not necessarily the currently active |
||||
| 261 | * MidCOM Page however, use the get_page_prefix() function for that. |
||||
| 262 | * |
||||
| 263 | * e.g. something like http[s]://www.domain.com[:8080]/host_prefix/ |
||||
| 264 | */ |
||||
| 265 | 7 | function get_host_prefix() : string |
|||
|
0 ignored issues
–
show
|
|||||
| 266 | { |
||||
| 267 | 7 | $host_prefix = midcom_connection::get_url('prefix'); |
|||
| 268 | 7 | if (!str_starts_with($host_prefix, '/')) { |
|||
|
0 ignored issues
–
show
It seems like
$host_prefix can also be of type null; however, parameter $haystack of str_starts_with() does only seem to accept string, maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
| 269 | 7 | $host_prefix = '/' . $host_prefix; |
|||
| 270 | } |
||||
| 271 | 7 | if (!str_ends_with($host_prefix, '/')) { |
|||
| 272 | $host_prefix .= '/'; |
||||
| 273 | } |
||||
| 274 | 7 | return $this->get_host_name() . $host_prefix; |
|||
| 275 | } |
||||
| 276 | |||||
| 277 | /* ************************************************************************* |
||||
| 278 | * Generic Helper Functions not directly related with MidCOM: |
||||
| 279 | * |
||||
| 280 | * relocate - executes a HTTP relocation to the given URL |
||||
| 281 | */ |
||||
| 282 | |||||
| 283 | /** |
||||
| 284 | * Sends a header out to the client. |
||||
| 285 | * |
||||
| 286 | * This function is syntactically identical to |
||||
| 287 | * the regular PHP header() function, but is integrated into the framework. Every |
||||
| 288 | * Header you sent must go through this function or it might be lost later on; |
||||
| 289 | * this is especially important with caching. |
||||
| 290 | */ |
||||
| 291 | 17 | public function header(string $header, int $response_code = 0) |
|||
| 292 | { |
||||
| 293 | 17 | $this->cache->content->register_sent_header($header); |
|||
| 294 | 17 | midcom_compat_environment::header($header, http_response_code: $response_code); |
|||
| 295 | } |
||||
| 296 | |||||
| 297 | /** |
||||
| 298 | * Relocate to another URL. |
||||
| 299 | * |
||||
| 300 | * Note, that this function automatically makes the page uncacheable, calls |
||||
| 301 | * midcom_finish and exit, so it will never return. If the headers have already |
||||
| 302 | * been sent, this will leave you with a partially completed page, so beware. |
||||
| 303 | */ |
||||
| 304 | public function relocate(string $url, int $response_code = Response::HTTP_FOUND) |
||||
| 305 | { |
||||
| 306 | $response = new midcom_response_relocate($url, $response_code); |
||||
| 307 | $response->send(); |
||||
| 308 | $this->finish(); |
||||
|
0 ignored issues
–
show
The function
midcom_application::finish() has been deprecated.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
| 309 | } |
||||
| 310 | |||||
| 311 | /** |
||||
| 312 | * Raise some PHP limits for resource-intensive tasks |
||||
| 313 | */ |
||||
| 314 | 9 | public function disable_limits() |
|||
| 315 | { |
||||
| 316 | 9 | $stat = ini_set('max_execution_time', $this->config->get('midcom_max_execution_time')); |
|||
|
0 ignored issues
–
show
It seems like
$this->config->get('midcom_max_execution_time') can also be of type null; however, parameter $value of ini_set() does only seem to accept string, maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
| 317 | 9 | if (false === $stat) { |
|||
| 318 | debug_add('ini_set("max_execution_time", ' . $this->config->get('midcom_max_execution_time') . ') returned false', MIDCOM_LOG_WARN); |
||||
| 319 | } |
||||
| 320 | 9 | $stat = ini_set('memory_limit', $this->config->get('midcom_max_memory')); |
|||
| 321 | 9 | if (false === $stat) { |
|||
| 322 | debug_add('ini_set("memory_limit", ' . $this->config->get('midcom_max_memory') . ') returned false', MIDCOM_LOG_WARN); |
||||
| 323 | } |
||||
| 324 | } |
||||
| 325 | } |
||||
| 326 |