diff --git a/.php_cs.cache b/.php_cs.cache deleted file mode 100644 index 2eece6cf..00000000 --- a/.php_cs.cache +++ /dev/null @@ -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}} \ No newline at end of file diff --git a/BACKERS.md b/BACKERS.md index b6bcbe6f..991d24cb 100644 --- a/BACKERS.md +++ b/BACKERS.md @@ -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 diff --git a/composer.json b/composer.json index 94e11c0e..140a0337 100755 --- a/composer.json +++ b/composer.json @@ -73,7 +73,10 @@ }, "autoload": { "classmap": [ - "src" + "src/flextype" + ], + "files": [ + "src/flextype/Support/helpers.php" ] }, "require-dev": { diff --git a/src/flextype/endpoints/access.php b/src/flextype/Endpoints/access.php similarity index 100% rename from src/flextype/endpoints/access.php rename to src/flextype/Endpoints/access.php diff --git a/src/flextype/endpoints/config.php b/src/flextype/Endpoints/config.php similarity index 100% rename from src/flextype/endpoints/config.php rename to src/flextype/Endpoints/config.php diff --git a/src/flextype/endpoints/entries.php b/src/flextype/Endpoints/entries.php similarity index 100% rename from src/flextype/endpoints/entries.php rename to src/flextype/Endpoints/entries.php diff --git a/src/flextype/endpoints/files.php b/src/flextype/Endpoints/files.php similarity index 100% rename from src/flextype/endpoints/files.php rename to src/flextype/Endpoints/files.php diff --git a/src/flextype/endpoints/folders.php b/src/flextype/Endpoints/folders.php similarity index 100% rename from src/flextype/endpoints/folders.php rename to src/flextype/Endpoints/folders.php diff --git a/src/flextype/endpoints/images.php b/src/flextype/Endpoints/images.php similarity index 100% rename from src/flextype/endpoints/images.php rename to src/flextype/Endpoints/images.php diff --git a/src/flextype/endpoints/registry.php b/src/flextype/Endpoints/registry.php similarity index 100% rename from src/flextype/endpoints/registry.php rename to src/flextype/Endpoints/registry.php diff --git a/src/flextype/core/Cache/AcpuAdapter.php b/src/flextype/Foundation/Cache/AcpuAdapter.php similarity index 100% rename from src/flextype/core/Cache/AcpuAdapter.php rename to src/flextype/Foundation/Cache/AcpuAdapter.php diff --git a/src/flextype/core/Cache/ArrayAdapter.php b/src/flextype/Foundation/Cache/ArrayAdapter.php similarity index 100% rename from src/flextype/core/Cache/ArrayAdapter.php rename to src/flextype/Foundation/Cache/ArrayAdapter.php diff --git a/src/flextype/core/Cache/Cache.php b/src/flextype/Foundation/Cache/Cache.php similarity index 99% rename from src/flextype/core/Cache/Cache.php rename to src/flextype/Foundation/Cache/Cache.php index 266c14f2..ef83984b 100755 --- a/src/flextype/core/Cache/Cache.php +++ b/src/flextype/Foundation/Cache/Cache.php @@ -160,6 +160,7 @@ class Cache if ($lifetime === null) { $lifetime = $this->getLifetime(); } + $this->driver->save($id, $data, $lifetime); } diff --git a/src/flextype/core/Cache/CacheAdapterInterface.php b/src/flextype/Foundation/Cache/CacheAdapterInterface.php similarity index 100% rename from src/flextype/core/Cache/CacheAdapterInterface.php rename to src/flextype/Foundation/Cache/CacheAdapterInterface.php diff --git a/src/flextype/core/Cache/FilesystemAdapter.php b/src/flextype/Foundation/Cache/FilesystemAdapter.php similarity index 100% rename from src/flextype/core/Cache/FilesystemAdapter.php rename to src/flextype/Foundation/Cache/FilesystemAdapter.php diff --git a/src/flextype/core/Cache/MemcachedAdapter.php b/src/flextype/Foundation/Cache/MemcachedAdapter.php similarity index 100% rename from src/flextype/core/Cache/MemcachedAdapter.php rename to src/flextype/Foundation/Cache/MemcachedAdapter.php diff --git a/src/flextype/core/Cache/RedisAdapter.php b/src/flextype/Foundation/Cache/RedisAdapter.php similarity index 100% rename from src/flextype/core/Cache/RedisAdapter.php rename to src/flextype/Foundation/Cache/RedisAdapter.php diff --git a/src/flextype/core/Cache/SQLite3Adapter.php b/src/flextype/Foundation/Cache/SQLite3Adapter.php similarity index 100% rename from src/flextype/core/Cache/SQLite3Adapter.php rename to src/flextype/Foundation/Cache/SQLite3Adapter.php diff --git a/src/flextype/core/Cache/WinCacheAdapter.php b/src/flextype/Foundation/Cache/WinCacheAdapter.php similarity index 100% rename from src/flextype/core/Cache/WinCacheAdapter.php rename to src/flextype/Foundation/Cache/WinCacheAdapter.php diff --git a/src/flextype/core/Cache/ZendDataCacheAdapter.php b/src/flextype/Foundation/Cache/ZendDataCacheAdapter.php similarity index 100% rename from src/flextype/core/Cache/ZendDataCacheAdapter.php rename to src/flextype/Foundation/Cache/ZendDataCacheAdapter.php diff --git a/src/flextype/core/Config/Config.php b/src/flextype/Foundation/Config/Config.php similarity index 64% rename from src/flextype/core/Config/Config.php rename to src/flextype/Foundation/Config/Config.php index 26b6c26a..7f6b43f3 100644 --- a/src/flextype/core/Config/Config.php +++ b/src/flextype/Foundation/Config/Config.php @@ -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 * diff --git a/src/flextype/core/Container/Container.php b/src/flextype/Foundation/Container/Container.php similarity index 100% rename from src/flextype/core/Container/Container.php rename to src/flextype/Foundation/Container/Container.php diff --git a/src/flextype/Foundation/Cors/Cors.php b/src/flextype/Foundation/Cors/Cors.php new file mode 100644 index 00000000..f09b01f8 --- /dev/null +++ b/src/flextype/Foundation/Cors/Cors.php @@ -0,0 +1,70 @@ +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); + }); + } +} diff --git a/src/flextype/Foundation/Entries/Entries.php b/src/flextype/Foundation/Entries/Entries.php new file mode 100755 index 00000000..cc61be10 --- /dev/null +++ b/src/flextype/Foundation/Entries/Entries.php @@ -0,0 +1,467 @@ + '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; + } +} diff --git a/src/flextype/core/Media/MediaFiles.php b/src/flextype/Foundation/Media/MediaFiles.php similarity index 76% rename from src/flextype/core/Media/MediaFiles.php rename to src/flextype/Foundation/Media/MediaFiles.php index dcea6255..47582e0d 100644 --- a/src/flextype/core/Media/MediaFiles.php +++ b/src/flextype/Foundation/Media/MediaFiles.php @@ -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)); diff --git a/src/flextype/core/Media/MediaFilesMeta.php b/src/flextype/Foundation/Media/MediaFilesMeta.php similarity index 95% rename from src/flextype/core/Media/MediaFilesMeta.php rename to src/flextype/Foundation/Media/MediaFilesMeta.php index 3a60d186..7a1161e1 100644 --- a/src/flextype/core/Media/MediaFilesMeta.php +++ b/src/flextype/Foundation/Media/MediaFilesMeta.php @@ -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')); } diff --git a/src/flextype/core/Media/MediaFolders.php b/src/flextype/Foundation/Media/MediaFolders.php similarity index 62% rename from src/flextype/core/Media/MediaFolders.php rename to src/flextype/Foundation/Media/MediaFolders.php index 4e79beb0..a4026e4b 100644 --- a/src/flextype/core/Media/MediaFolders.php +++ b/src/flextype/Foundation/Media/MediaFolders.php @@ -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)); diff --git a/src/flextype/core/Media/MediaFoldersMeta.php b/src/flextype/Foundation/Media/MediaFoldersMeta.php similarity index 100% rename from src/flextype/core/Media/MediaFoldersMeta.php rename to src/flextype/Foundation/Media/MediaFoldersMeta.php diff --git a/src/flextype/core/Parsers/Markdown.php b/src/flextype/Foundation/Parsers/Markdown.php similarity index 100% rename from src/flextype/core/Parsers/Markdown.php rename to src/flextype/Foundation/Parsers/Markdown.php diff --git a/src/flextype/core/Parsers/Parser.php b/src/flextype/Foundation/Parsers/Parser.php similarity index 76% rename from src/flextype/core/Parsers/Parser.php rename to src/flextype/Foundation/Parsers/Parser.php index 7b1d2cd6..49540dbe 100644 --- a/src/flextype/core/Parsers/Parser.php +++ b/src/flextype/Foundation/Parsers/Parser.php @@ -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... diff --git a/src/flextype/core/Parsers/shortcodes/EntriesShortcodeExtension.php b/src/flextype/Foundation/Parsers/shortcodes/EntriesShortcodeExtension.php similarity index 100% rename from src/flextype/core/Parsers/shortcodes/EntriesShortcodeExtension.php rename to src/flextype/Foundation/Parsers/shortcodes/EntriesShortcodeExtension.php diff --git a/src/flextype/core/Parsers/shortcodes/RegistryShortcodeExtension.php b/src/flextype/Foundation/Parsers/shortcodes/RegistryShortcodeExtension.php similarity index 100% rename from src/flextype/core/Parsers/shortcodes/RegistryShortcodeExtension.php rename to src/flextype/Foundation/Parsers/shortcodes/RegistryShortcodeExtension.php diff --git a/src/flextype/core/Parsers/shortcodes/UrlShortcodeExtension.php b/src/flextype/Foundation/Parsers/shortcodes/UrlShortcodeExtension.php similarity index 74% rename from src/flextype/core/Parsers/shortcodes/UrlShortcodeExtension.php rename to src/flextype/Foundation/Parsers/shortcodes/UrlShortcodeExtension.php index 4375be28..59aa979d 100644 --- a/src/flextype/core/Parsers/shortcodes/UrlShortcodeExtension.php +++ b/src/flextype/Foundation/Parsers/shortcodes/UrlShortcodeExtension.php @@ -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(); }); diff --git a/src/flextype/core/Plugins/Plugins.php b/src/flextype/Foundation/Plugins/Plugins.php similarity index 90% rename from src/flextype/core/Plugins/Plugins.php rename to src/flextype/Foundation/Plugins/Plugins.php index 85d1ec36..c861ce43 100755 --- a/src/flextype/core/Plugins/Plugins.php +++ b/src/flextype/Foundation/Plugins/Plugins.php @@ -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 'The following dependencies need to be installed properly:'; echo ''; - die(); + die; } // Return verified plugins list diff --git a/src/flextype/core/Serializers/Frontmatter.php b/src/flextype/Foundation/Serializers/Frontmatter.php similarity index 100% rename from src/flextype/core/Serializers/Frontmatter.php rename to src/flextype/Foundation/Serializers/Frontmatter.php index 242f8c22..a6883d67 100644 --- a/src/flextype/core/Serializers/Frontmatter.php +++ b/src/flextype/Foundation/Serializers/Frontmatter.php @@ -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 { diff --git a/src/flextype/core/Serializers/Json.php b/src/flextype/Foundation/Serializers/Json.php similarity index 100% rename from src/flextype/core/Serializers/Json.php rename to src/flextype/Foundation/Serializers/Json.php index 71c80171..03b5a5ae 100644 --- a/src/flextype/core/Serializers/Json.php +++ b/src/flextype/Foundation/Serializers/Json.php @@ -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 { diff --git a/src/flextype/core/Serializers/Serializer.php b/src/flextype/Foundation/Serializers/Serializer.php similarity index 98% rename from src/flextype/core/Serializers/Serializer.php rename to src/flextype/Foundation/Serializers/Serializer.php index fbf71ef0..8808af50 100644 --- a/src/flextype/core/Serializers/Serializer.php +++ b/src/flextype/Foundation/Serializers/Serializer.php @@ -27,10 +27,12 @@ class Serializer 'frontmatter' => [ 'name' => 'frontmatter', 'ext' => 'md', - ], 'json' => [ + ], + 'json' => [ 'name' => 'json', 'ext' => 'json', - ], 'yaml' => [ + ], + 'yaml' => [ 'name' => 'yaml', 'ext' => 'yaml', ], diff --git a/src/flextype/core/Serializers/Yaml.php b/src/flextype/Foundation/Serializers/Yaml.php similarity index 100% rename from src/flextype/core/Serializers/Yaml.php rename to src/flextype/Foundation/Serializers/Yaml.php diff --git a/src/flextype/Support/Collection.php b/src/flextype/Support/Collection.php new file mode 100644 index 00000000..9337540a --- /dev/null +++ b/src/flextype/Support/Collection.php @@ -0,0 +1,407 @@ + 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; + } +} diff --git a/src/flextype/Support/helpers.php b/src/flextype/Support/helpers.php new file mode 100644 index 00000000..e7e8f935 --- /dev/null +++ b/src/flextype/Support/helpers.php @@ -0,0 +1,22 @@ +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; } diff --git a/src/flextype/core/Cors/Cors.php b/src/flextype/core/Cors/Cors.php deleted file mode 100644 index f7073417..00000000 --- a/src/flextype/core/Cors/Cors.php +++ /dev/null @@ -1,66 +0,0 @@ -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); - }); - } - } -} diff --git a/src/flextype/core/Entries/Entries.php b/src/flextype/core/Entries/Entries.php deleted file mode 100755 index 3bbb157a..00000000 --- a/src/flextype/core/Entries/Entries.php +++ /dev/null @@ -1,667 +0,0 @@ - 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; - } -}