helpers.php 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. <?php
  2. use Composer\Autoload\ClassLoader;
  3. use Michel\Framework\Core\App;
  4. use Psr\Container\ContainerExceptionInterface;
  5. use Psr\Container\ContainerInterface;
  6. use Psr\Container\NotFoundExceptionInterface;
  7. use Psr\Http\Message\ResponseFactoryInterface;
  8. use Psr\Http\Message\ResponseInterface;
  9. use Psr\Http\Message\ServerRequestFactoryInterface;
  10. use Psr\Http\Message\ServerRequestInterface;
  11. if (!function_exists('michel_composer_loader')) {
  12. /**
  13. * Returns the instance of the Composer class loader.
  14. *
  15. * @return ClassLoader
  16. * @throws LogicException If the MICHEL_COMPOSER_AUTOLOAD_FILE constant is not defined.
  17. */
  18. function michel_composer_loader(): ClassLoader
  19. {
  20. if (!defined('MICHEL_COMPOSER_AUTOLOAD_FILE')) {
  21. throw new LogicException('MICHEL_COMPOSER_AUTOLOAD_FILE const must be defined!');
  22. }
  23. return require MICHEL_COMPOSER_AUTOLOAD_FILE;
  24. }
  25. }
  26. if (!function_exists('send_http_response')) {
  27. /**
  28. * Sends the HTTP response to the client.
  29. *
  30. * @param ResponseInterface $response The HTTP response to send.
  31. */
  32. function send_http_response(ResponseInterface $response)
  33. {
  34. $httpLine = sprintf('HTTP/%s %s %s',
  35. $response->getProtocolVersion(),
  36. $response->getStatusCode(),
  37. $response->getReasonPhrase()
  38. );
  39. if (!headers_sent()) {
  40. header($httpLine, true, $response->getStatusCode());
  41. foreach ($response->getHeaders() as $name => $values) {
  42. foreach ($values as $value) {
  43. header("$name: $value", false);
  44. }
  45. }
  46. }
  47. echo $response->getBody();
  48. }
  49. }
  50. if (!function_exists('container')) {
  51. /**
  52. * Retrieves the application's dependency injection container.
  53. *
  54. * @return ContainerInterface The dependency injection container.
  55. */
  56. function container(): ContainerInterface
  57. {
  58. return App::getContainer();
  59. }
  60. }
  61. if (!function_exists('create_request')) {
  62. /**
  63. * Creates a new HTTP request.
  64. *
  65. * @return ServerRequestInterface The HTTP response.
  66. */
  67. function create_request(): ServerRequestInterface
  68. {
  69. return App::createServerRequest();
  70. }
  71. }
  72. if (!function_exists('request_factory')) {
  73. /**
  74. * Creates a new HTTP request.
  75. *
  76. * @return ServerRequestFactoryInterface The HTTP response.
  77. */
  78. function request_factory(): ServerRequestFactoryInterface
  79. {
  80. return App::getServerRequestFactory();
  81. }
  82. }
  83. if (!function_exists('response_factory')) {
  84. /**
  85. * Retrieves the response factory.
  86. *
  87. * @return ResponseFactoryInterface The response factory.
  88. */
  89. function response_factory(): ResponseFactoryInterface
  90. {
  91. return App::getResponseFactory();
  92. }
  93. }
  94. if (!function_exists('response')) {
  95. /**
  96. * Creates a new HTTP response.
  97. *
  98. * @param string $content The response content.
  99. * @param int $status The HTTP status code.
  100. * @return ResponseInterface The HTTP response.
  101. */
  102. function response(string $content = '', int $status = 200, $contentType = 'text/html'): ResponseInterface
  103. {
  104. $response = response_factory()->createResponse($status);
  105. $response->getBody()->write($content);
  106. return $response->withHeader('Content-Type', $contentType);
  107. }
  108. }
  109. if (!function_exists('json_response')) {
  110. /**
  111. * Creates a new JSON response.
  112. *
  113. * @param array|JsonSerializable $data The data to encode to JSON.
  114. * @param int $status The HTTP status code.
  115. * @param int $flags JSON encoding flags.
  116. * @return ResponseInterface The JSON response.
  117. * @throws InvalidArgumentException If JSON encoding fails.
  118. */
  119. function json_response($data, int $status = 200, int $flags = JSON_HEX_TAG
  120. | JSON_HEX_APOS
  121. | JSON_HEX_AMP
  122. | JSON_HEX_QUOT
  123. | JSON_UNESCAPED_SLASHES): ResponseInterface
  124. {
  125. if (!is_array($data) && !is_subclass_of($data, JsonSerializable::class)) {
  126. throw new InvalidArgumentException(
  127. 'Data must be an array or implement JsonSerializable interface'
  128. );
  129. }
  130. $response = response_factory()->createResponse($status);
  131. $response->getBody()->write(json_encode($data, $flags));
  132. if (json_last_error() !== JSON_ERROR_NONE) {
  133. throw new InvalidArgumentException(
  134. sprintf('Unable to encode data to JSON: %s', json_last_error_msg())
  135. );
  136. }
  137. return $response->withHeader('Content-Type', 'application/json');
  138. }
  139. }
  140. if (!function_exists('redirect')) {
  141. /**
  142. * Creates a redirect response.
  143. *
  144. * @param string $url The URL to redirect to.
  145. * @param int $status The HTTP status code.
  146. * @return ResponseInterface The redirect response.
  147. */
  148. function redirect(string $url, int $status = 302): ResponseInterface
  149. {
  150. $response = response_factory()->createResponse($status);
  151. return $response->withHeader('Location', $url);
  152. }
  153. }
  154. if (!function_exists('render_view')) {
  155. /**
  156. * Renders a view template with the provided context.
  157. *
  158. * @param string $view The name of the view template.
  159. * @param array $context The context data to pass to the view.
  160. * @return string The rendered view.
  161. * @throws ContainerExceptionInterface
  162. * @throws NotFoundExceptionInterface
  163. */
  164. function render_view(string $view, array $context = []): string
  165. {
  166. if (!container()->has('render')) {
  167. throw new LogicException('The "render_view" method requires a Renderer to be available. You can choose between installing "Michel/php-renderer" or "twig/twig" depending on your preference.');
  168. }
  169. $renderer = container()->get('render');
  170. return $renderer->render($view, $context);
  171. }
  172. }
  173. if (!function_exists('render')) {
  174. /**
  175. * Renders a view template and creates an HTTP response.
  176. *
  177. * @param string $view The name of the view template.
  178. * @param array $context The context data to pass to the view.
  179. * @param int $status The HTTP status code.
  180. * @return ResponseInterface The HTTP response with the rendered view.
  181. * @throws ContainerExceptionInterface
  182. * @throws NotFoundExceptionInterface
  183. */
  184. function render(string $view, array $context = [], int $status = 200): ResponseInterface
  185. {
  186. return response(render_view($view, $context), $status);
  187. }
  188. }