1
0
mirror of https://github.com/flextype/flextype.git synced 2025-08-08 22:26:46 +02:00

feat(core): basic code updates for slim4 migration and possible integration with php-di

This commit is contained in:
Awilum
2021-07-28 16:31:23 +03:00
parent 4ac9d3224b
commit 25ec3cf06e
6 changed files with 266 additions and 475 deletions

View File

@@ -34,11 +34,10 @@
"atomastic/macroable": "^2.0.0",
"atomastic/csrf": "^1.0.1",
"slim/slim": "^3.12.3",
"slim/slim": "^4.8.1",
"filp/whoops": "^2.12.1",
"league/glide-slim": "^1.0.0",
"league/event": "^2.2.0",
"league/glide": "^1.7.0",
@@ -48,17 +47,18 @@
"monolog/monolog": "^2.2.0",
"cocur/slugify": "^4.0.0",
"ramsey/uuid": "^4.1.1",
"symfony/yaml": "^5.2.9",
"symfony/yaml": "^5.3.4",
"symfony/finder": "^5.2.9",
"bnf/slim3-psr15": "^1.1.1",
"league/commonmark": "^1.5.8",
"thunderer/shortcode": "^0.7.4",
"composer/semver": "^3.2.5",
"guzzlehttp/guzzle": "7.3.0"
"slim/psr7": "^1.4",
"php-di/php-di": "^6.3",
"php-di/slim-bridge": "^3.1",
"pimple/pimple": "^3.4"
},
"suggest": {
"ext-zend-opcache": "Recommended for better performance",
@@ -73,7 +73,8 @@
"files": [
"src/flextype/Support/Helpers/FindHelper.php",
"src/flextype/Support/Helpers/FilterHelper.php",
"src/flextype/Foundation/Helpers/FlextypeHelper.php"
"src/flextype/Foundation/Helpers/FlextypeHelper.php",
"src/flextype/Foundation/Helpers/ActionsHelper.php"
]
},
"require-dev": {

191
index.php
View File

@@ -18,6 +18,191 @@ use function version_compare;
use const DIRECTORY_SEPARATOR;
use const PHP_VERSION;
class Debug
{
/**
* Time
*
* @var array
*/
protected static $time = [];
/**
* Memory
*
* @var array
*/
protected static $memory = [];
/**
* Save current time for current point
*
* Debug::elapsedTimeSetPoint('point_name');
*
* @param string $point_name Point name
*/
public static function elapsedTimeSetPoint(string $point_name) : void
{
Debug::$time[$point_name] = microtime(true);
}
/**
* Get elapsed time for current point
*
* echo Debug::elapsedTime('point_name');
*
* @param string $point_name Point name
* @return string
*/
public static function elapsedTime(string $point_name) : string
{
if (isset(Debug::$time[$point_name])) return sprintf("%01.4f", microtime(true) - Debug::$time[$point_name]);
}
/**
* Save current memory for current point
*
* Debug::memoryUsageSetPoint('point_name');
*
* @param string $point_name Point name
*/
public static function memoryUsageSetPoint(string $point_name) : void
{
Debug::$memory[$point_name] = memory_get_usage();
}
/**
* Get memory usage for current point
*
* echo Debug::memoryUsage('point_name');
*
* @param string $point_name Point name
* @return string
*/
public static function memoryUsage(string $point_name) : string
{
if (isset(Debug::$memory[$point_name])) {
$unit = array('B', 'KB', 'MB', 'GB', 'TiB', 'PiB');
$size = memory_get_usage() - Debug::$memory[$point_name];
$memory_usage = @round($size/pow(1024, ($i=floor(log($size, 1024)))), 2).' '.$unit[($i < 0 ? 0 : $i)];
return $memory_usage;
}
}
/**
* Print the variable $data and exit if exit = true
*
* Debug::dump($data);
*
* @param mixed $data Data
* @param bool $exit Exit
*/
public static function dump($data, bool $exit = false) : void
{
echo "<pre>dump \n---------------------- \n\n" . print_r($data, true) . "\n----------------------</pre>";
if ($exit) exit;
}
/**
* Prints a list of all currently declared classes.
*
* Debug::classes();
*
* @access public
* @return string
*/
public static function classes()
{
return Debug::dump(get_declared_classes());
}
/**
* Prints a list of all currently declared interfaces.
*
* Debug::interfaces();
*
* @access public
* @return string
*/
public static function interfaces()
{
return Debug::dump(get_declared_interfaces());
}
/**
* Prints a list of all currently included (or required) files.
*
* Debug::includes();
*
* @access public
* @return string
*/
public static function includes()
{
return Debug::dump(get_included_files());
}
/**
* Prints a list of all currently declared functions.
*
* Debug::functions();
*
* @access public
* @return string
*/
public static function functions()
{
return Debug::dump(get_defined_functions());
}
/**
* Prints a list of all currently declared constants.
*
* Debug::constants();
*
* @access public
* @return string
*/
public static function constants()
{
return Debug::dump(get_defined_constants());
}
/**
* Prints a list of all currently loaded PHP extensions.
*
* Debug::extensions();
*
* @access public
* @return string
*/
public static function extensions()
{
return Debug::dump(get_loaded_extensions());
}
/**
* Prints a list of the configuration settings read from php.ini
*
* Debug::phpini();
*
* @access public
* @return string
*/
public static function phpini()
{
if (!is_readable(get_cfg_var('cfg_file_path'))) {
return false;
}
return Debug::dump(parse_ini_file(get_cfg_var('cfg_file_path'), true));
}
}
Debug::elapsedTimeSetPoint('flextype');
Debug::memoryUsageSetPoint('flextype');
/**
* Define the application minimum supported PHP version.
*/
@@ -65,3 +250,9 @@ $flextypeLoader = require_once $flextypeAutoload;
* the responses back to the browser and delight our users.
*/
include __DIR__ . '/src/flextype/flextype.php';
echo "<div style='position:absolute; bottom: 10px; left: 10px;'>";
echo "Time: " . Debug::elapsedTime('flextype');
echo " Memory: " . Debug::memoryUsage('flextype');
echo "</div>";

View File

@@ -10,14 +10,26 @@ declare(strict_types=1);
namespace Flextype\Foundation;
use Exception;
use Psr\Container\ContainerInterface;
use DI\Bridge\Slim\Bridge;
use DI\Container;
use Slim\App;
use Slim\Http\Environment;
use Slim\Http\Uri;
use Slim\Middleware\ContentLengthMiddleware;
use Slim\Middleware\OutputBufferingMiddleware;
use Slim\Middleware\RoutingMiddleware;
use Slim\Psr7\Factory\StreamFactory;
use Atomastic\Csrf\Csrf;
use Atomastic\Registry\Registry;
use Atomastic\Session\Session;
use Cocur\Slugify\Slugify;
use DateTimeZone;
use Flextype\Foundation\Actions;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Container\ContainerInterface;
use function is_null;
final class Flextype extends App
final class Flextype
{
/**
* Flextype version
@@ -33,6 +45,9 @@ final class Flextype extends App
*/
private static array $instances = [];
private App $app;
private Container $container;
/**
* Flextype should not be cloneable.
*/
@@ -51,34 +66,28 @@ final class Flextype extends App
/**
* Flextype construct
*
* @param ContainerInterface|array $container
*/
protected function __construct($container = [])
protected function __construct(ContainerInterface $container = null)
{
parent::__construct($container);
$this->app = Bridge::create($container);
$this->container = $this->app->getContainer();
}
/**
* Get/Set Dependency Injection Container.
*
* @param string|null $name DI Container name.
*/
public function container(?string $name = null)
public function app()
{
if (is_null($name)) {
return self::getInstance()->getContainer();
}
return self::getInstance()->getContainer()[$name];
return $this->app;
}
public function container()
{
return $this->container;
}
/**
* Returns Flextype Instance
*
* @param ContainerInterface|array $container Container.
*/
public static function getInstance($container = []): Flextype
public static function getInstance(ContainerInterface $container = null): Flextype
{
$cls = static::class;
if (! isset(self::$instances[$cls])) {

View File

@@ -11,15 +11,10 @@ use Flextype\Foundation\Flextype;
if (! function_exists('flextype')) {
/**
* Get the available Flextype Application instance
* or try to get Dependency Injection Container if $container is not null.
* Get the available Flextype instance.
*/
function flextype($containerName = null, $container = [])
function flextype($container = null)
{
if (is_null($containerName)) {
return Flextype::getInstance($container);
}
return Flextype::getInstance($container)->container($containerName);
return Flextype::getInstance($container);
}
}

View File

@@ -9,464 +9,59 @@ declare(strict_types=1);
namespace Flextype;
use Flextype\Foundation\Flextype;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Factory\AppFactory;
use Slim\Middleware\ContentLengthMiddleware;
use Slim\Middleware\OutputBufferingMiddleware;
use Slim\Middleware\RoutingMiddleware;
use Slim\Psr7\Factory\StreamFactory;
use Atomastic\Csrf\Csrf;
use Atomastic\Registry\Registry;
use Atomastic\Session\Session;
use Bnf\Slim3Psr15\CallableResolver;
use Cocur\Slugify\Slugify;
use DateTimeZone;
use Flextype\Foundation\Actions;
use Flextype\Foundation\Cors;
use Flextype\Foundation\Content\Content;
use Flextype\Foundation\Flextype;
use Flextype\Foundation\Media\Media;
use Flextype\Foundation\Plugins;
use Flextype\Support\Parsers\Parsers;
use Flextype\Support\Serializers\Serializers;
use Intervention\Image\ImageManager;
use League\Event\Emitter;
use League\Flysystem\Adapter\Local;
use League\Flysystem\Filesystem as Flysystem;
use League\Glide\Api\Api;
use League\Glide\Manipulators\Background;
use League\Glide\Manipulators\Blur;
use League\Glide\Manipulators\Border;
use League\Glide\Manipulators\Brightness;
use League\Glide\Manipulators\Contrast;
use League\Glide\Manipulators\Crop;
use League\Glide\Manipulators\Encode;
use League\Glide\Manipulators\Filter;
use League\Glide\Manipulators\Gamma;
use League\Glide\Manipulators\Orientation;
use League\Glide\Manipulators\Pixelate;
use League\Glide\Manipulators\Sharpen;
use League\Glide\Manipulators\Size;
use League\Glide\Manipulators\Watermark;
use League\Glide\Responses\SlimResponseFactory;
use League\Glide\ServerFactory;
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
use Phpfastcache\Drivers\Apcu\Config;
use Phpfastcache\Helper\Psr16Adapter as Cache;
use Slim\Http\Environment;
use Slim\Http\Uri;
use Whoops\Handler\JsonResponseHandler;
use Whoops\Handler\PrettyPageHandler;
use Whoops\Run;
use Whoops\Util\Misc;
use function date;
use function date_default_timezone_set;
use function error_reporting;
use function extension_loaded;
use function file_exists;
use function flextype;
use function function_exists;
use function get_class;
use function in_array;
use function mb_internal_encoding;
use function mb_language;
use function mb_regex_encoding;
use function str_replace;
use function strings;
use function sys_get_temp_dir;
use function ucwords;
/**
* Get Flextype Instance
*/
$flextype = flextype();
/**
* Set Flextype base path
*/
flextype()->app()->setBasePath('/flextype');
flextype()->app()->add(new RoutingMiddleware(flextype()->app()->getRouteResolver(), flextype()->app()->getRouteCollector()->getRouteParser()));
flextype()->app()->add(new ContentLengthMiddleware());
flextype()->app()->add(new OutputBufferingMiddleware(new StreamFactory(), OutputBufferingMiddleware::APPEND));
/**
* Init Registry
*/
$registry = Registry::getInstance();
flextype()->container()->set('registry', registry());
/**
* Init Actions
*/
$actions = Actions::getInstance();
flextype()->container()->set('actions', actions());
/**
* Preflight the Flextype
*/
include_once ROOT_DIR . '/src/flextype/preflight.php';
/**
* Create new Flextype Application
*/
$flextype = Flextype::getInstance([
'settings' => [
'debug' => $registry->get('flextype.settings.errors.display'),
'displayErrorDetails' => $registry->get('flextype.settings.display_error_details'),
'addContentLengthHeader' => $registry->get('flextype.settings.add_content_length_header'),
'routerCacheFile' => $registry->get('flextype.settings.router_cache_file'),
'determineRouteBeforeAppMiddleware' => $registry->get('flextype.settings.determine_route_before_app_middleware'),
'outputBuffering' => $registry->get('flextype.settings.output_buffering'),
'responseChunkSize' => $registry->get('flextype.settings.response_chunk_size'),
'httpVersion' => $registry->get('flextype.settings.http_version'),
],
]);
/**
* Display Errors
*/
if ($registry->get('flextype.settings.errors.display')) {
$environment = new Environment($_SERVER);
$uri = Uri::createFromEnvironment($environment);
flextype()->app()->get('/hello/{name}', function ($name, Request $request, Response $response) {
$response->getBody()->write('Hello' . $name);
return $response;
})->setName('root');
$prettyPageHandler = new PrettyPageHandler();
flextype()->app()->getRouteCollector()->setCacheFile(PATH['tmp'] . '/routes.php');
$prettyPageHandler->setEditor((string) $registry->get('flextype.settings.whoops.editor'));
$prettyPageHandler->setPageTitle((string) $registry->get('flextype.settings.whoops.page_title'));
flextype()->app()->addErrorMiddleware(true, true, true);
$prettyPageHandler->addDataTable('Flextype Application', [
'Application Class' => get_class(flextype()),
'Script Name' => $environment->get('SCRIPT_NAME'),
'Request URI' => $environment->get('PATH_INFO') ?: '<none>',
]);
$prettyPageHandler->addDataTable('Flextype Application (Request)', [
'Path' => $uri->getPath(),
'URL' => (string) $uri,
'Query String' => $uri->getQuery() ?: '<none>',
'Scheme' => $uri->getScheme() ?: '<none>',
'Port' => $uri->getPort() ?: '<none>',
'Host' => $uri->getHost() ?: '<none>',
]);
// Set Whoops to default exception handler
$whoops = new Run();
$whoops->pushHandler($prettyPageHandler);
// Enable JsonResponseHandler when request is AJAX
if (Misc::isAjaxRequest()) {
$whoops->pushHandler(new JsonResponseHandler());
}
$whoops->register();
flextype()->container()['whoops'] = $whoops;
} else {
error_reporting(0);
}
/**
* Create a standard session hanndler
*/
flextype()->container()['session'] = static fn () => new Session();
/**
* Supply a custom callable resolver, which resolves PSR-15 middlewares.
*/
flextype()->container()['callableResolver'] = static fn () => new CallableResolver(flextype()->container());
/**
* Add registry service to Flextype container
*/
flextype()->container()['registry'] = $registry;
/**
* Add actions service to Flextype container
*/
flextype()->container()['actions'] = $actions;
/**
* Add logger service to Flextype container
*/
flextype()->container()['logger'] = static function () {
$logger = new Logger('flextype');
$logger->pushHandler(new StreamHandler(PATH['tmp'] . '/logs/' . date('Y-m-d') . '.log'));
return $logger;
};
/**
* Add emitter service to Flextype container
*/
flextype()->container()['emitter'] = static fn () => new Emitter();
/**
* Add slugify service to Flextype container
*/
flextype()->container()['slugify'] = static function () {
return new Slugify([
'separator' => flextype('registry')->get('flextype.settings.slugify.separator'),
'lowercase' => flextype('registry')->get('flextype.settings.slugify.lowercase'),
'trim' => flextype('registry')->get('flextype.settings.slugify.trim'),
'regexp' => flextype('registry')->get('flextype.settings.slugify.regexp'),
'lowercase_after_regexp' => flextype('registry')->get('flextype.settings.slugify.lowercase_after_regexp'),
'strip_tags' => flextype('registry')->get('flextype.settings.slugify.strip_tags'),
]);
};
flextype()->container()['cache'] = static function () {
$driverName = flextype('registry')->get('flextype.settings.cache.driver');
$config = [];
function getDriverConfig(string $driverName): array
{
$config = [];
foreach (flextype('registry')->get('flextype.settings.cache.drivers.' . $driverName) as $key => $value) {
if ($key === 'path' && in_array($driverName, ['files', 'sqlite', 'leveldb'])) {
$config['path'] = ! empty($value) ? PATH['tmp'] . '/' . $value : sys_get_temp_dir();
} else {
$config[strings($key)->camel()->toString()] = $value;
}
}
return $config;
}
if (! $driverName || $driverName === 'auto') {
if (extension_loaded('apcu')) {
$driverName = 'apcu';
} elseif (extension_loaded('wincache')) {
$driverName = 'wincache';
} else {
$driverName = 'files';
}
}
if (flextype('registry')->get('flextype.settings.cache.enabled') === false) {
$driverName = 'devnull';
}
switch ($driverName) {
case 'apcu':
$config = new Config(getDriverConfig($driverName));
break;
case 'cassandra':
$config = new \Phpfastcache\Drivers\Cassandra\Config(getDriverConfig($driverName));
break;
case 'cookie':
$config = new \Phpfastcache\Drivers\Cookie\Config(getDriverConfig($driverName));
break;
case 'couchbase':
$config = new \Phpfastcache\Drivers\Couchbase\Config(getDriverConfig($driverName));
break;
case 'couchdb':
$config = new \Phpfastcache\Drivers\Couchdb\Config(getDriverConfig($driverName));
break;
case 'devfalse':
$config = new \Phpfastcache\Drivers\Devfalse\Config(getDriverConfig($driverName));
break;
case 'devnull':
$config = new \Phpfastcache\Drivers\Devnull\Config(getDriverConfig($driverName));
break;
case 'devtrue':
$config = new \Phpfastcache\Drivers\Devtrue\Config(getDriverConfig($driverName));
break;
case 'files':
$config = new \Phpfastcache\Drivers\Files\Config(getDriverConfig($driverName));
break;
case 'leveldb':
$config = new \Phpfastcache\Drivers\Leveldb\Config(getDriverConfig($driverName));
break;
case 'memcache':
$config = new \Phpfastcache\Drivers\Memcache\Config(getDriverConfig($driverName));
break;
case 'memcached':
$config = new \Phpfastcache\Drivers\Memcached\Config(getDriverConfig($driverName));
break;
case 'memstatic':
$config = new \Phpfastcache\Drivers\Memstatic\Config(getDriverConfig($driverName));
break;
case 'mongodb':
$config = new \Phpfastcache\Drivers\Mongodb\Config(getDriverConfig($driverName));
break;
case 'predis':
$config = new \Phpfastcache\Drivers\Predis\Config(getDriverConfig($driverName));
break;
case 'redis':
$config = new \Phpfastcache\Drivers\Redis\Config(getDriverConfig($driverName));
break;
case 'riak':
$config = new \Phpfastcache\Drivers\Riak\Config(getDriverConfig($driverName));
break;
case 'sqlite':
$config = new \Phpfastcache\Drivers\Sqlite\Config(getDriverConfig($driverName));
break;
case 'ssdb':
$config = new \Phpfastcache\Drivers\Ssdb\Config(getDriverConfig($driverName));
break;
case 'wincache':
$config = new \Phpfastcache\Drivers\Wincache\Config(getDriverConfig($driverName));
break;
case 'zenddisk':
$config = new \Phpfastcache\Drivers\Zenddisk\Config(getDriverConfig($driverName));
break;
case 'zendshm':
$config = new \Phpfastcache\Drivers\Zendshm\Config(getDriverConfig($driverName));
break;
default:
// code...
break;
}
return new Cache($driverName, $config);
};
/**
* Add parsers service to Flextype container
*/
flextype()->container()['parsers'] = static fn () => new Parsers();
/**
* Add serializer service to Flextype container
*/
flextype()->container()['serializers'] = static fn () => new Serializers();
/**
* Add images service to Flextype container
*/
flextype()->container()['images'] = static function () {
// Get images settings
$imagesSettings = ['driver' => flextype('registry')->get('flextype.settings.media.image.driver')];
// Set source filesystem
$source = new Flysystem(
new Local(PATH['project'] . '/media/')
);
// Set cache filesystem
$cache = new Flysystem(
new Local(PATH['tmp'] . '/glide')
);
// Set watermarks filesystem
$watermarks = new Flysystem(
new Local(PATH['project'] . '/watermarks')
);
// Set image manager
$imageManager = new ImageManager($imagesSettings);
// Set manipulators
$manipulators = [
new Orientation(),
new Crop(),
new Size(2000 * 2000),
new Brightness(),
new Contrast(),
new Gamma(),
new Sharpen(),
new Filter(),
new Blur(),
new Pixelate(),
new Watermark($watermarks),
new Background(),
new Border(),
new Encode(),
];
// Set API
$api = new Api($imageManager, $manipulators);
// Setup Glide server
return ServerFactory::create([
'source' => $source,
'cache' => $cache,
'api' => $api,
'response' => new SlimResponseFactory(),
]);
};
/**
* Add content service to Flextype container
*/
flextype()->container()['content'] = static fn () => new Content(flextype('registry')->get('flextype.settings.entries.content'));
/**
* Add media service to Flextype container
*/
flextype()->container()['media'] = static fn () => new Media();
/**
* Add plugins service to Flextype container
*/
flextype()->container()['plugins'] = static fn () => new Plugins();
/**
* Add cors service to Flextype container
*/
flextype()->container()['cors'] = static fn () => new Cors();
/**
* Set session options before you start the session
* Standard PHP session configuration options
* https://secure.php.net/manual/en/session.configuration.php
*/
flextype('session')->setOptions(flextype('registry')->get('flextype.settings.session'));
/**
* Start the session
*/
flextype('session')->start();
/**
* Add CSRF (cross-site request forgery) protection service to Flextype container
*/
flextype()->container()['csrf'] = static fn () => new Csrf('__csrf_token', '', 128);
/**
* Set internal encoding
*/
function_exists('mb_language') and mb_language('uni');
function_exists('mb_regex_encoding') and mb_regex_encoding(flextype('registry')->get('flextype.settings.charset'));
function_exists('mb_internal_encoding') and mb_internal_encoding(flextype('registry')->get('flextype.settings.charset'));
/**
* Set default timezone
*/
if (in_array(flextype('registry')->get('flextype.settings.timezone'), DateTimeZone::listIdentifiers())) {
date_default_timezone_set(flextype('registry')->get('flextype.settings.timezone'));
}
/**
* Init shortocodes
*
* Load Flextype Shortcodes from directory /flextype/Support/Parsers/Shortcodes/ based on flextype.settings.parsers.shortcode.shortcodes array
*/
$shortcodes = flextype('registry')->get('flextype.settings.parsers.shortcode.shortcodes');
foreach ($shortcodes as $shortcodeName => $shortcode) {
$shortcodeFilePath = ROOT_DIR . '/src/flextype/Support/Parsers/Shortcodes/' . str_replace('_', '', ucwords($shortcodeName, '_')) . 'Shortcode.php';
if (! file_exists($shortcodeFilePath)) {
continue;
}
include_once $shortcodeFilePath;
}
/**
* Init plugins
*/
flextype('plugins')->init();
/**
* Include API ENDPOINTS
*/
include_once ROOT_DIR . '/src/flextype/Endpoints/Utils/errors.php';
include_once ROOT_DIR . '/src/flextype/Endpoints/Utils/access.php';
include_once ROOT_DIR . '/src/flextype/Endpoints/content.php';
include_once ROOT_DIR . '/src/flextype/Endpoints/registry.php';
include_once ROOT_DIR . '/src/flextype/Endpoints/media.php';
include_once ROOT_DIR . '/src/flextype/Endpoints/images.php';
/**
* Enable lazy CORS
*
* CORS (Cross-origin resource sharing) allows JavaScript web apps to make HTTP requests to other domains.
* This is important for third party web apps using Flextype, as without CORS, a JavaScript app hosted on example.com
* couldn't access our APIs because they're hosted on another.com which is a different domain.
*/
flextype('cors')->init();
/**
* Run high priority event: onFlextypeBeforeRun before Flextype Application starts.
*/
flextype('emitter')->emit('onFlextypeBeforeRun');
/**
* Run application
*/
flextype()->run();
// Run flextype
flextype()->app()->run();

View File

@@ -68,4 +68,4 @@ if (filesystem()->file($preflightFlextypePath . '/' . $cacheID . '.txt')->exists
}
// Store flextype merged data in the flextype registry.
$registry->set('flextype', $flextypeData);
flextype()->container()->get('registry')->set('flextype', $flextypeData);