1
0
mirror of https://github.com/flextype/flextype.git synced 2025-08-12 08:04:05 +02:00

Merge branch 'element-queries-436' into dev

This commit is contained in:
Awilum
2020-07-15 17:50:34 +03:00
43 changed files with 1161 additions and 933 deletions

View File

@@ -1 +0,0 @@
{"php":"7.2.20","version":"2.15.0","indent":" ","lineEnding":"\n","rules":{"blank_line_after_namespace":true,"braces":true,"class_definition":true,"elseif":true,"function_declaration":true,"indentation_type":true,"line_ending":true,"lowercase_constants":true,"lowercase_keywords":true,"method_argument_space":{"on_multiline":"ensure_fully_multiline"},"no_break_comment":true,"no_closing_tag":true,"no_spaces_after_function_name":true,"no_spaces_inside_parenthesis":true,"no_trailing_whitespace":true,"no_trailing_whitespace_in_comment":true,"single_blank_line_at_eof":true,"single_class_element_per_statement":{"elements":["property"]},"single_import_per_statement":true,"single_line_after_imports":true,"switch_case_semicolon_to_colon":true,"switch_case_space":true,"visibility_required":true,"encoding":true,"full_opening_tag":true},"hashes":{"vendor\/flextype-components\/arr\/Arr.php":3460238454}}

View File

@@ -13,8 +13,9 @@ However, the amount of effort needed to maintain and develop new features for th
### Backers
* Arseni Khramenkin
* Roman
* Viktoriya Kozyr
### One-time donations
* Viktoriya Kozyr
* Alexander Greca
* Izabela Sokołowska

View File

@@ -73,7 +73,10 @@
},
"autoload": {
"classmap": [
"src"
"src/flextype"
],
"files": [
"src/flextype/Support/helpers.php"
]
},
"require-dev": {

View File

@@ -160,6 +160,7 @@ class Cache
if ($lifetime === null) {
$lifetime = $this->getLifetime();
}
$this->driver->save($id, $data, $lifetime);
}

View File

@@ -9,8 +9,8 @@ declare(strict_types=1);
namespace Flextype;
use Flextype\Component\Filesystem\Filesystem;
use Flextype\Component\Arr\Arr;
use Flextype\Component\Filesystem\Filesystem;
class Config
{
@@ -50,24 +50,22 @@ class Config
/**
* Create new config item
*
* @param string $config Config namespace.
* @param string $key The key of the config item to get.
* @param mixed $value Value
*
* @return bool
* @param string $config Config namespace.
* @param string $key The key of the config item to get.
* @param mixed $value Value
*/
public function create(string $config, string $key, $value) : bool
{
$config_file = $this->getFileLocation($config);
if (Filesystem::has($config_file)) {
$config_file_data = $this->flextype->serializer->decode(Filesystem::read($config_file), 'yaml');
if (!Arr::keyExists($config_file_data, $key)) {
Arr::set($config_file_data, $key, $value);
return Filesystem::write($config_file, $this->flextype->serializer->encode($config_file_data, 'yaml'));
}
if (! Arr::keyExists($config_file_data, $key)) {
Arr::set($config_file_data, $key, $value);
return Filesystem::write($config_file, $this->flextype->serializer->encode($config_file_data, 'yaml'));
}
return false;
}
@@ -78,24 +76,22 @@ class Config
/**
* Update config item
*
* @param string $config Config namespace.
* @param string $key The key of the config item to get.
* @param mixed $value Value
*
* @return bool
* @param string $config Config namespace.
* @param string $key The key of the config item to get.
* @param mixed $value Value
*/
public function update(string $config, string $key, $value) : bool
{
$config_file = $this->getFileLocation($config);
if (Filesystem::has($config_file)) {
$config_file_data = $this->flextype->serializer->decode(Filesystem::read($config_file), 'yaml');
if (Arr::keyExists($config_file_data, $key)) {
Arr::set($config_file_data, $key, $value);
return Filesystem::write($config_file, $this->flextype->serializer->encode($config_file_data, 'yaml'));
}
if (Arr::keyExists($config_file_data, $key)) {
Arr::set($config_file_data, $key, $value);
return Filesystem::write($config_file, $this->flextype->serializer->encode($config_file_data, 'yaml'));
}
return false;
}
@@ -106,23 +102,21 @@ class Config
/**
* Delete config item
*
* @param string $config Config namespace.
* @param string $key The key of the config item to get.
*
* @return bool
* @param string $config Config namespace.
* @param string $key The key of the config item to get.
*/
public function delete(string $config, $key) : bool
public function delete(string $config, string $key) : bool
{
$config_file = $this->getFileLocation($config);
if (Filesystem::has($config_file)) {
$config_file_data = $this->flextype->serializer->decode(Filesystem::read($config_file), 'yaml');
if (Arr::keyExists($config_file_data, $key)) {
Arr::delete($config_file_data, $key);
return Filesystem::write($config_file, $this->flextype->serializer->encode($config_file_data, 'yaml'));
}
if (Arr::keyExists($config_file_data, $key)) {
Arr::delete($config_file_data, $key);
return Filesystem::write($config_file, $this->flextype->serializer->encode($config_file_data, 'yaml'));
}
return false;
}
@@ -133,22 +127,19 @@ class Config
/**
* Checks if an config item with this key name is in the config.
*
* @param string $config Config namespace.
* @param string $key The key of the config item to get.
*
* @return bool
* @param string $config Config namespace.
* @param string $key The key of the config item to get.
*/
public function has(string $config, $key) : bool
public function has(string $config, string $key) : bool
{
$config_file = $this->getFileLocation($config);
if (Filesystem::has($config_file)) {
$config_file_data = $this->flextype->serializer->decode(Filesystem::read($config_file), 'yaml');
if (Arr::keyExists($config_file_data, $key)) {
return true;
}
if (Arr::keyExists($config_file_data, $key)) {
return true;
}
return false;
}
@@ -159,7 +150,7 @@ class Config
/**
* Get config file location
*
* @param string $config Config namespace.
* @param string $config Config namespace.
*
* @return string config file location
*
@@ -173,7 +164,7 @@ class Config
/**
* Get config directory location
*
* @param string $config Config namespace.
* @param string $config Config namespace.
*
* @return string config directory location
*

View File

@@ -0,0 +1,70 @@
<?php
declare(strict_types=1);
/**
* Flextype (http://flextype.org)
* Founded by Sergey Romanenko and maintained by Flextype Community.
*/
namespace Flextype;
use function count;
use function implode;
class Cors
{
/**
* Flextype Dependency Container
*/
private $flextype;
/**
* Flextype app
*/
private $app;
/**
* __construct
*/
public function __construct($flextype, $app)
{
$this->flextype = $flextype;
$this->app = $app;
}
/**
* Init CORS
*/
public function init() : void
{
$flextype = $this->flextype;
if (! $flextype['registry']->get('flextype.settings.cors.enabled')) {
return;
}
$this->app->options('/{routes:.+}', function ($request, $response, $args) {
return $response;
});
$this->app->add(function ($req, $res, $next) use ($flextype) {
$response = $next($req, $res);
// Set variables
$origin = $flextype['registry']->get('flextype.settings.cors.origin');
$headers = count($flextype['registry']->get('flextype.settings.cors.headers')) ? implode(', ', $flextype['registry']->get('flextype.settings.cors.headers')) : '';
$methods = count($flextype['registry']->get('flextype.settings.cors.methods')) ? implode(', ', $flextype['registry']->get('flextype.settings.cors.methods')) : '';
$expose = count($flextype['registry']->get('flextype.settings.cors.expose')) ? implode(', ', $flextype['registry']->get('flextype.settings.cors.expose')) : '';
$credentials = $flextype['registry']->get('flextype.settings.cors.credentials') ? true : false;
return $response
->withHeader('Access-Control-Allow-Origin', $origin)
->withHeader('Access-Control-Allow-Headers', $headers)
->withHeader('Access-Control-Allow-Methods', $methods)
->withHeader('Access-Control-Allow-Expose', $expose)
->withHeader('Access-Control-Allow-Credentials', $credentials);
});
}
}

View File

@@ -0,0 +1,467 @@
<?php
declare(strict_types=1);
/**
* Flextype (http://flextype.org)
* Founded by Sergey Romanenko and maintained by Flextype Community.
*/
namespace Flextype;
use Flextype\Component\Arr\Arr;
use Flextype\Component\Filesystem\Filesystem;
use Flextype\Component\Session\Session;
use Ramsey\Uuid\Uuid;
use function array_merge;
use function count;
use function date;
use function in_array;
use function is_array;
use function is_bool;
use function ltrim;
use function md5;
use function rename;
use function rtrim;
use function str_replace;
use function strpos;
use function strtotime;
use function time;
class Entries
{
/**
* Current entry data array
*
* @var array
* @access public
*/
public $entry = [];
/**
* Current entries data array
*
* @var array
* @access public
*/
public $entries = [];
/**
* Entries Visibility
*
* @var array
* @access public
*/
public $visibility = [
'draft' => 'draft',
'hidden' => 'hidden',
'visible' => 'visible',
];
/**
* Entries system fields
*
* @var array
* @access public
*/
public $system_fields = [
'published_at' => 'published_at',
'published_by' => 'published_by',
'created_at' => 'created_at',
'modified_at' => 'modified_at',
'slug' => 'slug',
'routable' => 'routable',
'parsers' => 'parsers',
'visibility' => 'visibility',
];
/**
* Flextype Dependency Container
*
* @access private
*/
private $flextype;
/**
* Constructor
*
* @access public
*/
public function __construct($flextype)
{
$this->flextype = $flextype;
}
/**
* Fetch entry(entries)
*
* @param string $path Unique identifier of the entry(entries).
* @param array|null $filter Select items in collection by given conditions.
*
* @return array The entry array data.
*
* @access public
*/
public function fetch(string $path, ?array $filter = null) : array
{
// If filter is array then it is entries collection request
if (is_array($filter)) {
return $this->fetchCollection($path, $filter);
}
return $this->fetchSingle($path);
}
/**
* Fetch single entry
*
* @param string $path Unique identifier of the entry(entries).
*
* @return array The entry array data.
*
* @access public
*/
public function fetchSingle(string $path) : array
{
// Get entry file location
$entry_file = $this->getFileLocation($path);
// If requested entry file founded then process it
if (Filesystem::has($entry_file)) {
// Create unique entry cache_id
// Entry Cache ID = entry + entry file + entry file time stamp
if ($timestamp = Filesystem::getTimestamp($entry_file)) {
$entry_cache_id = md5('entry' . $entry_file . $timestamp);
} else {
$entry_cache_id = md5('entry' . $entry_file);
}
// Try to get the requested entry from cache
if ($this->flextype['cache']->contains($entry_cache_id)) {
// Try to fetch requested entry from the cache
if ($entry = $this->flextype['cache']->fetch($entry_cache_id)) {
// Run event onEntryAfterInitialized
$this->flextype['emitter']->emit('onEntryAfterInitialized');
// Return entry
return $entry;
}
// Return empty array
return [];
// else Try to get requested entry from the filesystem
}
$entry_decoded = $this->flextype['serializer']->decode(Filesystem::read($entry_file), 'frontmatter');
// Add predefined entry items
// Entry Published At
$entry_decoded['published_at'] = isset($entry_decoded['published_at']) ? (int) strtotime($entry_decoded['published_at']) : (int) Filesystem::getTimestamp($entry_file);
// Entry Created At
$entry_decoded['created_at'] = isset($entry_decoded['created_at']) ? (int) strtotime($entry_decoded['created_at']) : (int) Filesystem::getTimestamp($entry_file);
// Entry Modified
$entry_decoded['modified_at'] = (int) Filesystem::getTimestamp($entry_file);
// Entry Slug
$entry_decoded['slug'] = isset($entry_decoded['slug']) ? (string) $entry_decoded['slug'] : (string) ltrim(rtrim($path, '/'), '/');
// Entry Routable
$entry_decoded['routable'] = isset($entry_decoded['routable']) ? (bool) $entry_decoded['routable'] : true;
// Entry Visibility
if (isset($entry_decoded['visibility']) && in_array($entry_decoded['visibility'], $this->visibility)) {
$entry_decoded['visibility'] = (string) $this->visibility[$entry_decoded['visibility']];
} else {
$entry_decoded['visibility'] = (string) $this->visibility['visible'];
}
// Parsers
if (isset($entry_decoded['parsers'])) {
foreach ($entry_decoded['parsers'] as $parser_name => $parser_data) {
if (! in_array($parser_name, ['markdown', 'shortcodes'])) {
continue;
}
if (! isset($entry_decoded['parsers'][$parser_name]['enabled']) || $entry_decoded['parsers'][$parser_name]['enabled'] !== true) {
continue;
}
if (isset($entry_decoded['parsers'][$parser_name]['cache']) && $entry_decoded['parsers'][$parser_name]['cache'] === true) {
$cache = true;
} else {
$cache = false;
}
if (! isset($entry_decoded['parsers'][$parser_name]['fields'])) {
continue;
}
if (! is_array($entry_decoded['parsers'][$parser_name]['fields'])) {
continue;
}
foreach ($entry_decoded['parsers'][$parser_name]['fields'] as $field) {
if (in_array($field, $this->system_fields)) {
continue;
}
if ($parser_name === 'markdown') {
if (Arr::keyExists($entry_decoded, $field)) {
Arr::set($entry_decoded, $field, $this->flextype['parser']->parse(Arr::get($entry_decoded, $field), 'markdown', $cache));
}
}
if ($parser_name !== 'shortcodes') {
continue;
}
if (! Arr::keyExists($entry_decoded, $field)) {
continue;
}
Arr::set($entry_decoded, $field, $this->flextype['parser']->parse(Arr::get($entry_decoded, $field), 'shortcodes', $cache));
}
}
}
// Save decoded entry content into the cache
$this->flextype['cache']->save($entry_cache_id, $entry_decoded);
// Set entry to the Entry class property $entry
$this->entry = $entry_decoded;
// Run event onEntryAfterInitialized
$this->flextype['emitter']->emit('onEntryAfterInitialized');
// Return entry from the Entry class property $entry
return $this->entry;
}
// Return empty array
return [];
}
/**
* Fetch entries collection
*
* @param string $path Unique identifier of the entry(entries).
* @param array $deep
*
* @return array The entries array data.
*
* @access public
*/
public function fetchCollection(string $path, $recursive = false) : array
{
// Init Entries
$entries = [];
// Init Entries
$this->entries = $entries;
// Get entries path
$entries_path = $this->getDirLocation($path);
// Get entries list
$entries_list = Filesystem::listContents($entries_path, $recursive);
// If entries founded in entries folder
if (count($entries_list) > 0) {
// Create entries array from entries list and ignore current requested entry
foreach ($entries_list as $current_entry) {
if (strpos($current_entry['path'], $path . '/entry' . '.' . $this->flextype->registry->get('flextype.settings.entries.extension')) !== false) {
// ignore ...
} else {
// We are checking...
// Whether the requested entry is a director and whether the file entry is in this directory.
if ($current_entry['type'] === 'dir' && Filesystem::has($current_entry['path'] . '/entry' . '.' . $this->flextype->registry->get('flextype.settings.entries.extension'))) {
// Get entry uid
// 1. Remove entries path
// 2. Remove left and right slashes
$uid = ltrim(rtrim(str_replace(PATH['project'] . '/entries/', '', $current_entry['path']), '/'), '/');
// For each founded entry we should create $entries array.
$entry = $this->fetch($uid);
// Add entry into the entries
$entries[$uid] = $entry;
}
}
}
// Set entries into the property entries
$this->entries = $entries;
// Run event onEntriesAfterInitialized
$this->flextype['emitter']->emit('onEntriesAfterInitialized');
}
// Return entries
return $this->entries;
}
/**
* Rename entry
*
* @param string $path Unique identifier of the entry(entries).
* @param string $new_id New Unique identifier of the entry(entries).
*
* @return bool True on success, false on failure.
*
* @access public
*/
public function rename(string $path, string $new_id) : bool
{
if (! Filesystem::has($this->getDirLocation($new_id))) {
return rename($this->getDirLocation($path), $this->getDirLocation($new_id));
}
return false;
}
/**
* Update entry
*
* @param string $path Unique identifier of the entry(entries).
* @param array $data Data to update for the entry.
*
* @return bool True on success, false on failure.
*
* @access public
*/
public function update(string $path, array $data) : bool
{
$entry_file = $this->getFileLocation($path);
if (Filesystem::has($entry_file)) {
$body = Filesystem::read($entry_file);
$entry = $this->flextype['serializer']->decode($body, 'frontmatter');
return Filesystem::write($entry_file, $this->flextype['serializer']->encode(array_merge($entry, $data), 'frontmatter'));
}
return false;
}
/**
* Create entry
*
* @param string $path Unique identifier of the entry(entries).
* @param array $data Data to create for the entry.
*
* @return bool True on success, false on failure.
*
* @access public
*/
public function create(string $path, array $data) : bool
{
$entry_dir = $this->getDirLocation($path);
if (! Filesystem::has($entry_dir)) {
// Try to create directory for new entry
if (Filesystem::createDir($entry_dir)) {
// Check if new entry file exists
if (! Filesystem::has($entry_file = $entry_dir . '/entry' . '.' . $this->flextype->registry->get('flextype.settings.entries.extension'))) {
$data['uuid'] = Uuid::uuid4()->toString();
$data['published_at'] = date($this->flextype->registry->get('flextype.settings.date_format'), time());
$data['created_at'] = date($this->flextype->registry->get('flextype.settings.date_format'), time());
$data['published_by'] = (Session::exists('uuid') ? Session::get('uuid') : '');
$data['created_by'] = (Session::exists('uuid') ? Session::get('uuid') : '');
if (isset($data['routable']) && is_bool($data['routable'])) {
$data['routable'] = $data['routable'];
} else {
$data['routable'] = true;
}
if (isset($data['visibility']) && in_array($data['visibility'], $this->visibility)) {
$data['visibility'] = $data['visibility'];
} else {
$data['visibility'] = 'visible';
}
return Filesystem::write($entry_file, $this->flextype['serializer']->encode($data, 'frontmatter'));
}
return false;
}
}
return false;
}
/**
* Delete entry
*
* @param string $path Unique identifier of the entry(entries).
*
* @return bool True on success, false on failure.
*
* @access public
*/
public function delete(string $path) : bool
{
return Filesystem::deleteDir($this->getDirLocation($path));
}
/**
* Copy entry(s)
*
* @param string $path Unique identifier of the entry(entries).
* @param string $new_id New Unique identifier of the entry(entries).
* @param bool $recursive Recursive copy entries.
*
* @return bool|null True on success, false on failure.
*
* @access public
*/
public function copy(string $path, string $new_id, bool $recursive = false) : ?bool
{
return Filesystem::copy($this->getDirLocation($path), $this->getDirLocation($new_id), $recursive);
}
/**
* Check whether entry exists
*
* @param string $path Unique identifier of the entry(entries).
*
* @return bool True on success, false on failure.
*
* @access public
*/
public function has(string $path) : bool
{
return Filesystem::has($this->getFileLocation($path));
}
/**
* Get entry file location
*
* @param string $path Unique identifier of the entry(entries).
*
* @return string entry file location
*
* @access private
*/
public function getFileLocation(string $path) : string
{
return PATH['project'] . '/entries/' . $path . '/entry' . '.' . $this->flextype->registry->get('flextype.settings.entries.extension');
}
/**
* Get entry directory location
*
* @param string $path Unique identifier of the entry(entries).
*
* @return string entry directory location
*
* @access private
*/
public function getDirLocation(string $path) : string
{
return PATH['project'] . '/entries/' . $path;
}
}

View File

@@ -10,10 +10,19 @@ declare(strict_types=1);
namespace Flextype;
use Flextype\Component\Filesystem\Filesystem;
use Flextype\Component\Arr\Arr;
use Intervention\Image\ImageManagerStatic as Image;
use Slim\Http\Environment;
use Slim\Http\Uri;
use function in_array;
use function is_uploaded_file;
use function mime_content_type;
use function pathinfo;
use function strpos;
use function strtolower;
use const PATHINFO_EXTENSION;
use const UPLOAD_ERR_INI_SIZE;
use const UPLOAD_ERR_OK;
use function getimagesize;
class MediaFiles
{
@@ -44,7 +53,7 @@ class MediaFiles
*/
public function upload(array $file, string $folder)
{
$upload_folder = PATH['project'] . '/uploads/' . $folder . '/';
$upload_folder = PATH['project'] . '/uploads/' . $folder . '/';
$upload_metadata_folder = PATH['project'] . '/uploads/.meta/' . $folder . '/';
if (! Filesystem::has($upload_folder)) {
@@ -56,93 +65,94 @@ class MediaFiles
}
$accept_file_types = $this->flextype['registry']->get('flextype.settings.media.accept_file_types');
$max_file_size = $this->flextype['registry']->get('flextype.settings.media.max_file_size');
$safe_names = $this->flextype['registry']->get('flextype.settings.media.safe_names');
$max_image_width = $this->flextype['registry']->get('flextype.settings.media.max_image_width');
$max_image_height = $this->flextype['registry']->get('flextype.settings.media.max_image_height');
$max_file_size = $this->flextype['registry']->get('flextype.settings.media.max_file_size');
$safe_names = $this->flextype['registry']->get('flextype.settings.media.safe_names');
$max_image_width = $this->flextype['registry']->get('flextype.settings.media.max_image_width');
$max_image_height = $this->flextype['registry']->get('flextype.settings.media.max_image_height');
$exact = false;
$chmod = 0644;
$filename = null;
$exact = false;
$chmod = 0644;
$filename = null;
$exif_data = [];
//
// Tests if a successful upload has been made.
//
if (isset($file['error'])
and isset($file['tmp_name'])
and $file['error'] === UPLOAD_ERR_OK
and is_uploaded_file($file['tmp_name'])) {
//
// Tests if upload data is valid, even if no file was uploaded.
//
if (isset($file['error'])
and isset($file['name'])
and isset($file['type'])
and isset($file['tmp_name'])
and isset($file['size'])) {
//
// Test if an uploaded file is an allowed file type, by extension.
//
if (strpos($accept_file_types, strtolower(pathinfo($file['name'], PATHINFO_EXTENSION))) !== false) {
//
// Validation rule to test if an uploaded file is allowed by file size.
//
if (($file['error'] != UPLOAD_ERR_INI_SIZE)
and ($file['error'] == UPLOAD_ERR_OK)
if (($file['error'] !== UPLOAD_ERR_INI_SIZE)
and ($file['error'] === UPLOAD_ERR_OK)
and ($file['size'] <= $max_file_size)) {
//
// Validation rule to test if an upload is an image and, optionally, is the correct size.
//
if (in_array(mime_content_type($file['tmp_name']), ['image/jpeg', 'image/jpg', 'image/png', 'image/gif'])) {
function validateImage($file, $max_image_width, $max_image_height, $exact)
{
try {
// Get the width and height from the uploaded image
list($width, $height) = getimagesize($file['tmp_name']);
[$width, $height] = getimagesize($file['tmp_name']);
} catch (ErrorException $e) {
// Ignore read errors
}
if (empty($width) or empty($height)) {
// Cannot get image size, cannot validate
return false;
}
if (!$max_image_width) {
if (! $max_image_width) {
// No limit, use the image width
$max_image_width = $width;
}
if (!$max_image_height) {
if (! $max_image_height) {
// No limit, use the image height
$max_image_height = $height;
}
if ($exact) {
// Check if dimensions match exactly
return ($width === $max_image_width and $height === $max_image_height);
return $width === $max_image_width and $height === $max_image_height;
} else {
// Check if size is within maximum dimensions
return ($width <= $max_image_width and $height <= $max_image_height);
return $width <= $max_image_width and $height <= $max_image_height;
}
return false;
}
if (validateImage($file, $max_image_width, $max_image_height, $exact) === false) {
return false;
}
}
if (!isset($file['tmp_name']) or !is_uploaded_file($file['tmp_name'])) {
if (! isset($file['tmp_name']) or ! is_uploaded_file($file['tmp_name'])) {
// Ignore corrupted uploads
return false;
}
if ($filename === null) {
// Use the default filename
$filename = $file['name'];
}
if ($safe_names === true) {
// Remove spaces from the filename
$filename = $this->flextype['slugify']->slugify(pathinfo($filename)['filename']) . '.' . pathinfo($filename)['extension'];
}
if (!is_dir($upload_folder) or !is_writable(realpath($upload_folder))) {
if (! is_dir($upload_folder) or ! is_writable(realpath($upload_folder))) {
throw new \RuntimeException("Directory {$upload_folder} must be writable");
}
// Make the filename into a complete path
$filename = realpath($upload_folder) . DIRECTORY_SEPARATOR . $filename;
if (move_uploaded_file($file['tmp_name'], $filename)) {
@@ -155,17 +165,17 @@ class MediaFiles
// now you are able to resize the instance
if ($this->flextype['registry']->get('plugins.admin.settings.entries.media.upload_images_width') > 0 && $this->flextype['registry']->get('plugins.admin.settings.entries.media.upload_images_height') > 0) {
$img->resize($this->flextype['registry']->get('plugins.admin.settings.entries.media.upload_images_width'), $this->flextype['registry']->get('plugins.admin.settings.entries.media.upload_images_height'), function($constraint) {
$img->resize($this->flextype['registry']->get('plugins.admin.settings.entries.media.upload_images_width'), $this->flextype['registry']->get('plugins.admin.settings.entries.media.upload_images_height'), static function ($constraint) : void {
$constraint->aspectRatio();
$constraint->upsize();
});
} elseif ($this->flextype['registry']->get('plugins.admin.settings.entries.media.upload_images_width') > 0) {
$img->resize($this->flextype['registry']->get('plugins.admin.settings.entries.media.upload_images_width'), null, function($constraint) {
$img->resize($this->flextype['registry']->get('plugins.admin.settings.entries.media.upload_images_width'), null, static function ($constraint) : void {
$constraint->aspectRatio();
$constraint->upsize();
});
} elseif ($this->flextype['registry']->get('plugins.admin.settings.entries.media.upload_images_height') > 0) {
$img->resize(null, $this->flextype['registry']->get('plugins.admin.settings.entries.media.upload_images_height'), function($constraint) {
$img->resize(null, $this->flextype['registry']->get('plugins.admin.settings.entries.media.upload_images_height'), static function ($constraint) : void {
$constraint->aspectRatio();
$constraint->upsize();
});
@@ -186,16 +196,19 @@ class MediaFiles
}
}
$metadata = ['title' => substr(basename($filename), 0, strrpos(basename($filename), '.')),
'description' => '',
'type' => mime_content_type($filename),
'filesize' => Filesystem::getSize($filename),
'uploaded_on' => time(),
'exif' => $exif_data];
Filesystem::write($upload_metadata_folder . basename($filename) . '.yaml',
$this->flextype['serializer']->encode($metadata, 'yaml'));
$metadata = [
'title' => substr(basename($filename), 0, strrpos(basename($filename), '.')),
'description' => '',
'type' => mime_content_type($filename),
'filesize' => Filesystem::getSize($filename),
'uploaded_on' => time(),
'exif' => $exif_data,
];
Filesystem::write(
$upload_metadata_folder . basename($filename) . '.yaml',
$this->flextype['serializer']->encode($metadata, 'yaml')
);
// Return new file path
return $filename;
@@ -241,14 +254,14 @@ class MediaFiles
if (Filesystem::has($this->flextype['media_files_meta']->getFileMetaLocation($path))) {
$result = $this->flextype['serializer']->decode(Filesystem::read($this->flextype['media_files_meta']->getFileMetaLocation($path)), 'yaml');
$result['filename'] = pathinfo(str_replace("/.meta", "", $this->flextype['media_files_meta']->getFileMetaLocation($path)))['filename'];
$result['basename'] = explode(".", basename($this->flextype['media_files_meta']->getFileMetaLocation($path)))[0];
$result['filename'] = pathinfo(str_replace('/.meta', '', $this->flextype['media_files_meta']->getFileMetaLocation($path)))['filename'];
$result['basename'] = explode('.', basename($this->flextype['media_files_meta']->getFileMetaLocation($path)))[0];
$result['extension'] = ltrim(strstr($path, '.'), '.');
$result['dirname'] = pathinfo(str_replace("/.meta", "", $this->flextype['media_files_meta']->getFileMetaLocation($path)))['dirname'];
$result['dirname'] = pathinfo(str_replace('/.meta', '', $this->flextype['media_files_meta']->getFileMetaLocation($path)))['dirname'];
$result['url'] = 'project/uploads/' . $path;
if ($this->flextype['registry']->has('flextype.settings.url') && $this->flextype['registry']->get('flextype.settings.url') != '') {
if ($this->flextype['registry']->has('flextype.settings.url') && $this->flextype['registry']->get('flextype.settings.url') !== '') {
$full_url = $this->flextype['registry']->get('flextype.settings.url');
} else {
$full_url = Uri::createFromEnvironment(new Environment($_SERVER))->getBaseUrl();
@@ -274,14 +287,14 @@ class MediaFiles
foreach (Filesystem::listContents($this->flextype['media_folders_meta']->getDirMetaLocation($path)) as $file) {
$result[$file['basename']] = $this->flextype['serializer']->decode(Filesystem::read($file['path']), 'yaml');
$result[$file['basename']]['filename'] = pathinfo(str_replace("/.meta", "", $this->flextype['media_files_meta']->getFileMetaLocation($file['basename'])))['filename'];
$result[$file['basename']]['basename'] = explode(".", basename($this->flextype['media_files_meta']->getFileMetaLocation($file['basename'])))[0];
$result[$file['basename']]['filename'] = pathinfo(str_replace('/.meta', '', $this->flextype['media_files_meta']->getFileMetaLocation($file['basename'])))['filename'];
$result[$file['basename']]['basename'] = explode('.', basename($this->flextype['media_files_meta']->getFileMetaLocation($file['basename'])))[0];
$result[$file['basename']]['extension'] = ltrim(strstr($file['basename'], '.'), '.');
$result[$file['basename']]['dirname'] = pathinfo(str_replace("/.meta", "", $file['path']))['dirname'];
$result[$file['basename']]['dirname'] = pathinfo(str_replace('/.meta', '', $file['path']))['dirname'];
$result[$file['basename']]['url'] = 'project/uploads/' . $path . '/' . $file['basename'];
if ($this->flextype['registry']->has('flextype.settings.url') && $this->flextype['registry']->get('flextype.settings.url') != '') {
if ($this->flextype['registry']->has('flextype.settings.url') && $this->flextype['registry']->get('flextype.settings.url') !== '') {
$full_url = $this->flextype['registry']->get('flextype.settings.url');
} else {
$full_url = Uri::createFromEnvironment(new Environment($_SERVER))->getBaseUrl();
@@ -305,15 +318,11 @@ class MediaFiles
*/
public function rename(string $id, string $new_id) : bool
{
if (!Filesystem::has($this->getFileLocation($new_id)) && !Filesystem::has($this->flextype['media_files_meta']->getFileMetaLocation($new_id))) {
if (rename($this->getFileLocation($id), $this->getFileLocation($new_id)) && rename($this->flextype['media_files_meta']->getFileMetaLocation($id), $this->flextype['media_files_meta']->getFileMetaLocation($new_id))) {
return true;
} else {
return false;
}
} else {
return false;
if (! Filesystem::has($this->getFileLocation($new_id)) && ! Filesystem::has($this->flextype['media_files_meta']->getFileMetaLocation($new_id))) {
return rename($this->getFileLocation($id), $this->getFileLocation($new_id)) && rename($this->flextype['media_files_meta']->getFileMetaLocation($id), $this->flextype['media_files_meta']->getFileMetaLocation($new_id));
}
return false;
}
/**
@@ -325,7 +334,7 @@ class MediaFiles
*
* @access public
*/
public function delete(string $id)
public function delete(string $id) : bool
{
Filesystem::delete($this->getFileLocation($id));
Filesystem::delete($this->flextype['media_files_meta']->getFileMetaLocation($id));

View File

@@ -9,11 +9,8 @@ declare(strict_types=1);
namespace Flextype;
use Flextype\Component\Filesystem\Filesystem;
use Flextype\Component\Arr\Arr;
use Intervention\Image\ImageManagerStatic as Image;
use Slim\Http\Environment;
use Slim\Http\Uri;
use Flextype\Component\Filesystem\Filesystem;
class MediaFilesMeta
{
@@ -51,6 +48,7 @@ class MediaFilesMeta
if (Arr::keyExists($file_data, $field)) {
Arr::set($file_data, $field, $value);
return Filesystem::write($this->getFileMetaLocation($id), $this->flextype['serializer']->encode($file_data, 'yaml'));
}
@@ -72,8 +70,9 @@ class MediaFilesMeta
{
$file_data = $this->flextype['serializer']->decode(Filesystem::read($this->getFileMetaLocation($id)), 'yaml');
if (!Arr::keyExists($file_data, $field)) {
if (! Arr::keyExists($file_data, $field)) {
Arr::set($file_data, $field, $value);
return Filesystem::write($this->getFileMetaLocation($id), $this->flextype['serializer']->encode($file_data, 'yaml'));
}
@@ -96,6 +95,7 @@ class MediaFilesMeta
if (Arr::keyExists($file_data, $field)) {
Arr::delete($file_data, $field);
return Filesystem::write($this->getFileMetaLocation($id), $this->flextype['serializer']->encode($file_data, 'yaml'));
}

View File

@@ -10,10 +10,10 @@ declare(strict_types=1);
namespace Flextype;
use Flextype\Component\Filesystem\Filesystem;
use Flextype\Component\Arr\Arr;
use Intervention\Image\ImageManagerStatic as Image;
use Slim\Http\Environment;
use Slim\Http\Uri;
use function rename;
use function str_replace;
class MediaFolders
{
@@ -44,9 +44,9 @@ class MediaFolders
*/
public function fetch(string $path, string $mode = 'collection') : array
{
if ($mode == 'collection') {
if ($mode === 'collection') {
$result = $this->fetchCollection($path);
} elseif ($mode == 'single') {
} elseif ($mode === 'single') {
$result = $this->fetchSingle($path);
}
@@ -65,12 +65,11 @@ class MediaFolders
$result = [];
if (Filesystem::has($this->flextype['media_folders_meta']->getDirMetaLocation($path))) {
$result['path'] = $path;
$result['full_path'] = str_replace('/.meta', '', $this->flextype['media_folders_meta']->getDirMetaLocation($path));
$result['url'] = 'project/uploads/' . $path;
$result['path'] = $path;
$result['full_path'] = str_replace("/.meta", "", $this->flextype['media_folders_meta']->getDirMetaLocation($path));
$result['url'] = 'project/uploads/' . $path;
if ($this->flextype['registry']->has('flextype.settings.url') && $this->flextype['registry']->get('flextype.settings.url') != '') {
if ($this->flextype['registry']->has('flextype.settings.url') && $this->flextype['registry']->get('flextype.settings.url') !== '') {
$full_url = $this->flextype['registry']->get('flextype.settings.url');
} else {
$full_url = Uri::createFromEnvironment(new Environment($_SERVER))->getBaseUrl();
@@ -94,25 +93,25 @@ class MediaFolders
$result = [];
foreach (Filesystem::listContents($this->flextype['media_folders_meta']->getDirMetaLocation($path)) as $folder) {
if ($folder['type'] == 'dir') {
$result[$folder['dirname']]['full_path'] = str_replace("/.meta", "", $this->flextype['media_folders_meta']->getDirMetaLocation($folder['dirname']));
$result[$folder['dirname']]['url'] = 'project/uploads/' . $folder['dirname'];
if ($this->flextype['registry']->has('flextype.settings.url') && $this->flextype['registry']->get('flextype.settings.url') != '') {
$full_url = $this->flextype['registry']->get('flextype.settings.url');
} else {
$full_url = Uri::createFromEnvironment(new Environment($_SERVER))->getBaseUrl();
}
$result[$folder['dirname']]['full_url'] = $full_url . '/project/uploads/' . $folder['dirname'];
if ($folder['type'] !== 'dir') {
continue;
}
$result[$folder['dirname']]['full_path'] = str_replace('/.meta', '', $this->flextype['media_folders_meta']->getDirMetaLocation($folder['dirname']));
$result[$folder['dirname']]['url'] = 'project/uploads/' . $folder['dirname'];
if ($this->flextype['registry']->has('flextype.settings.url') && $this->flextype['registry']->get('flextype.settings.url') !== '') {
$full_url = $this->flextype['registry']->get('flextype.settings.url');
} else {
$full_url = Uri::createFromEnvironment(new Environment($_SERVER))->getBaseUrl();
}
$result[$folder['dirname']]['full_url'] = $full_url . '/project/uploads/' . $folder['dirname'];
}
return $result;
}
/**
* Create folder
*
@@ -124,15 +123,11 @@ class MediaFolders
*/
public function create(string $id) : bool
{
if (!Filesystem::has($this->getDirLocation($id)) && !Filesystem::has($this->flextype['media_folders_meta']->getDirMetaLocation($id))) {
if (Filesystem::createDir($this->getDirLocation($id)) && Filesystem::createDir($this->flextype['media_folders_meta']->getDirMetaLocation($id))) {
return true;
} else {
return false;
}
} else {
return false;
if (! Filesystem::has($this->getDirLocation($id)) && ! Filesystem::has($this->flextype['media_folders_meta']->getDirMetaLocation($id))) {
return Filesystem::createDir($this->getDirLocation($id)) && Filesystem::createDir($this->flextype['media_folders_meta']->getDirMetaLocation($id));
}
return false;
}
/**
@@ -147,15 +142,11 @@ class MediaFolders
*/
public function rename(string $id, string $new_id) : bool
{
if (!Filesystem::has($this->getDirLocation($new_id)) && !Filesystem::has($this->flextype['media_folders_meta']->getDirMetaLocation($new_id))) {
if (rename($this->getDirLocation($id), $this->getDirLocation($new_id)) && rename($this->flextype['media_folders_meta']->getDirMetaLocation($id), $this->flextype['media_folders_meta']->getDirMetaLocation($new_id))) {
return true;
} else {
return false;
}
} else {
return false;
if (! Filesystem::has($this->getDirLocation($new_id)) && ! Filesystem::has($this->flextype['media_folders_meta']->getDirMetaLocation($new_id))) {
return rename($this->getDirLocation($id), $this->getDirLocation($new_id)) && rename($this->flextype['media_folders_meta']->getDirMetaLocation($id), $this->flextype['media_folders_meta']->getDirMetaLocation($new_id));
}
return false;
}
/**
@@ -167,7 +158,7 @@ class MediaFolders
*
* @access public
*/
public function delete(string $id)
public function delete(string $id) : bool
{
Filesystem::deleteDir($this->getDirLocation($id));
Filesystem::deleteDir($this->flextype['media_folders_meta']->getDirMetaLocation($id));

View File

@@ -86,22 +86,22 @@ class Parser
}
break;
case 'shortcodes':
if ($cache === true && $this->flextype['registry']->get('flextype.settings.cache.enabled') === true) {
$key = md5($input);
case 'shortcodes':
if ($cache === true && $this->flextype['registry']->get('flextype.settings.cache.enabled') === true) {
$key = md5($input);
if ($data_from_cache = $this->flextype['cache']->fetch($key)) {
return $data_from_cache;
}
$data = $this->flextype['shortcodes']->process($input);
$this->flextype['cache']->save($key, $data);
return $data;
} else {
return $this->flextype['shortcodes']->process($input);
if ($data_from_cache = $this->flextype['cache']->fetch($key)) {
return $data_from_cache;
}
$data = $this->flextype['shortcodes']->process($input);
$this->flextype['cache']->save($key, $data);
return $data;
} else {
return $this->flextype['shortcodes']->process($input);
}
break;
default:
// code...

View File

@@ -14,9 +14,9 @@ use Slim\Http\Uri;
// Shortcode: [url]
$flextype['shortcodes']->addHandler('url', static function () use ($flextype) {
if ($flextype['registry']->has('flextype.settings.url') && $flextype['registry']->get('flextype.settings.url') != '') {
if ($flextype['registry']->has('flextype.settings.url') && $flextype['registry']->get('flextype.settings.url') !== '') {
return $flextype['registry']->get('flextype.settings.url');
} else {
return Uri::createFromEnvironment(new Environment($_SERVER))->getBaseUrl();
}
return Uri::createFromEnvironment(new Environment($_SERVER))->getBaseUrl();
});

View File

@@ -9,12 +9,12 @@ declare(strict_types=1);
namespace Flextype;
use Composer\Semver\Semver;
use Flextype\Component\Arr\Arr;
use Flextype\Component\Filesystem\Filesystem;
use Flextype\Component\I18n\I18n;
use Composer\Semver\Comparator;
use Composer\Semver\Semver;
use RuntimeException;
use function array_diff_key;
use function array_replace_recursive;
use function count;
use function filemtime;
@@ -94,19 +94,17 @@ class Plugins
$dictionary = $this->getPluginsDictionary($plugins_list, $locale);
$this->flextype['cache']->save($locale, $dictionary[$locale]);
}
} else {
// Init plugin configs
$plugins = [];
$plugin_settings = [];
$plugin_manifest = [];
$default_plugin_settings = [];
$project_plugin_settings = [];
$project_plugin_settings = [];
$default_plugin_manifest = [];
// Go through...
foreach ($plugins_list as $plugin) {
// Set plugin settings directory
$project_plugin_settings_dir = PATH['project'] . '/config/plugins/' . $plugin['dirname'];
@@ -156,7 +154,6 @@ class Plugins
// Check if is not set plugin priority
if (! isset($plugins[$plugin['dirname']]['settings']['priority'])) {
// Set default plugin priority = 1
$plugins[$plugin['dirname']]['settings']['priority'] = 100;
}
@@ -183,7 +180,6 @@ class Plugins
// Save plugins dictionary
$dictionary = $this->getPluginsDictionary($plugins_list, $locale);
$this->flextype['cache']->save($locale, $dictionary[$locale]);
}
$this->includeEnabledPlugins($flextype, $app);
@@ -260,9 +256,8 @@ class Plugins
*
* @access public
*/
public function getValidPluginsDependencies($plugins) : array
public function getValidPluginsDependencies(array $plugins) : array
{
// Set verified plugins array
$verified_plugins = [];
@@ -271,55 +266,55 @@ class Plugins
// Go through plugins list and verify them.
foreach ($plugins as $plugin_name => &$plugin_data) {
// Set verified true by default
$verified = true;
// If there is any dependencies for this plugin
if (isset($plugin_data['manifest']['dependencies'])) {
// Go through plugin dependencies
foreach ($plugin_data['manifest']['dependencies'] as $dependency => $constraints) {
// Verify flextype version
if ($dependency === 'flextype') {
if (!Semver::satisfies($this->flextype['registry']->get('flextype.manifest.version'), $constraints)) {
if (! Semver::satisfies($this->flextype['registry']->get('flextype.manifest.version'), $constraints)) {
$verified = false;
// Remove plugin where it is require this dependency
foreach ($plugins as $_plugin_name => $_plugin_data) {
if ($_plugin_data['manifest']['dependencies'][$plugin_name]) {
unset($plugins[$_plugin_name]);
unset($verified_plugins[$_plugin_name]);
if (! $_plugin_data['manifest']['dependencies'][$plugin_name]) {
continue;
}
}
unset($plugins[$_plugin_name]);
unset($verified_plugins[$_plugin_name]);
}
}
} else {
// Verify plugin dependencies
if (!isset($plugins[$dependency])) {
if (! isset($plugins[$dependency])) {
$verified = false;
// Remove plugin where it is require this dependency
foreach ($plugins as $_plugin_name => $_plugin_data) {
if ($_plugin_data['manifest']['dependencies'][$plugin_name]) {
unset($plugins[$_plugin_name]);
unset($verified_plugins[$_plugin_name]);
if (! $_plugin_data['manifest']['dependencies'][$plugin_name]) {
continue;
}
}
unset($plugins[$_plugin_name]);
unset($verified_plugins[$_plugin_name]);
}
} else {
$version = $plugins[$dependency]['manifest']['version'];
if (!Semver::satisfies($version, $constraints)) {
if (! Semver::satisfies($version, $constraints)) {
$verified = false;
// Remove plugin where it is require this dependency
foreach ($plugins as $_plugin_name => $_plugin_data) {
if ($_plugin_data['manifest']['dependencies'][$plugin_name]) {
unset($plugins[$_plugin_name]);
unset($verified_plugins[$_plugin_name]);
if (! $_plugin_data['manifest']['dependencies'][$plugin_name]) {
continue;
}
unset($plugins[$_plugin_name]);
unset($verified_plugins[$_plugin_name]);
}
}
}
@@ -328,9 +323,11 @@ class Plugins
}
// If plugin is verified than include it
if ($verified) {
$verified_plugins[$plugin_name] = $plugin_data;
if (! $verified) {
continue;
}
$verified_plugins[$plugin_name] = $plugin_data;
}
// Show alert if dependencies are not installed properly
@@ -338,11 +335,12 @@ class Plugins
if (count($diff) > 0) {
echo '<b>The following dependencies need to be installed properly:</b>';
echo '<ul>';
foreach($diff as $plugin_name => $plugin_data) {
echo '<li>'.$plugin_name.'</li>';
foreach ($diff as $plugin_name => $plugin_data) {
echo '<li>' . $plugin_name . '</li>';
}
echo '</ul>';
die();
die;
}
// Return verified plugins list

View File

@@ -10,13 +10,13 @@ declare(strict_types=1);
namespace Flextype;
use Flextype\Component\Arr\Arr;
use const PHP_EOL;
use function array_slice;
use function count;
use function implode;
use function ltrim;
use function preg_split;
use function trim;
use const PHP_EOL;
class Frontmatter
{

View File

@@ -10,11 +10,11 @@ declare(strict_types=1);
namespace Flextype;
use RuntimeException;
use function json_decode;
use function json_encode;
use const JSON_PRETTY_PRINT;
use const JSON_UNESCAPED_SLASHES;
use const JSON_UNESCAPED_UNICODE;
use function json_decode;
use function json_encode;
class Json
{

View File

@@ -27,10 +27,12 @@ class Serializer
'frontmatter' => [
'name' => 'frontmatter',
'ext' => 'md',
], 'json' => [
],
'json' => [
'name' => 'json',
'ext' => 'json',
], 'yaml' => [
],
'yaml' => [
'name' => 'yaml',
'ext' => 'yaml',
],

View File

@@ -0,0 +1,407 @@
<?php
declare(strict_types=1);
/**
* Flextype (http://flextype.org)
* Founded by Sergey Romanenko and maintained by Flextype Community.
*/
namespace Flextype\Support;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Criteria;
use Doctrine\Common\Collections\Expr\Comparison;
use Flextype\Component\Arr\Arr;
use Awilum\ArrayDots\ArrayDots;
use function array_merge;
use function array_rand;
use function count;
use function error_reporting;
use const E_NOTICE;
class Collection
{
/**
* Order Direction
*
* @var array
* @access public
*/
public $direction = [
'ASC' => Criteria::ASC,
'DESC' => Criteria::DESC,
];
/**
* Expression
*
* @var array
* @access public
*/
public $expression = [
'eq' => Comparison::EQ,
'=' => Comparison::EQ,
'<>' => Comparison::NEQ,
'!=' => Comparison::NEQ,
'neq' => Comparison::NEQ,
'<' => Comparison::LT,
'lt' => Comparison::LT,
'<=' => Comparison::LTE,
'lte' => Comparison::LTE,
'>' => Comparison::GT,
'gt' => Comparison::GT,
'>=' => Comparison::GTE,
'gte' => Comparison::GTE,
'is' => Comparison::IS,
'in' => Comparison::IN,
'nin' => Comparison::NIN,
'contains' => Comparison::CONTAINS,
'like' => Comparison::CONTAINS,
'member_of' => Comparison::MEMBER_OF,
'start_with' => Comparison::STARTS_WITH,
'ends_with' => Comparison::ENDS_WITH,
];
/**
* Collection
*
* @access private
*/
private $collection;
/**
* Criteria
*
* @access private
*/
private $criteria;
/**
* Error Reporting
*
* @access private
*/
private $errorReporting;
/**
* Constructor
*
* @access public
*/
public function __construct($array)
{
// Save error_reporting state and turn it off
// because PHP Doctrine Collections don't works with collections
// if there is no requested fields to search inside item:
// vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/ClosureExpressionVisitor.php
// line 40: return $object[$field];
//
// @todo research this issue and find possible better solution to avoid this in the future
$this->oldErrorReporting = error_reporting();
error_reporting($this->oldErrorReporting & ~E_NOTICE);
// Flatten a multi-dimensional array with dots.
if (Arr::isAssoc($array)) {
$flat_array = [];
foreach ($array as $key => $value) {
$flat_array[$key] = array_dot($value);
}
$array = $flat_array;
}
// Create Array Collection from entries array
$this->collection = new ArrayCollection($array);
// Create Criteria for filtering Selectable collections.
$this->criteria = new Criteria();
// Return
return $this;
}
public static function collect($array)
{
return new Collections($array);
}
public function merge(...$arrays)
{
$this->collection = new ArrayCollection(
array_merge($this->collection->toArray(), ...$arrays)
);
return $this;
}
/**
* Sets the where expression to evaluate when this Criteria is searched for.
*
* @param string $field The field path using dot notation.
* @param string $expr Expression @see $this->expression
* @param mixed $value Value
*
* @return
*
* @access public
*/
public function where(string $field, string $expr, $value)
{
$this->criteria->where(new Comparison($field, $this->expression[$expr], $value));
return $this;
}
/**
* Appends the where expression to evaluate when this Criteria is searched
* for using an AND with previous expression.
*
* @param string $field The field path using dot notation.
* @param string $expr Expression @see $this->expression
* @param mixed $value Value
*
* @return
*
* @access public
*/
public function andWhere(string $field, string $expr, $value)
{
$this->criteria->andWhere(new Comparison($field, $this->expression[$expr], $value));
return $this;
}
/**
* Appends the where expression to evaluate when this Criteria is searched
* for using an OR with previous expression.
*
* @param string $field The field path using dot notation.
* @param string $expr Expression @see $this->expression
* @param mixed $value Value
*
* @return
*
* @access public
*/
public function orWhere(string $field, string $expr, $value)
{
$this->criteria->orWhere(new Comparison($field, $this->expression[$expr], $value));
return $this;
}
/**
* Sets the ordering of the result of this Criteria.
*
* Keys are field and values are the order, being either ASC or DESC.
*
* @param string $field The field path using dot notation.
* @param string $direction Sort direction: asc or desc
*
* @return
*
* @access public
*/
public function orderBy(string $field, string $direction)
{
$this->criteria->orderBy([$field => $this->direction[$direction]]);
return $this;
}
/**
* Set the number of first result that this Criteria should return.
*
* @param int|null $firstResult The value to set.
*
* @return
*
* @access public
*/
public function setFirstResult(?int $firstResult)
{
$this->criteria->setFirstResult($firstResult);
return $this;
}
/**
* Sets the max results that this Criteria should return.
*
* @param int|null $limit The value to set.
*
* @return
*
* @access public
*/
public function limit(?int $limit)
{
$this->criteria->setMaxResults($limit);
return $this;
}
/**
* Returns a value indicating whether the collection contains any item of data.
*
* @return bool Return true or false.
*
* @access public
*/
public function exists() : bool
{
return $this->count() > 0;
}
/**
* Returns the number of items.
*
* @return int The number of items.
*
* @access public
*/
public function count() : int
{
return count($this->all());
}
/**
* Returns a last single item of result.
*
* @return array Item
*
* @access public
*/
public function last() : array
{
return array_undot($this->matchCollection()->last());
}
/**
* Returns a single item of result.
*
* Moves the internal iterator position to the next element and returns this element.
*
* @return array Item
*
* @access public
*/
public function next() : array
{
return array_undot($this->matchCollection()->next());
}
/**
* Returns a single item of result.
*
* Moves the internal iterator position to the next element and returns this element.
*
* @return array Item
*
* @access public
*/
public function shuffle() : array
{
$results = $this->matchCollection()->toArray();
return Arr::isAssoc($results) ?
Arr::shuffle(array_undot(array_dot($results))) :
$results;
}
/**
* Returns a single item of result.
*
* @return array Item
*
* @access public
*/
public function first() : array
{
$results = $this->matchCollection()->first();
return Arr::isAssoc($results) ?
array_undot($results) :
$results;
}
/**
* Returns random item from result.
*
* @return array The array data.
*
* @access public
*/
public function random() : array
{
$results = $this->matchCollection()->toArray();
return Arr::isAssoc($results) ?
$results[array_rand(array_undot(array_dot($results)))] :
$results[array_rand($results)];
}
/**
* Extracts a slice of $length elements starting at position $offset from the Collection.
*
* If $length is null it returns all elements from $offset to the end of the Collection.
* Keys have to be preserved by this method. Calling this method will only return
* the selected slice and NOT change the elements contained in the collection slice is called on.
*
* @param int $offset Slice begin index.
* @param int|null $length Length of the slice.
*
* @return array The array data.
*
* @access public
*/
public function slice(int $offset = 0, ?int $limit = null) : array
{
$results = $this->matchCollection()->slice($offset, $limit);
return Arr::isAssoc($results) ?
array_undot(array_dot($results)) :
$results;
}
/**
* Returns all results as an array.
*
* @return array The array data.
*
* @access public
*/
public function all() : array
{
$results = $this->matchCollection()->toArray();
return Arr::isAssoc($results) ?
array_undot(array_dot($results)) :
$results;
}
/**
* Match collection
*
* @access protected
*/
public function matchCollection()
{
// Match collection
$collection = $this->collection->matching($this->criteria);
// Restore error_reporting
error_reporting($this->oldErrorReporting);
// Return collection
return $collection;
}
}

View File

@@ -0,0 +1,22 @@
<?php
declare(strict_types=1);
/**
* Flextype (http://flextype.org)
* Founded by Sergey Romanenko and maintained by Flextype Community.
*/
use Flextype\Support\Collection;
if (! function_exists('collect')) {
/**
* Create a collection from the given value.
*
* @param array $value Items to collect
*/
function collect($array) : \Flextype\Support\Collection
{
return new Collection($array);
}
}

View File

@@ -169,7 +169,7 @@ date_default_timezone_set($flextype['registry']->get('flextype.settings.timezone
$shortcodes_extensions = $flextype['registry']->get('flextype.settings.shortcodes.extensions');
foreach ($shortcodes_extensions as $shortcodes_extension) {
$shortcodes_extension_file_path = ROOT_DIR . '/src/flextype/core/Parsers/shortcodes/' . $shortcodes_extension . 'ShortcodeExtension.php';
$shortcodes_extension_file_path = ROOT_DIR . '/src/flextype/Foundation/Parsers/shortcodes/' . $shortcodes_extension . 'ShortcodeExtension.php';
if (file_exists($shortcodes_extension_file_path)) {
include_once $shortcodes_extension_file_path;
}

View File

@@ -1,66 +0,0 @@
<?php
declare(strict_types=1);
/**
* Flextype (http://flextype.org)
* Founded by Sergey Romanenko and maintained by Flextype Community.
*/
namespace Flextype;
class Cors
{
/**
* Flextype Dependency Container
*/
private $flextype;
/**
* Flextype app
*/
private $app;
/**
* __construct
*/
public function __construct($flextype, $app)
{
$this->flextype = $flextype;
$this->app = $app;
}
/**
* Init CORS
*/
public function init()
{
$flextype = $this->flextype;
if ($flextype['registry']->get('flextype.settings.cors.enabled')) {
$this->app->options('/{routes:.+}', function ($request, $response, $args) {
return $response;
});
$this->app->add(function ($req, $res, $next) use ($flextype) {
$response = $next($req, $res);
// Set variables
$origin = $flextype['registry']->get('flextype.settings.cors.origin');
$headers = count($flextype['registry']->get('flextype.settings.cors.headers')) ? implode(', ', $flextype['registry']->get('flextype.settings.cors.headers')) : '';
$methods = count($flextype['registry']->get('flextype.settings.cors.methods')) ? implode(', ', $flextype['registry']->get('flextype.settings.cors.methods')) : '';
$expose = count($flextype['registry']->get('flextype.settings.cors.expose')) ? implode(', ', $flextype['registry']->get('flextype.settings.cors.expose')) : '';
$credentials = ($flextype['registry']->get('flextype.settings.cors.credentials')) ? true : false;
return $response
->withHeader('Access-Control-Allow-Origin', $origin)
->withHeader('Access-Control-Allow-Headers', $headers)
->withHeader('Access-Control-Allow-Methods', $methods)
->withHeader('Access-Control-Allow-Expose', $expose)
->withHeader('Access-Control-Allow-Credentials', $credentials);
});
}
}
}

View File

@@ -1,667 +0,0 @@
<?php
declare(strict_types=1);
/**
* Flextype (http://flextype.org)
* Founded by Sergey Romanenko and maintained by Flextype Community.
*/
namespace Flextype;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Criteria;
use Doctrine\Common\Collections\Expr\Comparison;
use Flextype\Component\Filesystem\Filesystem;
use Flextype\Component\Session\Session;
use Flextype\Component\Arr\Arr;
use Ramsey\Uuid\Uuid;
use function array_merge;
use function count;
use function date;
use function error_reporting;
use function in_array;
use function is_array;
use function is_bool;
use function json_encode;
use function ltrim;
use function md5;
use function rename;
use function rtrim;
use function str_replace;
use function strpos;
use function strtotime;
use function time;
class Entries
{
/**
* Current entry data array
*
* @var array
* @access public
*/
public $entry = [];
/**
* Current entries data array
*
* @var array
* @access public
*/
public $entries = [];
/**
* Expression
*
* @var array
* @access public
*/
public $expression = [
'eq' => Comparison::EQ,
'=' => Comparison::EQ,
'<>' => Comparison::NEQ,
'!=' => Comparison::NEQ,
'neq' => Comparison::NEQ,
'<' => Comparison::LT,
'lt' => Comparison::LT,
'<=' => Comparison::LTE,
'lte' => Comparison::LTE,
'>' => Comparison::GT,
'gt' => Comparison::GT,
'>=' => Comparison::GTE,
'gte' => Comparison::GTE,
'is' => Comparison::IS,
'in' => Comparison::IN,
'nin' => Comparison::NIN,
'contains' => Comparison::CONTAINS,
'like' => Comparison::CONTAINS,
'member_of' => Comparison::MEMBER_OF,
'start_with' => Comparison::STARTS_WITH,
'ends_with' => Comparison::ENDS_WITH,
];
/**
* Entires Order Direction
*
* @var array
* @access public
*/
public $direction = [
'asc' => Criteria::ASC,
'desc' => Criteria::DESC,
];
/**
* Entries Visibility
*
* @var array
* @access public
*/
public $visibility = [
'draft' => 'draft',
'hidden' => 'hidden',
'visible' => 'visible',
];
/**
* Entries system fields
*
* @var array
* @access public
*/
public $system_fields = [
'published_at' => 'published_at',
'published_by' => 'published_by',
'created_at' => 'created_at',
'modified_at' => 'modified_at',
'slug' => 'slug',
'routable' => 'routable',
'parsers' => 'parsers',
'visibility' => 'visibility',
];
/**
* Flextype Dependency Container
*
* @access private
*/
private $flextype;
/**
* Constructor
*
* @access public
*/
public function __construct($flextype)
{
$this->flextype = $flextype;
}
/**
* Fetch entry(entries)
*
* @param string $id Unique identifier of the entry(entries).
* @param array|null $filter Select items in collection by given conditions.
*
* @return array The entry array data.
*
* @access public
*/
public function fetch(string $id, ?array $filter = null) : array
{
// If filter is array then it is entries collection request
if (is_array($filter)) {
return $this->fetchCollection($id, $filter);
}
return $this->fetchSingle($id);
}
/**
* Fetch single entry
*
* @param string $id Unique identifier of the entry(entries).
*
* @return array The entry array data.
*
* @access public
*/
public function fetchSingle(string $id) : array
{
// Get entry file location
$entry_file = $this->getFileLocation($id);
// If requested entry file founded then process it
if (Filesystem::has($entry_file)) {
// Create unique entry cache_id
// Entry Cache ID = entry + entry file + entry file time stamp
if ($timestamp = Filesystem::getTimestamp($entry_file)) {
$entry_cache_id = md5('entry' . $entry_file . $timestamp);
} else {
$entry_cache_id = md5('entry' . $entry_file);
}
// Try to get the requested entry from cache
if ($this->flextype['cache']->contains($entry_cache_id)) {
// Try to fetch requested entry from the cache
if ($entry = $this->flextype['cache']->fetch($entry_cache_id)) {
// Run event onEntryAfterInitialized
$this->flextype['emitter']->emit('onEntryAfterInitialized');
// Return entry
return $entry;
}
// Return empty array
return [];
// else Try to get requested entry from the filesystem
}
$entry_decoded = $this->flextype['serializer']->decode(Filesystem::read($entry_file), 'frontmatter');
// Add predefined entry items
// Entry Published At
$entry_decoded['published_at'] = isset($entry_decoded['published_at']) ? (int) strtotime($entry_decoded['published_at']) : (int) Filesystem::getTimestamp($entry_file);
// Entry Created At
$entry_decoded['created_at'] = isset($entry_decoded['created_at']) ? (int) strtotime($entry_decoded['created_at']) : (int) Filesystem::getTimestamp($entry_file);
// Entry Modified
$entry_decoded['modified_at'] = (int) Filesystem::getTimestamp($entry_file);
// Entry Slug
$entry_decoded['slug'] = isset($entry_decoded['slug']) ? (string) $entry_decoded['slug'] : (string) ltrim(rtrim($id, '/'), '/');
// Entry Routable
$entry_decoded['routable'] = isset($entry_decoded['routable']) ? (bool) $entry_decoded['routable'] : true;
// Entry Visibility
if (isset($entry_decoded['visibility']) && in_array($entry_decoded['visibility'], $this->visibility)) {
$entry_decoded['visibility'] = (string) $this->visibility[$entry_decoded['visibility']];
} else {
$entry_decoded['visibility'] = (string) $this->visibility['visible'];
}
// Parsers
if (isset($entry_decoded['parsers'])) {
foreach ($entry_decoded['parsers'] as $parser_name => $parser_data) {
if (in_array($parser_name, ['markdown', 'shortcodes'])) {
if (isset($entry_decoded['parsers'][$parser_name]['enabled']) && $entry_decoded['parsers'][$parser_name]['enabled'] === true) {
if (isset($entry_decoded['parsers'][$parser_name]['cache']) && $entry_decoded['parsers'][$parser_name]['cache'] === true) {
$cache = true;
} else {
$cache = false;
}
if (isset($entry_decoded['parsers'][$parser_name]['fields'])) {
if (is_array($entry_decoded['parsers'][$parser_name]['fields'])) {
foreach ($entry_decoded['parsers'][$parser_name]['fields'] as $field) {
if (! in_array($field, $this->system_fields)) {
if ($parser_name == 'markdown') {
if (Arr::keyExists($entry_decoded, $field)) {
Arr::set($entry_decoded, $field, $this->flextype['parser']->parse(Arr::get($entry_decoded, $field), 'markdown', $cache));
}
}
if ($parser_name == 'shortcodes') {
if (Arr::keyExists($entry_decoded, $field)) {
Arr::set($entry_decoded, $field, $this->flextype['parser']->parse(Arr::get($entry_decoded, $field), 'shortcodes', $cache));
}
}
}
}
}
}
}
}
}
}
// Save decoded entry content into the cache
$this->flextype['cache']->save($entry_cache_id, $entry_decoded);
// Set entry to the Entry class property $entry
$this->entry = $entry_decoded;
// Run event onEntryAfterInitialized
$this->flextype['emitter']->emit('onEntryAfterInitialized');
// Return entry from the Entry class property $entry
return $this->entry;
}
// Return empty array
return [];
}
/**
* Fetch entries collection
*
* @param string $id Unique identifier of the entry(entries).
* @param array $filter Select items in collection by given conditions.
*
* @return array The entries array data.
*
* @access public
*/
public function fetchCollection(string $id, array $filter = []) : array
{
// Init Entries
$entries = [];
// Init Entries
$this->entries = $entries;
// Set Expression
$expression = $this->expression;
// Set Direction
$direction = $this->direction;
// Bind: Entry ID
$bind_id = $id;
// Bind: recursive
$bind_recursive = $filter['recursive'] ?? false;
// Bind: set first result
$bind_set_first_result = $filter['set_first_result'] ?? false;
// Bind: set max result
$bind_set_max_result = $filter['set_max_result'] ?? false;
// Bind: where
$bind_where = [];
if (isset($filter['where']['key']) && isset($filter['where']['expr']) && isset($filter['where']['value'])) {
$bind_where['where']['key'] = $filter['where']['key'];
$bind_where['where']['expr'] = $expression[$filter['where']['expr']];
$bind_where['where']['value'] = $filter['where']['value'];
}
// Bind: and where
$bind_and_where = [];
if (isset($filter['and_where'])) {
foreach ($filter['and_where'] as $key => $value) {
if (! isset($value['key']) || ! isset($value['expr']) || ! isset($value['value'])) {
continue;
}
$bind_and_where[$key] = $value;
}
}
// Bind: or where
$bind_or_where = [];
if (isset($filter['or_where'])) {
foreach ($filter['or_where'] as $key => $value) {
if (! isset($value['key']) || ! isset($value['expr']) || ! isset($value['value'])) {
continue;
}
$bind_or_where[$key] = $value;
}
}
// Bind: order by
$bind_order_by = [];
if (isset($filter['order_by']['field']) && isset($filter['order_by']['direction'])) {
$bind_order_by['order_by']['field'] = $filter['order_by']['field'];
$bind_order_by['order_by']['direction'] = $filter['order_by']['direction'];
}
// Get entries path
$entries_path = $this->getDirLocation($bind_id);
// Get entries list
$entries_list = Filesystem::listContents($entries_path, $bind_recursive);
// If entries founded in entries folder
if (count($entries_list) > 0) {
// Entries IDs
$entries_ids = '';
// Entries IDs timestamps
$entries_ids_timestamps = '';
// Create entries array from entries list and ignore current requested entry
foreach ($entries_list as $current_entry) {
if (strpos($current_entry['path'], $bind_id . '/entry' . '.' . $this->flextype->registry->get('flextype.settings.entries.extension')) !== false) {
// ignore ...
} else {
// We are checking...
// Whether the requested entry is a director and whether the file entry is in this directory.
if ($current_entry['type'] === 'dir' && Filesystem::has($current_entry['path'] . '/entry' . '.' . $this->flextype->registry->get('flextype.settings.entries.extension'))) {
// Get entry uid
// 1. Remove entries path
// 2. Remove left and right slashes
$uid = ltrim(rtrim(str_replace(PATH['project'] . '/entries/', '', $current_entry['path']), '/'), '/');
// For each founded entry we should create $entries array.
$entry = $this->fetch($uid);
// Flatten a multi-dimensional entries array with dots.
$entry = Arr::dot($entry);
// Add entry into the entries
$entries[$uid] = $entry;
// Create entries IDs list
$entries_ids .= $uid;
// Create entries IDs timestamps
$entries_ids_timestamps .= Filesystem::getTimestamp($current_entry['path'] . '/entry' . '.' . $this->flextype->registry->get('flextype.settings.entries.extension'));
}
}
}
// Create unique entries $cache_id
$cache_id = md5(
$bind_id .
$entries_ids .
$entries_ids_timestamps .
($bind_recursive ? 'true' : 'false') .
($bind_set_max_result ? $bind_set_max_result : '') .
($bind_set_first_result ? $bind_set_first_result : '') .
json_encode($bind_where) .
json_encode($bind_and_where) .
json_encode($bind_or_where) .
json_encode($bind_order_by)
);
// If requested entries exist with a specific cache_id,
// then we take them from the cache otherwise we look for them.
if ($this->flextype['cache']->contains($cache_id)) {
$entries = $this->flextype['cache']->fetch($cache_id);
} else {
// Save error_reporting state and turn it off
// because PHP Doctrine Collections don't works with collections
// if there is no requested fields to search:
// vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/ClosureExpressionVisitor.php
// line 40: return $object[$field];
//
// @todo research this issue and find possible better solution to avoid this in the future
$oldErrorReporting = error_reporting();
error_reporting(0);
// Create Array Collection from entries array
$collection = new ArrayCollection($entries);
// Create Criteria for filtering Selectable collections.
$criteria = new Criteria();
// Exec: where
if (isset($bind_where['where']['key']) && isset($bind_where['where']['expr']) && isset($bind_where['where']['value'])) {
$expr = new Comparison($bind_where['where']['key'], $bind_where['where']['expr'], $bind_where['where']['value']);
$criteria->where($expr);
}
// Exec: and where
if (isset($bind_and_where)) {
$_expr = [];
foreach ($bind_and_where as $key => $value) {
$_expr[$key] = new Comparison($value['key'], $expression[$value['expr']], $value['value']);
$criteria->andWhere($_expr[$key]);
}
}
// Exec: or where
if (isset($bind_or_where)) {
$_expr = [];
foreach ($bind_or_where as $key => $value) {
$_expr[$key] = new Comparison($value['key'], $expression[$value['expr']], $value['value']);
$criteria->orWhere($_expr[$key]);
}
}
// Exec: order by
if (isset($bind_order_by['order_by']['field']) && isset($bind_order_by['order_by']['direction'])) {
$criteria->orderBy([$bind_order_by['order_by']['field'] => $direction[$bind_order_by['order_by']['direction']]]);
}
// Exec: set max result
if ($bind_set_max_result) {
$criteria->setMaxResults($bind_set_max_result);
}
// Exec: set first result
if ($bind_set_first_result) {
$criteria->setFirstResult($bind_set_first_result);
}
// Get entries for matching criterias
$entries = $collection->matching($criteria);
// Gets a native PHP array representation of the collection.
$entries = $entries->toArray();
// Magic is here... dot and undot for entries array
// 1. Flatten a multi-dimensional entries array with dots.
// 2. Restore entries array with dots into correct multi-dimensional entries array
$entries = Arr::undot(Arr::dot($entries));
// Restore error_reporting
error_reporting($oldErrorReporting);
// Save entries into the cache
$this->flextype['cache']->save($cache_id, $entries);
}
// Set entries into the property entries
$this->entries = $entries;
// Run event onEntriesAfterInitialized
$this->flextype['emitter']->emit('onEntriesAfterInitialized');
}
// Return entries
return $this->entries;
}
/**
* Rename entry
*
* @param string $id Unique identifier of the entry(entries).
* @param string $new_id New Unique identifier of the entry(entries).
*
* @return bool True on success, false on failure.
*
* @access public
*/
public function rename(string $id, string $new_id) : bool
{
if (!Filesystem::has($this->getDirLocation($new_id))) {
return rename($this->getDirLocation($id), $this->getDirLocation($new_id));
} else {
return false;
}
}
/**
* Update entry
*
* @param string $id Unique identifier of the entry(entries).
* @param array $data Data to update for the entry.
*
* @return bool True on success, false on failure.
*
* @access public
*/
public function update(string $id, array $data) : bool
{
$entry_file = $this->getFileLocation($id);
if (Filesystem::has($entry_file)) {
$body = Filesystem::read($entry_file);
$entry = $this->flextype['serializer']->decode($body, 'frontmatter');
return Filesystem::write($entry_file, $this->flextype['serializer']->encode(array_merge($entry, $data), 'frontmatter'));
}
return false;
}
/**
* Create entry
*
* @param string $id Unique identifier of the entry(entries).
* @param array $data Data to create for the entry.
*
* @return bool True on success, false on failure.
*
* @access public
*/
public function create(string $id, array $data) : bool
{
$entry_dir = $this->getDirLocation($id);
if (! Filesystem::has($entry_dir)) {
// Try to create directory for new entry
if (Filesystem::createDir($entry_dir)) {
// Check if new entry file exists
if (! Filesystem::has($entry_file = $entry_dir . '/entry' . '.' . $this->flextype->registry->get('flextype.settings.entries.extension'))) {
$data['uuid'] = Uuid::uuid4()->toString();
$data['published_at'] = date($this->flextype->registry->get('flextype.settings.date_format'), time());
$data['created_at'] = date($this->flextype->registry->get('flextype.settings.date_format'), time());
$data['published_by'] = (Session::exists('uuid') ? Session::get('uuid') : '');
$data['created_by'] = (Session::exists('uuid') ? Session::get('uuid') : '');
if (isset($data['routable']) && is_bool($data['routable'])) {
$data['routable'] = $data['routable'];
} else {
$data['routable'] = true;
}
if (isset($data['visibility']) && in_array($data['visibility'], $this->visibility)) {
$data['visibility'] = $data['visibility'];
} else {
$data['visibility'] = 'visible';
}
return Filesystem::write($entry_file, $this->flextype['serializer']->encode($data, 'frontmatter'));
}
return false;
}
}
return false;
}
/**
* Delete entry
*
* @param string $id Unique identifier of the entry(entries).
*
* @return bool True on success, false on failure.
*
* @access public
*/
public function delete(string $id) : bool
{
return Filesystem::deleteDir($this->getDirLocation($id));
}
/**
* Copy entry(s)
*
* @param string $id Unique identifier of the entry(entries).
* @param string $new_id New Unique identifier of the entry(entries).
* @param bool $recursive Recursive copy entries.
*
* @return bool|null True on success, false on failure.
*
* @access public
*/
public function copy(string $id, string $new_id, bool $recursive = false) : ?bool
{
return Filesystem::copy($this->getDirLocation($id), $this->getDirLocation($new_id), $recursive);
}
/**
* Check whether entry exists
*
* @param string $id Unique identifier of the entry(entries).
*
* @return bool True on success, false on failure.
*
* @access public
*/
public function has(string $id) : bool
{
return Filesystem::has($this->getFileLocation($id));
}
/**
* Get entry file location
*
* @param string $id Unique identifier of the entry(entries).
*
* @return string entry file location
*
* @access private
*/
public function getFileLocation(string $id) : string
{
return PATH['project'] . '/entries/' . $id . '/entry' . '.' . $this->flextype->registry->get('flextype.settings.entries.extension');
}
/**
* Get entry directory location
*
* @param string $id Unique identifier of the entry(entries).
*
* @return string entry directory location
*
* @access private
*/
public function getDirLocation(string $id) : string
{
return PATH['project'] . '/entries/' . $id;
}
}