This commit is contained in:
2022-03-15 10:52:21 +01:00
parent 12814f64d4
commit ef94f03cde
476 changed files with 4612 additions and 1563 deletions

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Acl
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -14,7 +14,6 @@ use Countable;
use Grav\Common\Utils;
use IteratorAggregate;
use JsonSerializable;
use RuntimeException;
use Traversable;
use function count;
use function is_array;
@@ -25,6 +24,7 @@ use function strlen;
/**
* Class Access
* @package Grav\Framework\Acl
* @implements IteratorAggregate<string,bool|array|null>
*/
class Access implements JsonSerializable, IteratorAggregate, Countable
{
@@ -34,7 +34,7 @@ class Access implements JsonSerializable, IteratorAggregate, Countable
private $rules;
/** @var array */
private $ops;
/** @var array */
/** @var array<string,bool|array|null> */
private $acl = [];
/** @var array */
private $inherited = [];
@@ -78,12 +78,7 @@ class Access implements JsonSerializable, IteratorAggregate, Countable
$inherited = array_diff_key($parent->getAllActions(), $acl);
$this->inherited += $parent->inherited + array_fill_keys(array_keys($inherited), $name ?? $parent->getName());
$acl = array_replace($acl, $inherited);
if (null === $acl) {
throw new RuntimeException('Internal error');
}
$this->acl = $acl;
$this->acl = array_replace($acl, $inherited);
}
/**

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Acl
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -16,11 +16,11 @@ use IteratorAggregate;
use RuntimeException;
use Traversable;
use function count;
use function strlen;
/**
* Class Action
* @package Grav\Framework\Acl
* @implements IteratorAggregate<string,Action>
*/
class Action implements IteratorAggregate, Countable
{
@@ -37,7 +37,7 @@ class Action implements IteratorAggregate, Countable
/** @var Action|null */
protected $parent;
/** @var Action[] */
/** @var array<string,Action> */
protected $children = [];
/**
@@ -48,8 +48,8 @@ class Action implements IteratorAggregate, Countable
{
$label = $action['label'] ?? null;
if (!$label) {
if ($pos = strrpos($name, '.')) {
$label = substr($name, $pos + 1);
if ($pos = mb_strrpos($name, '.')) {
$label = mb_substr($name, $pos + 1);
} else {
$label = $name;
}
@@ -114,9 +114,9 @@ class Action implements IteratorAggregate, Countable
*/
public function getScope(): string
{
$pos = strpos($this->name, '.');
$pos = mb_strpos($this->name, '.');
if ($pos) {
return substr($this->name, 0, $pos);
return mb_substr($this->name, 0, $pos);
}
return $this->name;
@@ -127,7 +127,7 @@ class Action implements IteratorAggregate, Countable
*/
public function getLevels(): int
{
return substr_count($this->name, '.');
return mb_substr_count($this->name, '.');
}
/**
@@ -161,12 +161,12 @@ class Action implements IteratorAggregate, Countable
*/
public function addChild(Action $child): void
{
if (strpos($child->name, "{$this->name}.") !== 0) {
if (mb_strpos($child->name, "{$this->name}.") !== 0) {
throw new RuntimeException('Bad child');
}
$child->setParent($this);
$name = substr($child->name, strlen($this->name) + 1);
$name = mb_substr($child->name, mb_strlen($this->name) + 1);
$this->children[$name] = $child;
}
@@ -190,6 +190,7 @@ class Action implements IteratorAggregate, Countable
/**
* @return array
*/
#[\ReturnTypeWillChange]
public function __debugInfo()
{
return [

View File

@@ -3,26 +3,32 @@
/**
* @package Grav\Framework\Acl
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
namespace Grav\Framework\Acl;
use ArrayAccess;
use ArrayIterator;
use Countable;
use IteratorAggregate;
use RecursiveIteratorIterator;
use RuntimeException;
use Traversable;
use function count;
/**
* Class Permissions
* @package Grav\Framework\Acl
* @implements ArrayAccess<string,Action>
* @implements IteratorAggregate<string,Action>
*/
class Permissions implements \ArrayAccess, \Countable, \IteratorAggregate
class Permissions implements ArrayAccess, Countable, IteratorAggregate
{
/** @var Action[] */
/** @var array<string,Action> */
protected $instances = [];
/** @var Action[] */
/** @var array<string,Action> */
protected $actions = [];
/** @var array */
protected $nested = [];
@@ -142,9 +148,6 @@ class Permissions implements \ArrayAccess, \Countable, \IteratorAggregate
public function addTypes(array $types): void
{
$types = array_replace($this->types, $types);
if (null === $types) {
throw new RuntimeException('Internal error');
}
$this->types = $types;
}
@@ -206,6 +209,7 @@ class Permissions implements \ArrayAccess, \Countable, \IteratorAggregate
/**
* @return ArrayIterator|Traversable
*/
#[\ReturnTypeWillChange]
public function getIterator()
{
return new ArrayIterator($this->actions);
@@ -214,6 +218,7 @@ class Permissions implements \ArrayAccess, \Countable, \IteratorAggregate
/**
* @return array
*/
#[\ReturnTypeWillChange]
public function __debugInfo()
{
return [

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Acl
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -62,12 +62,14 @@ class PermissionsReader
{
$list = [];
foreach ($actions as $name => $action) {
$prefixNname = $prefix . $name;
$list[$prefixNname] = null;
$prefixName = $prefix . $name;
$list[$prefixName] = null;
// Support nested sets of actions.
if (isset($action['actions']) && is_array($action['actions'])) {
$list += static::read($action['actions'], "{$prefixNname}.");
$innerList = static::read($action['actions'], "{$prefixName}.");
$list += $innerList;
}
unset($action['actions']);
@@ -76,7 +78,7 @@ class PermissionsReader
$action = static::addDefaults($action);
// Build flat list of actions.
$list[$prefixNname] = $action;
$list[$prefixName] = $action;
}
return $list;
@@ -172,9 +174,6 @@ class PermissionsReader
$scopes[] = $action;
$action = array_replace_recursive(...$scopes);
if (null === $action) {
throw new RuntimeException('Internal error');
}
$newType = $defaults['type'] ?? null;
if ($newType && $newType !== $type) {

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Acl
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -17,6 +17,7 @@ use RocketTheme\Toolbox\ArrayTraits\Iterator;
/**
* Class Action
* @package Grav\Framework\Acl
* @implements RecursiveIterator<string,Action>
*/
class RecursiveActionIterator implements RecursiveIterator, \Countable
{
@@ -26,6 +27,7 @@ class RecursiveActionIterator implements RecursiveIterator, \Countable
* @see \Iterator::key()
* @return string
*/
#[\ReturnTypeWillChange]
public function key()
{
/** @var Action $current */

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Cache
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Cache
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -33,11 +33,15 @@ class ChainCache extends AbstractCache
* Chain Cache constructor.
* @param array $caches
* @param null|int|DateInterval $defaultLifetime
* @throws \Psr\SimpleCache\InvalidArgumentException|InvalidArgumentException
* @throws InvalidArgumentException
*/
public function __construct(array $caches, $defaultLifetime = null)
{
parent::__construct('', $defaultLifetime);
try {
parent::__construct('', $defaultLifetime);
} catch (\Psr\SimpleCache\InvalidArgumentException $e) {
throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
}
if (!$caches) {
throw new InvalidArgumentException('At least one cache must be specified');

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Cache
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -29,12 +29,16 @@ class DoctrineCache extends AbstractCache
* @param CacheProvider $doctrineCache
* @param string $namespace
* @param null|int|DateInterval $defaultLifetime
* @throws \Psr\SimpleCache\InvalidArgumentException|InvalidArgumentException
* @throws InvalidArgumentException
*/
public function __construct(CacheProvider $doctrineCache, $namespace = '', $defaultLifetime = null)
{
// Do not use $namespace or $defaultLifetime directly, store them with constructor and fetch with methods.
parent::__construct($namespace, $defaultLifetime);
try {
parent::__construct($namespace, $defaultLifetime);
} catch (\Psr\SimpleCache\InvalidArgumentException $e) {
throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
}
// Set namespace to Doctrine Cache provider if it was given.
$namespace = $this->getNamespace();

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Cache
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -42,9 +42,13 @@ class FileCache extends AbstractCache
*/
public function __construct($namespace = '', $defaultLifetime = null, $folder = null)
{
parent::__construct($namespace, $defaultLifetime ?: 31557600); // = 1 year
try {
parent::__construct($namespace, $defaultLifetime ?: 31557600); // = 1 year
$this->initFileCache($namespace, $folder ?? '');
$this->initFileCache($namespace, $folder ?? '');
} catch (\Psr\SimpleCache\InvalidArgumentException $e) {
throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
}
}
/**
@@ -103,7 +107,13 @@ class FileCache extends AbstractCache
{
$file = $this->getFile($key);
return (!file_exists($file) || @unlink($file) || !file_exists($file));
$result = false;
if (file_exists($file)) {
$result = @unlink($file);
$result &= !file_exists($file);
}
return $result;
}
/**
@@ -156,7 +166,7 @@ class FileCache extends AbstractCache
*/
protected function initFileCache($namespace, $directory)
{
if (!isset($directory[0])) {
if ($directory === '') {
$directory = sys_get_temp_dir() . '/grav-cache';
} else {
$directory = realpath($directory) ?: $directory;
@@ -246,6 +256,7 @@ class FileCache extends AbstractCache
/**
* @return void
*/
#[\ReturnTypeWillChange]
public function __destruct()
{
if ($this->tmp !== null && file_exists($this->tmp)) {

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Cache
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Cache
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Cache
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Cache
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Cache
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Cache
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Collection
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -68,6 +68,7 @@ class AbstractFileCollection extends AbstractLazyCollection implements FileColle
/**
* @param Criteria $criteria
* @return ArrayCollection
* @phpstan-return ArrayCollection<TKey,T>
* @todo Implement lazy matching
*/
public function matching(Criteria $criteria)
@@ -93,6 +94,7 @@ class AbstractFileCollection extends AbstractLazyCollection implements FileColle
foreach (array_reverse($orderings) as $field => $ordering) {
$next = ClosureExpressionVisitor::sortByField($field, $ordering === Criteria::DESC ? -1 : 1, $next);
}
/** @phpstan-ignore-next-line */
if (null === $next) {
throw new RuntimeException('Criteria is missing orderings');
}
@@ -162,6 +164,7 @@ class AbstractFileCollection extends AbstractLazyCollection implements FileColle
* @param SeekableIterator $iterator
* @param int $nestingLimit
* @return array
* @phpstan-param SeekableIterator<int,T> $iterator
*/
protected function doInitializeByIterator(SeekableIterator $iterator, $nestingLimit)
{
@@ -211,7 +214,6 @@ class AbstractFileCollection extends AbstractLazyCollection implements FileColle
protected function doInitializeChildren(array $children, $nestingLimit)
{
$objects = [];
foreach ($children as $iterator) {
$objects += $this->doInitializeByIterator($iterator, $nestingLimit);
}

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Collection
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -14,6 +14,7 @@ use Closure;
use Grav\Framework\Compat\Serializable;
use Grav\Framework\Flex\Interfaces\FlexObjectInterface;
use InvalidArgumentException;
use Iterator;
use function array_key_exists;
use function array_slice;
use function count;
@@ -79,17 +80,17 @@ abstract class AbstractIndexCollection implements CollectionInterface
/**
* {@inheritDoc}
*/
#[\ReturnTypeWillChange]
public function key()
{
/** @phpstan-var TKey $key */
$key = (string)key($this->entries);
return $key;
/** @phpstan-var TKey */
return (string)key($this->entries);
}
/**
* {@inheritDoc}
*/
#[\ReturnTypeWillChange]
public function next()
{
$value = next($this->entries);
@@ -101,6 +102,7 @@ abstract class AbstractIndexCollection implements CollectionInterface
/**
* {@inheritDoc}
*/
#[\ReturnTypeWillChange]
public function current()
{
$value = current($this->entries);
@@ -131,7 +133,7 @@ abstract class AbstractIndexCollection implements CollectionInterface
{
$key = $this->isAllowedElement($element) ? $this->getCurrentKey($element) : null;
if (!$key || !isset($this->entries[$key])) {
if (null !== $key || !isset($this->entries[$key])) {
return false;
}
@@ -143,49 +145,64 @@ abstract class AbstractIndexCollection implements CollectionInterface
/**
* Required by interface ArrayAccess.
*
* {@inheritDoc}
* @param string|int|null $offset
* @return bool
* @phpstan-param TKey|null $offset
*/
#[\ReturnTypeWillChange]
public function offsetExists($offset)
{
return $this->containsKey($offset);
/** @phpstan-ignore-next-line phpstan bug? */
return $offset !== null ? $this->containsKey($offset) : false;
}
/**
* Required by interface ArrayAccess.
*
* {@inheritDoc}
* @param string|int|null $offset
* @return mixed
* @phpstan-param TKey|null $offset
*/
#[\ReturnTypeWillChange]
public function offsetGet($offset)
{
return $this->get($offset);
/** @phpstan-ignore-next-line phpstan bug? */
return $offset !== null ? $this->get($offset) : null;
}
/**
* Required by interface ArrayAccess.
*
* {@inheritDoc}
* @param string|int|null $offset
* @param mixed $value
* @return void
* @phpstan-param TKey|null $offset
*/
#[\ReturnTypeWillChange]
public function offsetSet($offset, $value)
{
if (null === $offset) {
$this->add($value);
} else {
/** @phpstan-ignore-next-line phpstan bug? */
$this->set($offset, $value);
}
$this->set($offset, $value);
}
/**
* Required by interface ArrayAccess.
*
* {@inheritDoc}
* @param string|int|null $offset
* @return void
* @phpstan-param TKey|null $offset
*/
#[\ReturnTypeWillChange]
public function offsetUnset($offset)
{
$this->remove($offset);
if ($offset !== null) {
/** @phpstan-ignore-next-line phpstan bug? */
$this->remove($offset);
}
}
/**
@@ -255,6 +272,7 @@ abstract class AbstractIndexCollection implements CollectionInterface
/**
* {@inheritDoc}
*/
#[\ReturnTypeWillChange]
public function count()
{
return count($this->entries);
@@ -298,7 +316,9 @@ abstract class AbstractIndexCollection implements CollectionInterface
* Required by interface IteratorAggregate.
*
* {@inheritDoc}
* @phpstan-return Iterator<TKey,T>
*/
#[\ReturnTypeWillChange]
public function getIterator()
{
return new ArrayIterator($this->loadElements());
@@ -341,6 +361,7 @@ abstract class AbstractIndexCollection implements CollectionInterface
*
* @return string
*/
#[\ReturnTypeWillChange]
public function __toString()
{
return __CLASS__ . '@' . spl_object_hash($this);
@@ -395,7 +416,7 @@ abstract class AbstractIndexCollection implements CollectionInterface
$keys = $this->getKeys();
shuffle($keys);
return $this->createFrom(array_replace(array_flip($keys), $this->entries) ?? []);
return $this->createFrom(array_replace(array_flip($keys), $this->entries));
}
/**
@@ -436,9 +457,11 @@ abstract class AbstractIndexCollection implements CollectionInterface
*
* @param int $size Size of each chunk.
* @return array
* @phpstan-return array<array<TKey,T>>
*/
public function chunk($size)
{
/** @phpstan-var array<array<TKey,T>> */
return $this->loadCollection($this->entries)->chunk($size);
}
@@ -466,6 +489,7 @@ abstract class AbstractIndexCollection implements CollectionInterface
*
* @return array
*/
#[\ReturnTypeWillChange]
public function jsonSerialize()
{
return $this->loadCollection()->jsonSerialize();

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Collection
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -22,11 +22,15 @@ use Doctrine\Common\Collections\AbstractLazyCollection as BaseAbstractLazyCollec
*/
abstract class AbstractLazyCollection extends BaseAbstractLazyCollection implements CollectionInterface
{
/** @var ArrayCollection The backed collection to use */
/**
* @par ArrayCollection
* @phpstan-var ArrayCollection<TKey,T>
*/
protected $collection;
/**
* {@inheritDoc}
* @phpstan-return ArrayCollection<TKey,T>
*/
public function reverse()
{
@@ -37,6 +41,7 @@ abstract class AbstractLazyCollection extends BaseAbstractLazyCollection impleme
/**
* {@inheritDoc}
* @phpstan-return ArrayCollection<TKey,T>
*/
public function shuffle()
{
@@ -57,6 +62,8 @@ abstract class AbstractLazyCollection extends BaseAbstractLazyCollection impleme
/**
* {@inheritDoc}
* @phpstan-param array<TKey,T> $keys
* @phpstan-return ArrayCollection<TKey,T>
*/
public function select(array $keys)
{
@@ -67,6 +74,8 @@ abstract class AbstractLazyCollection extends BaseAbstractLazyCollection impleme
/**
* {@inheritDoc}
* @phpstan-param array<TKey,T> $keys
* @phpstan-return ArrayCollection<TKey,T>
*/
public function unselect(array $keys)
{
@@ -78,6 +87,7 @@ abstract class AbstractLazyCollection extends BaseAbstractLazyCollection impleme
/**
* @return array
*/
#[\ReturnTypeWillChange]
public function jsonSerialize()
{
$this->initialize();

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Collection
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -30,7 +30,10 @@ class ArrayCollection extends BaseArrayCollection implements CollectionInterface
*/
public function reverse()
{
return $this->createFrom(array_reverse($this->toArray()));
$keys = array_reverse($this->toArray());
/** @phpstan-var static<TKey,T> */
return $this->createFrom($keys);
}
/**
@@ -43,8 +46,10 @@ class ArrayCollection extends BaseArrayCollection implements CollectionInterface
{
$keys = $this->getKeys();
shuffle($keys);
$keys = array_replace(array_flip($keys), $this->toArray());
return $this->createFrom(array_replace(array_flip($keys), $this->toArray()) ?? []);
/** @phpstan-var static<TKey,T> */
return $this->createFrom($keys);
}
/**
@@ -52,9 +57,11 @@ class ArrayCollection extends BaseArrayCollection implements CollectionInterface
*
* @param int $size Size of each chunk.
* @return array
* @phpstan-return array<array<TKey,T>>
*/
public function chunk($size)
{
/** @phpstan-var array<array<TKey,T>> */
return array_chunk($this->toArray(), $size, true);
}
@@ -63,9 +70,9 @@ class ArrayCollection extends BaseArrayCollection implements CollectionInterface
*
* Collection is returned in the order of $keys given to the function.
*
* @param array<int|string> $keys
* @param array<int,string> $keys
* @return static
* @phpstan-param array<TKey> $keys
* @phpstan-param TKey[] $keys
* @phpstan-return static<TKey,T>
*/
public function select(array $keys)
@@ -77,6 +84,7 @@ class ArrayCollection extends BaseArrayCollection implements CollectionInterface
}
}
/** @phpstan-var static<TKey,T> */
return $this->createFrom($list);
}
@@ -85,11 +93,15 @@ class ArrayCollection extends BaseArrayCollection implements CollectionInterface
*
* @param array<int|string> $keys
* @return static
* @phpstan-param TKey[] $keys
* @phpstan-return static<TKey,T>
*/
public function unselect(array $keys)
{
return $this->select(array_diff($this->getKeys(), $keys));
$list = array_diff($this->getKeys(), $keys);
/** @phpstan-var static<TKey,T> */
return $this->select($list);
}
/**
@@ -97,6 +109,7 @@ class ArrayCollection extends BaseArrayCollection implements CollectionInterface
*
* @return array
*/
#[\ReturnTypeWillChange]
public function jsonSerialize()
{
return $this->toArray();

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Collection
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -43,6 +43,7 @@ interface CollectionInterface extends Collection, JsonSerializable
*
* @param int $size Size of each chunk.
* @return array
* @phpstan-return array<array<TKey,T>>
*/
public function chunk($size);

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Collection
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Collection
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Compat
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\ContentBlock
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -161,6 +161,7 @@ class ContentBlock implements ContentBlockInterface
/**
* @return string
*/
#[\ReturnTypeWillChange]
public function __toString()
{
try {

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\ContentBlock
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\ContentBlock
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -29,6 +29,8 @@ class HtmlBlock extends ContentBlock implements HtmlBlockInterface
/** @var array */
protected $scripts = [];
/** @var array */
protected $links = [];
/** @var array */
protected $html = [];
/**
@@ -40,6 +42,7 @@ class HtmlBlock extends ContentBlock implements HtmlBlockInterface
$this->sortAssets($assets['styles']);
$this->sortAssets($assets['scripts']);
$this->sortAssets($assets['links']);
$this->sortAssets($assets['html']);
return $assets;
@@ -73,6 +76,15 @@ class HtmlBlock extends ContentBlock implements HtmlBlockInterface
return $this->getAssetsInLocation('scripts', $location);
}
/**
* @param string $location
* @return array
*/
public function getLinks($location = 'head')
{
return $this->getAssetsInLocation('links', $location);
}
/**
* @param string $location
* @return array
@@ -98,6 +110,9 @@ class HtmlBlock extends ContentBlock implements HtmlBlockInterface
if ($this->scripts) {
$array['scripts'] = $this->scripts;
}
if ($this->links) {
$array['links'] = $this->links;
}
if ($this->html) {
$array['html'] = $this->html;
}
@@ -117,6 +132,7 @@ class HtmlBlock extends ContentBlock implements HtmlBlockInterface
$this->frameworks = isset($serialized['frameworks']) ? (array) $serialized['frameworks'] : [];
$this->styles = isset($serialized['styles']) ? (array) $serialized['styles'] : [];
$this->scripts = isset($serialized['scripts']) ? (array) $serialized['scripts'] : [];
$this->links = isset($serialized['links']) ? (array) $serialized['links'] : [];
$this->html = isset($serialized['html']) ? (array) $serialized['html'] : [];
}
@@ -199,11 +215,14 @@ class HtmlBlock extends ContentBlock implements HtmlBlockInterface
$content = (string) $element['content'];
$type = !empty($element['type']) ? (string) $element['type'] : 'text/css';
unset($element['content'], $element['type']);
$this->styles[$location][md5($content) . sha1($content)] = [
':type' => 'inline',
':priority' => (int) $priority,
'content' => $content,
'type' => $type
'type' => $type,
'element' => $element
];
return true;
@@ -229,18 +248,23 @@ class HtmlBlock extends ContentBlock implements HtmlBlockInterface
$src = $element['src'];
$type = !empty($element['type']) ? (string) $element['type'] : 'text/javascript';
$defer = isset($element['defer']);
$async = isset($element['async']);
$loading = !empty($element['loading']) ? (string) $element['loading'] : null;
$defer = !empty($element['defer']);
$async = !empty($element['async']);
$handle = !empty($element['handle']) ? (string) $element['handle'] : '';
unset($element['src'], $element['type'], $element['loading'], $element['defer'], $element['async'], $element['handle']);
$this->scripts[$location][md5($src) . sha1($src)] = [
':type' => 'file',
':priority' => (int) $priority,
'src' => $src,
'type' => $type,
'loading' => $loading,
'defer' => $defer,
'async' => $async,
'handle' => $handle
'handle' => $handle,
'element' => $element
];
return true;
@@ -266,12 +290,83 @@ class HtmlBlock extends ContentBlock implements HtmlBlockInterface
$content = (string) $element['content'];
$type = !empty($element['type']) ? (string) $element['type'] : 'text/javascript';
$loading = !empty($element['loading']) ? (string) $element['loading'] : null;
unset($element['content'], $element['type'], $element['loading']);
$this->scripts[$location][md5($content) . sha1($content)] = [
':type' => 'inline',
':priority' => (int) $priority,
'content' => $content,
'type' => $type
'type' => $type,
'loading' => $loading,
'element' => $element
];
return true;
}
/**
* @param string|array $element
* @param int $priority
* @param string $location
* @return bool
*/
public function addModule($element, $priority = 0, $location = 'head')
{
if (!is_array($element)) {
$element = ['src' => (string) $element];
}
$element['type'] = 'module';
return $this->addScript($element, $priority, $location);
}
/**
* @param string|array $element
* @param int $priority
* @param string $location
* @return bool
*/
public function addInlineModule($element, $priority = 0, $location = 'head')
{
if (!is_array($element)) {
$element = ['content' => (string) $element];
}
$element['type'] = 'module';
return $this->addInlineScript($element, $priority, $location);
}
/**
* @param array $element
* @param int $priority
* @param string $location
* @return bool
*/
public function addLink($element, $priority = 0, $location = 'head')
{
if (!is_array($element) || empty($element['rel']) || empty($element['href'])) {
return false;
}
if (!isset($this->links[$location])) {
$this->links[$location] = [];
}
$rel = (string) $element['rel'];
$href = (string) $element['href'];
unset($element['rel'], $element['href']);
$this->links[$location][md5($href) . sha1($href)] = [
':type' => 'file',
':priority' => (int) $priority,
'href' => $href,
'rel' => $rel,
'element' => $element,
];
return true;
@@ -309,6 +404,7 @@ class HtmlBlock extends ContentBlock implements HtmlBlockInterface
'frameworks' => $this->frameworks,
'styles' => $this->styles,
'scripts' => $this->scripts,
'links' => $this->links,
'html' => $this->html
];
@@ -333,6 +429,14 @@ class HtmlBlock extends ContentBlock implements HtmlBlockInterface
}
}
foreach ($blockAssets['links'] as $location => $links) {
if (!isset($assets['links'][$location])) {
$assets['links'][$location] = $links;
} elseif ($links) {
$assets['links'][$location] += $links;
}
}
foreach ($blockAssets['html'] as $location => $htmls) {
if (!isset($assets['html'][$location])) {
$assets['html'][$location] = $htmls;
@@ -391,7 +495,7 @@ class HtmlBlock extends ContentBlock implements HtmlBlockInterface
*/
protected function sortAssets(array &$array)
{
foreach ($array as $location => &$items) {
foreach ($array as &$items) {
$this->sortAssetsInLocation($items);
}
}

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\ContentBlock
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -37,6 +37,13 @@ interface HtmlBlockInterface extends ContentBlockInterface
*/
public function getScripts($location = 'head');
/**
* @param string $location
* @return array
*/
public function getLinks($location = 'head');
/**
* @param string $location
* @return array
@@ -76,7 +83,6 @@ interface HtmlBlockInterface extends ContentBlockInterface
*/
public function addScript($element, $priority = 0, $location = 'head');
/**
* @param string|array $element
* @param int $priority
@@ -85,6 +91,35 @@ interface HtmlBlockInterface extends ContentBlockInterface
*/
public function addInlineScript($element, $priority = 0, $location = 'head');
/**
* Shortcut for writing addScript(['type' => 'module', 'src' => ...]).
*
* @param string|array $element
* @param int $priority
* @param string $location
* @return bool
*/
public function addModule($element, $priority = 0, $location = 'head');
/**
* Shortcut for writing addInlineScript(['type' => 'module', 'content' => ...]).
*
* @param string|array $element
* @param int $priority
* @param string $location
* @return bool
*/
public function addInlineModule($element, $priority = 0, $location = 'head');
/**
* @param array $element
* @param int $priority
* @param string $location
* @return bool
*/
public function addLink($element, $priority = 0, $location = 'head');
/**
* @param string $html
* @param int $priority

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Controller
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -97,7 +97,7 @@ trait ControllerResponseTrait
$headers = $headers ?? [];
$options = $options ?? ['force_download' => true];
$file_parts = pathinfo($filename);
$file_parts = Utils::pathinfo($filename);
if (!isset($headers['Content-Type'])) {
$mimetype = Utils::getMimeByExtension($file_parts['extension']);
@@ -140,9 +140,9 @@ trait ControllerResponseTrait
$code = (int)$this->getConfig()->get('system.pages.redirect_default_code', 302);
}
$ext = Utils::pathinfo($url, PATHINFO_EXTENSION);
$accept = $this->getAccept(['application/json', 'text/html']);
if ($accept === 'application/json') {
if ($ext === 'json' || $accept === 'application/json') {
return $this->createJsonResponse(['code' => $code, 'status' => 'redirect', 'redirect' => $url]);
}
@@ -217,6 +217,7 @@ trait ControllerResponseTrait
'code' => $code,
'status' => 'error',
'message' => $message,
'redirect' => null,
'error' => [
'code' => $code,
'message' => $message

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\DI
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
/**
* @package Grav\Framework\File
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -55,6 +55,7 @@ class AbstractFile implements FileInterface
/**
* Unlock file when the object gets destroyed.
*/
#[\ReturnTypeWillChange]
public function __destruct()
{
if ($this->isLocked()) {
@@ -65,6 +66,7 @@ class AbstractFile implements FileInterface
/**
* @return void
*/
#[\ReturnTypeWillChange]
public function __clone()
{
$this->handle = null;
@@ -191,15 +193,16 @@ class AbstractFile implements FileInterface
$this->handle = @fopen($this->filepath, 'cb+') ?: null;
if (!$this->handle) {
$error = error_get_last();
$message = $error['message'] ?? 'Unknown error';
throw new RuntimeException("Opening file for writing failed on error {$error['message']}");
throw new RuntimeException("Opening file for writing failed on error {$message}");
}
}
$lock = $block ? LOCK_EX : LOCK_EX | LOCK_NB;
// Some filesystems do not support file locks, only fail if another process holds the lock.
$this->locked = flock($this->handle, $lock, $wouldblock) || !$wouldblock;
$this->locked = flock($this->handle, $lock, $wouldBlock) || !$wouldBlock;
return $this->locked;
}

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
/**
* @package Grav\Framework\File
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -28,4 +28,13 @@ class CsvFile extends DataFile
{
parent::__construct($filepath, $formatter);
}
/**
* @return array
*/
public function load(): array
{
/** @var array */
return parent::load();
}
}

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
/**
* @package Grav\Framework\File
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
/**
* @package Grav\Framework\File
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -20,15 +20,6 @@ use function is_string;
*/
class File extends AbstractFile
{
/**
* {@inheritdoc}
* @see FileInterface::load()
*/
public function load()
{
return parent::load();
}
/**
* {@inheritdoc}
* @see FileInterface::save()

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
/**
* @package Grav\Framework\File\Formatter
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
/**
* @package Grav\Framework\File\Formatter
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -16,6 +16,7 @@ use Grav\Framework\File\Interfaces\FileFormatterInterface;
use JsonSerializable;
use RuntimeException;
use stdClass;
use function count;
use function is_array;
use function is_object;
use function is_scalar;

View File

@@ -5,13 +5,14 @@ declare(strict_types=1);
/**
* @package Grav\Framework\File\Formatter
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
namespace Grav\Framework\File\Formatter;
use Grav\Framework\File\Interfaces\FileFormatterInterface;
use RuntimeException;
/**
* Class IniFormatter
@@ -59,7 +60,7 @@ class IniFormatter extends AbstractFormatter
$decoded = @parse_ini_string($data);
if ($decoded === false) {
throw new \RuntimeException('Decoding INI failed');
throw new RuntimeException('Decoding INI failed');
}
return $decoded;

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
/**
* @package Grav\Framework\File\Formatter
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -75,9 +75,11 @@ class JsonFormatter extends AbstractFormatter
if (is_string($options)) {
$list = preg_split('/[\s,|]+/', $options);
$options = 0;
foreach ($list as $option) {
if (isset($this->encodeOptions[$option])) {
$options += $this->encodeOptions[$option];
if ($list) {
foreach ($list as $option) {
if (isset($this->encodeOptions[$option])) {
$options += $this->encodeOptions[$option];
}
}
}
} else {
@@ -100,9 +102,11 @@ class JsonFormatter extends AbstractFormatter
if (is_string($options)) {
$list = preg_split('/[\s,|]+/', $options);
$options = 0;
foreach ($list as $option) {
if (isset($this->decodeOptions[$option])) {
$options += $this->decodeOptions[$option];
if ($list) {
foreach ($list as $option) {
if (isset($this->decodeOptions[$option])) {
$options += $this->decodeOptions[$option];
}
}
}
} else {
@@ -117,6 +121,7 @@ class JsonFormatter extends AbstractFormatter
* Returns recursion depth used in decode() function.
*
* @return int
* @phpstan-return positive-int
*/
public function getDecodeDepth(): int
{

View File

@@ -5,13 +5,14 @@ declare(strict_types=1);
/**
* @package Grav\Framework\File\Formatter
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
namespace Grav\Framework\File\Formatter;
use Grav\Framework\File\Interfaces\FileFormatterInterface;
use RuntimeException;
/**
* Class MarkdownFormatter
@@ -99,7 +100,7 @@ class MarkdownFormatter extends AbstractFormatter
// Normalize line endings to Unix style.
$encoded = preg_replace("/(\r\n|\r)/u", "\n", $encoded);
if (null === $encoded) {
throw new \RuntimeException('Encoding markdown failed');
throw new RuntimeException('Encoding markdown failed');
}
return $encoded;
@@ -126,7 +127,7 @@ class MarkdownFormatter extends AbstractFormatter
// Normalize line endings to Unix style.
$data = preg_replace("/(\r\n|\r)/u", "\n", $data);
if (null === $data) {
throw new \RuntimeException('Decoding markdown failed');
throw new RuntimeException('Decoding markdown failed');
}
// Parse header.

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
/**
* @package Grav\Framework\File\Formatter
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
/**
* @package Grav\Framework\File\Formatter
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -107,7 +107,9 @@ class YamlFormatter extends AbstractFormatter
$saved = @ini_get('yaml.decode_php');
@ini_set('yaml.decode_php', '0');
$decoded = @yaml_parse($data);
@ini_set('yaml.decode_php', $saved);
if ($saved !== false) {
@ini_set('yaml.decode_php', $saved);
}
if ($decoded !== false) {
return (array) $decoded;

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
/**
* @package Grav\Framework\File
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -28,4 +28,13 @@ class IniFile extends DataFile
{
parent::__construct($filepath, $formatter);
}
/**
* @return array
*/
public function load(): array
{
/** @var array */
return parent::load();
}
}

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
/**
* @package Grav\Framework\File
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
/**
* @package Grav\Framework\File
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
/**
* @package Grav\Framework\File
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
/**
* @package Grav\Framework\File
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -28,4 +28,13 @@ class MarkdownFile extends DataFile
{
parent::__construct($filepath, $formatter);
}
/**
* @return array
*/
public function load(): array
{
/** @var array */
return parent::load();
}
}

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
/**
* @package Grav\Framework\File
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -28,4 +28,13 @@ class YamlFile extends DataFile
{
parent::__construct($filepath, $formatter);
}
/**
* @return array
*/
public function load(): array
{
/** @var array */
return parent::load();
}
}

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
/**
* @package Grav\Framework\Filesystem
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -15,6 +15,7 @@ use Grav\Framework\Filesystem\Interfaces\FilesystemInterface;
use RuntimeException;
use function count;
use function dirname;
use function is_array;
use function pathinfo;
/**
@@ -150,7 +151,10 @@ class Filesystem implements FilesystemInterface
*/
public function basename(string $path, ?string $suffix = null): string
{
return $suffix ? basename($path, $suffix) : basename($path);
// Escape path.
$path = str_replace(['%2F', '%5C'], '/', rawurlencode($path));
return rawurldecode($suffix ? basename($path, $suffix) : basename($path));
}
/**
@@ -176,6 +180,7 @@ class Filesystem implements FilesystemInterface
* @param string $path
* @param int $levels
* @return string
* @phpstan-param positive-int $levels
*/
public function pathname(string $path, int $levels = 1): string
{
@@ -204,6 +209,7 @@ class Filesystem implements FilesystemInterface
* @param string $path
* @param int $levels
* @return array
* @phpstan-param positive-int $levels
*/
protected function dirnameInternal(?string $scheme, string $path, int $levels = 1): array
{
@@ -229,20 +235,30 @@ class Filesystem implements FilesystemInterface
*/
protected function pathinfoInternal(?string $scheme, string $path, ?int $options = null)
{
if ($options) {
return pathinfo($path, $options);
$path = str_replace(['%2F', '%5C'], ['/', '\\'], rawurlencode($path));
if (null === $options) {
$info = pathinfo($path);
} else {
$info = pathinfo($path, $options);
}
$info = pathinfo($path);
if (!is_array($info)) {
return rawurldecode($info);
}
$info = array_map('rawurldecode', $info);
if (null !== $scheme) {
$info['scheme'] = $scheme;
$dirname = isset($info['dirname']) && $info['dirname'] !== '.' ? $info['dirname'] : null;
if (null !== $dirname) {
/** @phpstan-ignore-next-line because pathinfo('') doesn't have dirname */
$dirname = $info['dirname'] ?? '.';
if ('' !== $dirname && '.' !== $dirname) {
// In Windows dirname may be using backslashes, fix that.
if (DIRECTORY_SEPARATOR !== '/') {
$dirname = str_replace('\\', '/', $dirname);
$dirname = str_replace(DIRECTORY_SEPARATOR, '/', $dirname);
}
$info['dirname'] = $scheme . '://' . $dirname;

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
/**
* @package Grav\Framework\Filesystem
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -31,6 +31,7 @@ interface FilesystemInterface
* @param int $levels The number of parent directories to go up (>= 1).
* @return string Returns parent path.
* @throws RuntimeException
* @phpstan-param positive-int $levels
* @api
*/
public function parent(string $path, int $levels = 1): string;
@@ -46,7 +47,7 @@ interface FilesystemInterface
public function normalize(string $path): string;
/**
* Returns filename component of path.
* Unicode-safe and stream-safe `\basename()` replacement.
*
* @param string $path A filename or path, does not need to exist as a file.
* @param string|null $suffix If the filename ends in suffix this will also be cut off.
@@ -56,7 +57,7 @@ interface FilesystemInterface
public function basename(string $path, ?string $suffix = null): string;
/**
* Stream-safe `\dirname()` replacement.
* Unicode-safe and stream-safe `\dirname()` replacement.
*
* @see http://php.net/manual/en/function.dirname.php
*
@@ -64,12 +65,13 @@ interface FilesystemInterface
* @param int $levels The number of parent directories to go up (>= 1).
* @return string Returns path to the directory.
* @throws RuntimeException
* @phpstan-param positive-int $levels
* @api
*/
public function dirname(string $path, int $levels = 1): string;
/**
* Stream-safe `\pathinfo()` replacement.
* Unicode-safe and stream-safe `\pathinfo()` replacement.
*
* @see http://php.net/manual/en/function.pathinfo.php
*

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
/**
* @package Grav\Framework\Flex
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -62,7 +62,7 @@ class Flex implements FlexInterface
*/
public function addDirectoryType(string $type, string $blueprint, array $config = [])
{
$config = array_replace_recursive(['enabled' => true], $this->config ?? [], $config);
$config = array_replace_recursive(['enabled' => true], $this->config, $config);
$this->types[$type] = new FlexDirectory($type, $blueprint, $config);
@@ -123,6 +123,7 @@ class Flex implements FlexInterface
* @param array|null $keys
* @param string|null $keyField
* @return FlexCollectionInterface|null
* @phpstan-return FlexCollectionInterface<FlexObjectInterface>|null
*/
public function getCollection(string $type, array $keys = null, string $keyField = null): ?FlexCollectionInterface
{
@@ -137,11 +138,12 @@ class Flex implements FlexInterface
* collection_class: Class to be used to create the collection. Defaults to ObjectCollection.
* @return FlexCollectionInterface
* @throws RuntimeException
* @phpstan-return FlexCollectionInterface<FlexObjectInterface>
*/
public function getMixedCollection(array $keys, array $options = []): FlexCollectionInterface
{
$collectionClass = $options['collection_class'] ?? ObjectCollection::class;
if (!class_exists($collectionClass)) {
if (!is_a($collectionClass, FlexCollectionInterface::class, true)) {
throw new RuntimeException(sprintf('Cannot create collection: Class %s does not exist', $collectionClass));
}
@@ -231,7 +233,7 @@ class Flex implements FlexInterface
// Use the original key ordering.
if (!$guessed) {
$list = array_replace(array_fill_keys($keys, null), $list) ?? [];
$list = array_replace(array_fill_keys($keys, null), $list);
} else {
// We have mixed keys, we need to map flex keys back to storage keys.
$results = [];

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Flex
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -19,6 +19,7 @@ use Grav\Common\User\Interfaces\UserInterface;
use Grav\Common\Utils;
use Grav\Framework\Cache\CacheInterface;
use Grav\Framework\ContentBlock\HtmlBlock;
use Grav\Framework\Flex\Interfaces\FlexIndexInterface;
use Grav\Framework\Flex\Interfaces\FlexObjectInterface;
use Grav\Framework\Object\ObjectCollection;
use Grav\Framework\Flex\Interfaces\FlexCollectionInterface;
@@ -47,7 +48,7 @@ class FlexCollection extends ObjectCollection implements FlexCollectionInterface
private $_flexDirectory;
/** @var string */
private $_keyField;
private $_keyField = 'storage_key';
/**
* Get list of cached methods.
@@ -124,6 +125,7 @@ class FlexCollection extends ObjectCollection implements FlexCollectionInterface
*/
public function getFlexFeatures(): array
{
/** @var array $implements */
$implements = class_implements($this);
$list = [];
@@ -152,7 +154,11 @@ class FlexCollection extends ObjectCollection implements FlexCollectionInterface
arsort($matching, SORT_NUMERIC);
}
return $this->select(array_keys($matching));
/** @var string[] $array */
$array = array_keys($matching);
/** @phpstan-var static<T> */
return $this->select($array);
}
/**
@@ -163,7 +169,7 @@ class FlexCollection extends ObjectCollection implements FlexCollectionInterface
{
$criteria = Criteria::create()->orderBy($order);
/** @var FlexCollectionInterface $matching */
/** @phpstan-var FlexCollectionInterface<T> $matching */
$matching = $this->matching($criteria);
return $matching;
@@ -171,7 +177,8 @@ class FlexCollection extends ObjectCollection implements FlexCollectionInterface
/**
* @param array $filters
* @return FlexCollectionInterface|Collection
* @return static
* @phpstan-return static<T>
*/
public function filterBy(array $filters)
{
@@ -182,6 +189,7 @@ class FlexCollection extends ObjectCollection implements FlexCollectionInterface
$criteria->andWhere($expr->eq($key, $value));
}
/** @phpstan-var static<T> */
return $this->matching($criteria);
}
@@ -336,6 +344,7 @@ class FlexCollection extends ObjectCollection implements FlexCollectionInterface
*/
public function getIndex()
{
/** @phpstan-var FlexIndexInterface<T> */
return $this->getFlexDirectory()->getIndex($this->getKeys(), $this->getKeyField());
}
@@ -460,7 +469,7 @@ class FlexCollection extends ObjectCollection implements FlexCollectionInterface
* @param string $key
* @return array
*/
public function getMetaData(string $key): array
public function getMetaData($key): array
{
$object = $this->get($key);
@@ -481,7 +490,7 @@ class FlexCollection extends ObjectCollection implements FlexCollectionInterface
*/
public function getKeyField(): string
{
return $this->_keyField ?? 'storage_key';
return $this->_keyField;
}
/**
@@ -496,13 +505,18 @@ class FlexCollection extends ObjectCollection implements FlexCollectionInterface
$list = $this->call('isAuthorized', [$action, $scope, $user]);
$list = array_filter($list);
return $this->select(array_keys($list));
/** @var string[] $keys */
$keys = array_keys($list);
/** @phpstan-var static<T> */
return $this->select($keys);
}
/**
* @param string $value
* @param string $field
* @return T|null
* @return FlexObjectInterface|null
* @phpstan-return T|null
*/
public function find($value, $field = 'id')
{
@@ -520,6 +534,7 @@ class FlexCollection extends ObjectCollection implements FlexCollectionInterface
/**
* @return array
*/
#[\ReturnTypeWillChange]
public function jsonSerialize()
{
$elements = [];
@@ -538,6 +553,7 @@ class FlexCollection extends ObjectCollection implements FlexCollectionInterface
/**
* @return array
*/
#[\ReturnTypeWillChange]
public function __debugInfo()
{
return [

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Flex
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -21,7 +21,7 @@ use Grav\Common\Utils;
use Grav\Framework\Cache\Adapter\DoctrineCache;
use Grav\Framework\Cache\Adapter\MemoryCache;
use Grav\Framework\Cache\CacheInterface;
use Grav\Framework\Flex\Interfaces\FlexAuthorizeInterface;
use Grav\Framework\Filesystem\Filesystem;
use Grav\Framework\Flex\Interfaces\FlexCollectionInterface;
use Grav\Framework\Flex\Interfaces\FlexDirectoryInterface;
use Grav\Framework\Flex\Interfaces\FlexFormInterface;
@@ -45,7 +45,6 @@ use function is_callable;
/**
* Class FlexDirectory
* @package Grav\Framework\Flex
* @template T
*/
class FlexDirectory implements FlexDirectoryInterface
{
@@ -57,9 +56,15 @@ class FlexDirectory implements FlexDirectoryInterface
protected $blueprint_file;
/** @var Blueprint[] */
protected $blueprints;
/** @var FlexIndexInterface[] */
/**
* @var FlexIndexInterface[]
* @phpstan-var FlexIndexInterface<FlexObjectInterface>[]
*/
protected $indexes = [];
/** @var FlexCollectionInterface|null */
/**
* @var FlexCollectionInterface|null
* @phpstan-var FlexCollectionInterface<FlexObjectInterface>|null
*/
protected $collection;
/** @var bool */
protected $enabled;
@@ -213,8 +218,17 @@ class FlexDirectory implements FlexDirectoryInterface
/** @var UniformResourceLocator $locator */
$locator = $grav['locator'];
/** @var string $filename Filename is always string */
$filename = $locator->findResource($this->getDirectoryConfigUri($name), true, true);
$filename = $this->getDirectoryConfigUri($name);
if (file_exists($filename)) {
$filename = $locator->findResource($filename, true);
} else {
$filesystem = Filesystem::getInstance();
$dirname = $filesystem->dirname($filename);
$basename = $filesystem->basename($filename);
$dirname = $locator->findResource($dirname, true) ?: $locator->findResource($dirname, true, true);
$filename = "{$dirname}/{$basename}";
}
$file = YamlFile::instance($filename);
if (!empty($data)) {
@@ -318,7 +332,7 @@ class FlexDirectory implements FlexDirectoryInterface
* @param array|null $keys Array of keys.
* @param string|null $keyField Field to be used as the key.
* @return FlexCollectionInterface
* @phpstan-return FlexCollectionInterface<T>
* @phpstan-return FlexCollectionInterface<FlexObjectInterface>
*/
public function getCollection(array $keys = null, string $keyField = null): FlexCollectionInterface
{
@@ -345,6 +359,7 @@ class FlexDirectory implements FlexDirectoryInterface
* @param array|null $keys Array of keys.
* @param string|null $keyField Field to be used as the key.
* @return FlexIndexInterface
* @phpstan-return FlexIndexInterface<FlexObjectInterface>
*/
public function getIndex(array $keys = null, string $keyField = null): FlexIndexInterface
{
@@ -353,7 +368,7 @@ class FlexDirectory implements FlexDirectoryInterface
$index = clone $index;
if (null !== $keys) {
/** @var FlexIndexInterface $index */
/** @var FlexIndexInterface<FlexObjectInterface> $index */
$index = $index->select($keys);
}
@@ -487,8 +502,11 @@ class FlexDirectory implements FlexDirectoryInterface
*/
public function createObject(array $data, string $key = '', bool $validate = false): FlexObjectInterface
{
/** @var string|FlexObjectInterface $className */
/** @phpstan-var class-string $className */
$className = $this->objectClassName ?: $this->getObjectClass();
if (!is_a($className, FlexObjectInterface::class, true)) {
throw new \RuntimeException('Bad object class: ' . $className);
}
return new $className($data, $key, $this, $validate);
}
@@ -497,11 +515,15 @@ class FlexDirectory implements FlexDirectoryInterface
* @param array $entries
* @param string|null $keyField
* @return FlexCollectionInterface
* @phpstan-return FlexCollectionInterface<FlexObjectInterface>
*/
public function createCollection(array $entries, string $keyField = null): FlexCollectionInterface
{
/** @var string|FlexCollectionInterface $className */
/** phpstan-var class-string $className */
$className = $this->collectionClassName ?: $this->getCollectionClass();
if (!is_a($className, FlexCollectionInterface::class, true)) {
throw new \RuntimeException('Bad collection class: ' . $className);
}
return $className::createFromArray($entries, $this, $keyField);
}
@@ -510,11 +532,15 @@ class FlexDirectory implements FlexDirectoryInterface
* @param array $entries
* @param string|null $keyField
* @return FlexIndexInterface
* @phpstan-return FlexIndexInterface<FlexObjectInterface>
*/
public function createIndex(array $entries, string $keyField = null): FlexIndexInterface
{
/** @var string|FlexIndexInterface $className */
/** @phpstan-var class-string $className */
$className = $this->indexClassName ?: $this->getIndexClass();
if (!is_a($className, FlexIndexInterface::class, true)) {
throw new \RuntimeException('Bad index class: ' . $className);
}
return $className::createFromArray($entries, $this, $keyField);
}
@@ -560,6 +586,7 @@ class FlexDirectory implements FlexDirectoryInterface
* @param array $entries
* @param string|null $keyField
* @return FlexCollectionInterface
* @phpstan-return FlexCollectionInterface<FlexObjectInterface>
*/
public function loadCollection(array $entries, string $keyField = null): FlexCollectionInterface
{
@@ -889,12 +916,17 @@ class FlexDirectory implements FlexDirectoryInterface
$className = $storage['class'] ?? SimpleStorage::class;
$options = $storage['options'] ?? [];
if (!is_a($className, FlexStorageInterface::class, true)) {
throw new \RuntimeException('Bad storage class: ' . $className);
}
return new $className($options);
}
/**
* @param string $keyField
* @return FlexIndexInterface
* @phpstan-return FlexIndexInterface<FlexObjectInterface>
*/
protected function loadIndex(string $keyField): FlexIndexInterface
{
@@ -924,7 +956,7 @@ class FlexDirectory implements FlexDirectoryInterface
}
if (!is_array($keys)) {
/** @var string|FlexIndexInterface $className */
/** @phpstan-var class-string $className */
$className = $this->getIndexClass();
$keys = $className::loadEntriesFromStorage($storage);
if (!$cache instanceof MemoryCache) {
@@ -946,7 +978,7 @@ class FlexDirectory implements FlexDirectoryInterface
// We need to do this in two steps as orderBy() calls loadIndex() again and we do not want infinite loop.
$this->indexes['storage_key'] = $index = $this->createIndex($keys, 'storage_key');
if ($ordering) {
/** @var FlexCollectionInterface $collection */
/** @var FlexCollectionInterface<FlexObjectInterface> $collection */
$collection = $this->indexes['storage_key']->orderBy($ordering);
$this->indexes['storage_key'] = $index = $collection->getIndex();
}
@@ -1035,7 +1067,9 @@ class FlexDirectory implements FlexDirectoryInterface
$newKey = $object->getStorageKey();
if ($oldKey !== $newKey) {
$object->triggerEvent('move');
if (method_exists($object, 'triggerEvent')) {
$object->triggerEvent('move');
}
$storage->renameRow($oldKey, $newKey);
// TODO: media support.
}

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Flex
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -358,6 +358,7 @@ class FlexDirectoryForm implements FlexDirectoryFormInterface, JsonSerializable
* @param string $name
* @return mixed|null
*/
#[\ReturnTypeWillChange]
public function __get($name)
{
$method = "get{$name}";
@@ -375,6 +376,7 @@ class FlexDirectoryForm implements FlexDirectoryFormInterface, JsonSerializable
* @param mixed $value
* @return void
*/
#[\ReturnTypeWillChange]
public function __set($name, $value)
{
$method = "set{$name}";
@@ -387,6 +389,7 @@ class FlexDirectoryForm implements FlexDirectoryFormInterface, JsonSerializable
* @param string $name
* @return bool
*/
#[\ReturnTypeWillChange]
public function __isset($name)
{
$method = "get{$name}";
@@ -403,6 +406,7 @@ class FlexDirectoryForm implements FlexDirectoryFormInterface, JsonSerializable
* @param string $name
* @return void
*/
#[\ReturnTypeWillChange]
public function __unset($name)
{
}
@@ -493,6 +497,7 @@ class FlexDirectoryForm implements FlexDirectoryFormInterface, JsonSerializable
* Filter validated data.
*
* @param ArrayAccess|Data|null $data
* @phpstan-param ArrayAccess<string,mixed>|Data|null $data
*/
protected function filterData($data = null): void
{

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Flex
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -444,6 +444,7 @@ class FlexForm implements FlexObjectFormInterface, JsonSerializable
* @param string $name
* @return mixed|null
*/
#[\ReturnTypeWillChange]
public function __get($name)
{
$method = "get{$name}";
@@ -461,6 +462,7 @@ class FlexForm implements FlexObjectFormInterface, JsonSerializable
* @param mixed $value
* @return void
*/
#[\ReturnTypeWillChange]
public function __set($name, $value)
{
$method = "set{$name}";
@@ -473,6 +475,7 @@ class FlexForm implements FlexObjectFormInterface, JsonSerializable
* @param string $name
* @return bool
*/
#[\ReturnTypeWillChange]
public function __isset($name)
{
$method = "get{$name}";
@@ -489,6 +492,7 @@ class FlexForm implements FlexObjectFormInterface, JsonSerializable
* @param string $name
* @return void
*/
#[\ReturnTypeWillChange]
public function __unset($name)
{
}
@@ -594,6 +598,7 @@ class FlexForm implements FlexObjectFormInterface, JsonSerializable
*
* @param ArrayAccess|Data|null $data
* @return void
* @phpstan-param ArrayAccess<string,mixed>|Data|null $data
*/
protected function filterData($data = null): void
{

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Flex
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Flex
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -11,6 +11,7 @@ namespace Grav\Framework\Flex;
use Exception;
use Grav\Common\Debugger;
use Grav\Common\File\CompiledJsonFile;
use Grav\Common\File\CompiledYamlFile;
use Grav\Common\Grav;
use Grav\Common\Inflector;
@@ -39,14 +40,14 @@ use function in_array;
* @implements FlexIndexInterface<T>
* @mixin C
*/
class FlexIndex extends ObjectIndex implements FlexCollectionInterface, FlexIndexInterface
class FlexIndex extends ObjectIndex implements FlexIndexInterface
{
const VERSION = 1;
/** @var FlexDirectory|null */
private $_flexDirectory;
/** @var string */
private $_keyField;
private $_keyField = 'storage_key';
/** @var array */
private $_indexKeys;
@@ -117,6 +118,14 @@ class FlexIndex extends ObjectIndex implements FlexCollectionInterface, FlexInde
$this->setKeyField(null);
}
/**
* @return string
*/
public function getKey()
{
return $this->_key ?: $this->getFlexType() . '@@' . spl_object_hash($this);
}
/**
* {@inheritdoc}
* @see FlexCommonInterface::hasFlexFeature()
@@ -132,6 +141,7 @@ class FlexIndex extends ObjectIndex implements FlexCollectionInterface, FlexInde
*/
public function getFlexFeatures(): array
{
/** @var array $implements */
$implements = class_implements($this->getFlexDirectory()->getCollectionClass());
$list = [];
@@ -164,7 +174,6 @@ class FlexIndex extends ObjectIndex implements FlexCollectionInterface, FlexInde
return $this->orderBy($orderings);
}
/**
* {@inheritdoc}
* @see FlexCollectionInterface::filterBy()
@@ -353,7 +362,7 @@ class FlexIndex extends ObjectIndex implements FlexCollectionInterface, FlexInde
*/
public function getKeyField(): string
{
return $this->_keyField ?? 'storage_key';
return $this->_keyField;
}
/**
@@ -416,7 +425,7 @@ class FlexIndex extends ObjectIndex implements FlexCollectionInterface, FlexInde
$previous = $search;
}
return $this->createFrom(array_replace($previous ?? [], $this->getEntries()) ?? []);
return $this->createFrom(array_replace($previous ?? [], $this->getEntries()));
}
/**
@@ -432,12 +441,13 @@ class FlexIndex extends ObjectIndex implements FlexCollectionInterface, FlexInde
* @param array $arguments
* @return mixed
*/
#[\ReturnTypeWillChange]
public function __call($name, $arguments)
{
/** @var Debugger $debugger */
$debugger = Grav::instance()['debugger'];
/** @var FlexCollection $className */
/** @phpstan-var class-string $className */
$className = $this->getFlexDirectory()->getCollectionClass();
$cachedMethods = $className::getCachedMethods();
@@ -492,9 +502,13 @@ class FlexIndex extends ObjectIndex implements FlexCollectionInterface, FlexInde
}
} else {
$collection = $this->loadCollection();
$result = $collection->{$name}(...$arguments);
if (!isset($cachedMethods[$name])) {
$debugger->addMessage("Call '{$flexType}:{$name}()' isn't cached", 'debug');
if (\is_callable([$collection, $name])) {
$result = $collection->{$name}(...$arguments);
if (!isset($cachedMethods[$name])) {
$debugger->addMessage("Call '{$flexType}:{$name}()' isn't cached", 'debug');
}
} else {
$result = null;
}
}
@@ -522,6 +536,7 @@ class FlexIndex extends ObjectIndex implements FlexCollectionInterface, FlexInde
/**
* @return array
*/
#[\ReturnTypeWillChange]
public function __debugInfo()
{
return [
@@ -607,9 +622,11 @@ class FlexIndex extends ObjectIndex implements FlexCollectionInterface, FlexInde
* @param string $key
* @param mixed $value
* @return ObjectInterface|null
* @phpstan-return T|null
*/
protected function loadElement($key, $value): ?ObjectInterface
{
/** @phpstan-var T[] $objects */
$objects = $this->getFlexDirectory()->loadObjects([$key => $value]);
return $objects ? reset($objects): null;
@@ -618,10 +635,14 @@ class FlexIndex extends ObjectIndex implements FlexCollectionInterface, FlexInde
/**
* @param array|null $entries
* @return ObjectInterface[]
* @phpstan-return T[]
*/
protected function loadElements(array $entries = null): array
{
return $this->getFlexDirectory()->loadObjects($entries ?? $this->getEntries());
/** @phpstan-var T[] $objects */
$objects = $this->getFlexDirectory()->loadObjects($entries ?? $this->getEntries());
return $objects;
}
/**
@@ -824,7 +845,7 @@ class FlexIndex extends ObjectIndex implements FlexCollectionInterface, FlexInde
/**
* @param FlexStorageInterface $storage
* @return CompiledYamlFile|null
* @return CompiledYamlFile|CompiledJsonFile|null
*/
protected static function getIndexFile(FlexStorageInterface $storage)
{

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Flex
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -69,13 +69,13 @@ class FlexObject implements FlexObjectInterface, FlexAuthorizeInterface
private $_forms = [];
/** @var Blueprint[] */
private $_blueprint = [];
/** @var array */
/** @var array|null */
private $_meta;
/** @var array */
/** @var array|null */
protected $_original;
/** @var string */
/** @var string|null */
protected $storage_key;
/** @var int */
/** @var int|null */
protected $storage_timestamp;
/**
@@ -163,6 +163,7 @@ class FlexObject implements FlexObjectInterface, FlexAuthorizeInterface
*/
public function getFlexFeatures(): array
{
/** @var array $implements */
$implements = class_implements($this);
$list = [];
@@ -656,6 +657,7 @@ class FlexObject implements FlexObjectInterface, FlexAuthorizeInterface
/**
* @return array
*/
#[\ReturnTypeWillChange]
public function jsonSerialize()
{
return $this->getElements();
@@ -775,7 +777,7 @@ class FlexObject implements FlexObjectInterface, FlexAuthorizeInterface
$value = reset($result);
$meta = $value['__META'] ?? null;
if ($meta) {
/** @var FlexIndex $indexClass */
/** @phpstan-var class-string $indexClass */
$indexClass = $this->getFlexDirectory()->getIndexClass();
$indexClass::updateObjectMeta($meta, $value, $storage);
$this->_meta = $meta;
@@ -887,8 +889,8 @@ class FlexObject implements FlexObjectInterface, FlexAuthorizeInterface
public function getDefaultValue(string $name, string $separator = null)
{
$separator = $separator ?: '.';
$path = explode($separator, $name) ?: [];
$offset = array_shift($path) ?? '';
$path = explode($separator, $name);
$offset = array_shift($path);
$current = $this->getDefaultValues();
@@ -950,6 +952,7 @@ class FlexObject implements FlexObjectInterface, FlexAuthorizeInterface
*
* @return string
*/
#[\ReturnTypeWillChange]
public function __toString()
{
return $this->getFlexKey();
@@ -958,6 +961,7 @@ class FlexObject implements FlexObjectInterface, FlexAuthorizeInterface
/**
* @return array
*/
#[\ReturnTypeWillChange]
public function __debugInfo()
{
return [
@@ -973,6 +977,7 @@ class FlexObject implements FlexObjectInterface, FlexAuthorizeInterface
/**
* Clone object.
*/
#[\ReturnTypeWillChange]
public function __clone()
{
// Allows future compatibility as parent::__clone() works.

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
/**
* @package Grav\Framework\Flex
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
/**
* @package Grav\Framework\Flex
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -140,5 +140,5 @@ interface FlexCollectionInterface extends FlexCommonInterface, ObjectCollectionI
* @param string $key Key.
* @return array
*/
public function getMetaData(string $key): array;
public function getMetaData($key): array;
}

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
/**
* @package Grav\Framework\Flex
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Flex
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Flex
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -105,6 +105,7 @@ interface FlexDirectoryInterface extends FlexAuthorizeInterface
* @param array|null $keys Array of keys.
* @param string|null $keyField Field to be used as the key.
* @return FlexCollectionInterface
* @phpstan-return FlexCollectionInterface<FlexObjectInterface>
*/
public function getCollection(array $keys = null, string $keyField = null): FlexCollectionInterface;
@@ -116,6 +117,7 @@ interface FlexDirectoryInterface extends FlexAuthorizeInterface
* @param array|null $keys Array of keys.
* @param string|null $keyField Field to be used as the key.
* @return FlexIndexInterface
* @phpstan-return FlexIndexInterface<FlexObjectInterface>
*/
public function getIndex(array $keys = null, string $keyField = null): FlexIndexInterface;
@@ -170,6 +172,7 @@ interface FlexDirectoryInterface extends FlexAuthorizeInterface
* @param array $entries
* @param string|null $keyField
* @return FlexCollectionInterface
* @phpstan-return FlexCollectionInterface<FlexObjectInterface>
*/
public function createCollection(array $entries, string $keyField = null): FlexCollectionInterface;
@@ -177,6 +180,7 @@ interface FlexDirectoryInterface extends FlexAuthorizeInterface
* @param array $entries
* @param string|null $keyField
* @return FlexIndexInterface
* @phpstan-return FlexIndexInterface<FlexObjectInterface>
*/
public function createIndex(array $entries, string $keyField = null): FlexIndexInterface;
@@ -199,6 +203,7 @@ interface FlexDirectoryInterface extends FlexAuthorizeInterface
* @param array $entries
* @param string|null $keyField
* @return FlexCollectionInterface
* @phpstan-return FlexCollectionInterface<FlexObjectInterface>
*/
public function loadCollection(array $entries, string $keyField = null): FlexCollectionInterface;

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Flex
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -43,4 +43,9 @@ interface FlexFormInterface extends Serializable, FormInterface
* @return Route|null Returns Route object or null if file uploads are not enabled.
*/
public function getFileDeleteAjaxRoute($field, $filename);
// /**
// * @return FlexObjectInterface
// */
// public function getObject();
}

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
/**
* @package Grav\Framework\Flex
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
/**
* @package Grav\Framework\Flex
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -59,6 +59,7 @@ interface FlexInterface extends Countable
* @param array|null $keys
* @param string|null $keyField
* @return FlexCollectionInterface|null
* @phpstan-return FlexCollectionInterface<FlexObjectInterface>|null
*/
public function getCollection(string $type, array $keys = null, string $keyField = null): ?FlexCollectionInterface;
@@ -68,6 +69,7 @@ interface FlexInterface extends Countable
* collection_class: Class to be used to create the collection. Defaults to ObjectCollection.
* @return FlexCollectionInterface
* @throws RuntimeException
* @phpstan-return FlexCollectionInterface<FlexObjectInterface>
*/
public function getMixedCollection(array $keys, array $options = []): FlexCollectionInterface;

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Flex
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
/**
* @package Grav\Framework\Flex
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -23,6 +23,7 @@ use RuntimeException;
/**
* Defines Flex Objects.
*
* @extends ArrayAccess<string,mixed>
* @used-by \Grav\Framework\Flex\FlexObject
* @since 1.6
*/

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
/**
* @package Grav\Framework\Flex
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
/**
* @package Grav\Framework\Flex
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
/**
* @package Grav\Framework\Flex
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -13,6 +13,7 @@ namespace Grav\Framework\Flex\Pages;
use Grav\Common\Page\Interfaces\PageInterface;
use Grav\Framework\Flex\FlexCollection;
use Grav\Framework\Flex\Interfaces\FlexObjectInterface;
use function array_search;
use function assert;
use function is_int;
@@ -20,7 +21,7 @@ use function is_int;
/**
* Class FlexPageCollection
* @package Grav\Plugin\FlexObjects\Types\FlexPages
* @template T of \Grav\Framework\Flex\Interfaces\FlexObjectInterface
* @template T of FlexObjectInterface
* @extends FlexCollection<T>
*/
class FlexPageCollection extends FlexCollection
@@ -56,8 +57,10 @@ class FlexPageCollection extends FlexCollection
*/
public function withPublished(bool $bool = true)
{
/** @var string[] $list */
$list = array_keys(array_filter($this->call('isPublished', [$bool])));
/** @phpstan-var static<T> */
return $this->select($list);
}
@@ -68,8 +71,10 @@ class FlexPageCollection extends FlexCollection
*/
public function withVisible(bool $bool = true)
{
/** @var string[] $list */
$list = array_keys(array_filter($this->call('isVisible', [$bool])));
/** @phpstan-var static<T> */
return $this->select($list);
}
@@ -80,8 +85,10 @@ class FlexPageCollection extends FlexCollection
*/
public function withRoutable(bool $bool = true)
{
/** @var string[] $list */
$list = array_keys(array_filter($this->call('isRoutable', [$bool])));
/** @phpstan-var static<T> */
return $this->select($list);
}
@@ -148,9 +155,10 @@ class FlexPageCollection extends FlexCollection
public function adjacentSibling($path, $direction = 1)
{
$keys = $this->getKeys();
$direction = (int)$direction;
$pos = array_search($path, $keys, true);
if ($pos !== false) {
if (is_int($pos)) {
$pos += $direction;
if (isset($keys[$pos])) {
return $this[$keys[$pos]];
@@ -170,7 +178,7 @@ class FlexPageCollection extends FlexCollection
{
$pos = array_search($path, $this->getKeys(), true);
return $pos !== false ? $pos : null;
return is_int($pos) ? $pos : null;
}
/**
@@ -184,7 +192,6 @@ class FlexPageCollection extends FlexCollection
$keys = $collection->getStorageKeys();
// Assign next free order.
/** @var FlexPageObject|null $last */
$last = null;
$order = 0;
foreach ($keys as $folder => $key) {
@@ -196,8 +203,9 @@ class FlexPageCollection extends FlexCollection
}
}
/** @var FlexPageObject|null $last */
$last = $collection[$last];
return sprintf('%d.', $last ? $last->value('order') + 1 : 1);
return sprintf('%d.', $last ? $last->getFormValue('order') + 1 : 1);
}
}

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
/**
* @package Grav\Framework\Flex
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Flex
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -55,6 +55,7 @@ class FlexPageObject extends FlexObject implements PageInterface, FlexTranslateI
/**
* Clone page.
*/
#[\ReturnTypeWillChange]
public function __clone()
{
parent::__clone();

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
/**
* @package Grav\Framework\Flex
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Flex
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -75,13 +75,13 @@ trait PageContentTrait
'template' => 'template',
];
/** @var object */
/** @var object|null */
protected $header;
/** @var string */
/** @var string|null */
protected $_summary;
/** @var string */
/** @var string|null */
protected $_content;
/**
@@ -100,6 +100,7 @@ trait PageContentTrait
/**
* @inheritdoc
* @return Header
*/
public function header($var = null)
{
@@ -288,7 +289,7 @@ trait PageContentTrait
'process',
$var,
function ($value) {
$value = array_replace(Grav::instance()['config']->get('system.pages.process', []), is_array($value) ? $value : []) ?? [];
$value = array_replace(Grav::instance()['config']->get('system.pages.process', []), is_array($value) ? $value : []);
foreach ($value as $process => $status) {
$value[$process] = (bool)$status;
}
@@ -664,6 +665,7 @@ trait PageContentTrait
*/
protected function processContent($content): string
{
$content = is_string($content) ? $content : '';
$grav = Grav::instance();
/** @var Config $config */
@@ -676,7 +678,6 @@ trait PageContentTrait
$twig_first = $this->getNestedProperty('header.twig_first') ?? $config->get('system.pages.twig_first', false);
$never_cache_twig = $this->getNestedProperty('header.never_cache_twig') ?? $config->get('system.pages.never_cache_twig', false);
$cached = null;
if ($cache_enable) {
$cache = $this->getCache('render');
$key = md5($this->getCacheKey() . '-content');
@@ -688,12 +689,10 @@ trait PageContentTrait
if ($process_twig && $never_cache_twig) {
$this->_content = $this->processTwig($this->_content);
}
} else {
$cached = null;
}
}
if (!$cached) {
if (null === $this->_content) {
$markdown_options = [];
if ($process_markdown) {
// Build markdown options.
@@ -746,6 +745,7 @@ trait PageContentTrait
}
if ($process_twig) {
\assert(is_string($this->_content));
$this->_content = $this->processTwig($this->_content);
}
}
@@ -755,6 +755,8 @@ trait PageContentTrait
}
}
\assert(is_string($this->_content));
// Handle summary divider
$delimiter = $config->get('site.summary.delimiter', '===');
$divider_pos = mb_strpos($this->_content, "<p>{$delimiter}</p>");

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Flex
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -17,13 +17,12 @@ use Grav\Common\Page\Interfaces\PageInterface;
use Grav\Common\Page\Pages;
use Grav\Common\Utils;
use Grav\Common\Yaml;
use Grav\Framework\Cache\CacheInterface;
use Grav\Framework\File\Formatter\MarkdownFormatter;
use Grav\Framework\File\Formatter\YamlFormatter;
use Grav\Framework\Filesystem\Filesystem;
use Grav\Framework\Flex\FlexDirectory;
use Grav\Framework\Flex\Interfaces\FlexCollectionInterface;
use Grav\Framework\Flex\Interfaces\FlexIndexInterface;
use Grav\Framework\Flex\Pages\FlexPageCollection;
use Grav\Framework\Flex\Pages\FlexPageIndex;
use Grav\Framework\Flex\Pages\FlexPageObject;
use InvalidArgumentException;
@@ -300,7 +299,7 @@ trait PageLegacyTrait
$parentStorageKey = ltrim($filesystem->dirname("/{$this->getMasterKey()}"), '/');
/** @var FlexPageIndex $index */
/** @var FlexPageIndex<FlexPageObject,FlexPageCollection<FlexPageObject>> $index */
$index = $this->getFlexDirectory()->getIndex();
if ($parent) {
@@ -323,8 +322,9 @@ trait PageLegacyTrait
if ($this instanceof FlexPageObject) {
$key = trim($parentKey . '/' . $this->folder(), '/');
$key = preg_replace(static::PAGE_ORDER_PREFIX_REGEX, '', $key);
\assert(is_string($key));
} else {
$key = trim($parentKey . '/' . basename($this->getKey()), '/');
$key = trim($parentKey . '/' . Utils::basename($this->getKey()), '/');
}
if ($index->containsKey($key)) {
@@ -336,7 +336,7 @@ trait PageLegacyTrait
} while ($index->containsKey($test));
$key = $test;
}
$folder = basename($key);
$folder = Utils::basename($key);
// Get the folder name.
$order = $this->getProperty('order');
@@ -539,7 +539,7 @@ trait PageLegacyTrait
if ($language) {
$language = '.' . $language;
}
$format = '.' . ($this->getProperty('format') ?? pathinfo($this->name(), PATHINFO_EXTENSION));
$format = '.' . ($this->getProperty('format') ?? Utils::pathinfo($this->name(), PATHINFO_EXTENSION));
return $language . $format;
}

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Flex
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -15,10 +15,10 @@ use Grav\Common\Page\Interfaces\PageCollectionInterface;
use Grav\Common\Page\Interfaces\PageInterface;
use Grav\Common\Page\Pages;
use Grav\Common\Uri;
use Grav\Common\Utils;
use Grav\Framework\Filesystem\Filesystem;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
use RuntimeException;
use function dirname;
use function is_string;
/**
@@ -375,7 +375,7 @@ trait PageRoutableTrait
$value = $this->getMasterKey() ?: $this->getKey();
}
return basename($value) ?: null;
return Utils::basename($value) ?: null;
}
);
}

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Flex
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -26,6 +26,14 @@ trait PageTranslateTrait
/** @var PageInterface[] */
private $_translations = [];
/**
* @return bool
*/
public function translated(): bool
{
return (bool)$this->translatedLanguages(true);
}
/**
* @param string|null $languageCode
* @param bool|null $fallback

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
/**
* @package Grav\Framework\Flex
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -127,6 +127,10 @@ abstract class AbstractFilesystemStorage implements FlexStorageInterface
$formatterClassName = $formatter['class'] ?? JsonFormatter::class;
$formatterOptions = $formatter['options'] ?? [];
if (!is_a($formatterClassName, FileFormatterInterface::class, true)) {
throw new \InvalidArgumentException('Bad Data Formatter');
}
$this->dataFormatter = new $formatterClassName($formatterOptions);
}

View File

@@ -5,13 +5,14 @@ declare(strict_types=1);
/**
* @package Grav\Framework\Flex
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
namespace Grav\Framework\Flex\Storage;
use FilesystemIterator;
use Grav\Common\Utils;
use Grav\Framework\Flex\Interfaces\FlexStorageInterface;
use RuntimeException;
use SplFileInfo;
@@ -125,7 +126,7 @@ class FileStorage extends FolderStorage
*/
protected function getKeyFromPath(string $path): string
{
return basename($path, $this->dataFormatter->getDefaultFileExtension());
return Utils::basename($path, $this->dataFormatter->getDefaultFileExtension());
}
/**

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
/**
* @package Grav\Framework\Flex
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -352,7 +352,7 @@ class FolderStorage extends AbstractFilesystemStorage
*/
protected function getKeyFromPath(string $path): string
{
return basename($path);
return Utils::basename($path);
}
/**
@@ -688,7 +688,7 @@ class FolderStorage extends AbstractFilesystemStorage
$pattern .= '/{FILE}{EXT}';
} else {
$filesystem = Filesystem::getInstance(true);
$this->dataFile = basename($pattern, $extension);
$this->dataFile = Utils::basename($pattern, $extension);
$pattern = $filesystem->dirname($pattern) . '/{FILE}{EXT}';
}
}

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
/**
* @package Grav\Framework\Flex
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -13,6 +13,7 @@ namespace Grav\Framework\Flex\Storage;
use Grav\Common\Data\Data;
use Grav\Common\Filesystem\Folder;
use Grav\Common\Utils;
use Grav\Framework\Filesystem\Filesystem;
use InvalidArgumentException;
use LogicException;
@@ -30,7 +31,7 @@ class SimpleStorage extends AbstractFilesystemStorage
protected $dataFolder;
/** @var string */
protected $dataPattern;
/** @var string */
/** @var string|null */
protected $prefix;
/** @var array|null */
protected $data;
@@ -53,9 +54,9 @@ class SimpleStorage extends AbstractFilesystemStorage
$filesystem = Filesystem::getInstance(true);
$extension = $this->dataFormatter->getDefaultFileExtension();
$pattern = basename($options['folder']);
$pattern = Utils::basename($options['folder']);
$this->dataPattern = basename($pattern, $extension) . $extension;
$this->dataPattern = Utils::basename($pattern, $extension) . $extension;
$this->dataFolder = $filesystem->dirname($options['folder']);
$this->keyField = $options['key'] ?? 'storage_key';
$this->keyLen = (int)($options['key_len'] ?? 32);
@@ -432,7 +433,7 @@ class SimpleStorage extends AbstractFilesystemStorage
*/
protected function getKeyFromPath(string $path): string
{
return basename($path);
return Utils::basename($path);
}
/**

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
/**
* @package Grav\Framework\Flex
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -5,7 +5,7 @@ namespace Grav\Framework\Flex\Traits;
/**
* @package Grav\Framework\Flex
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -44,7 +44,7 @@ trait FlexMediaTrait
}
/** @var array */
protected $_uploads;
protected $_uploads = [];
/**
* @return string|null
@@ -119,7 +119,7 @@ trait FlexMediaTrait
// Load settings for the field.
$schema = $this->getBlueprint()->schema();
$settings = $field && is_object($schema) ? (array)$schema->getProperty($field) : null;
$settings = (array)$schema->getProperty($field);
if (!is_array($settings)) {
return null;
}
@@ -165,6 +165,9 @@ trait FlexMediaTrait
return $settings + ['accept' => '*', 'limit' => 1000, 'self' => true];
}
/**
* @return array
*/
protected function getMediaFields(): array
{
// Load settings for the field.
@@ -286,6 +289,7 @@ trait FlexMediaTrait
/**
* @return array
*/
#[\ReturnTypeWillChange]
public function __debugInfo()
{
return parent::__debugInfo() + [
@@ -342,7 +346,7 @@ trait FlexMediaTrait
}
// Calculate path without the retina scaling factor.
$realpath = $filesystem->pathname($filepath) . str_replace(['@3x', '@2x'], '', basename($filepath));
$realpath = $filesystem->pathname($filepath) . str_replace(['@3x', '@2x'], '', Utils::basename($filepath));
$list[$filename] = [$file, $settings];
@@ -397,11 +401,11 @@ trait FlexMediaTrait
}
/**
* @return array<string, UploadedFileInterface|array|null>
* @return array<string,UploadedFileInterface|array|null>
*/
protected function getUpdatedMedia(): array
{
return $this->_uploads ?? [];
return $this->_uploads;
}
/**
@@ -504,7 +508,7 @@ trait FlexMediaTrait
user_error(__METHOD__ . '() is deprecated since Grav 1.7, use Media class that implements MediaUploadInterface instead', E_USER_DEPRECATED);
// Check the file extension.
$extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
$extension = strtolower(Utils::pathinfo($filename, PATHINFO_EXTENSION));
$grav = Grav::instance();

View File

@@ -5,15 +5,15 @@ declare(strict_types=1);
/**
* @package Grav\Common\Flex
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
namespace Grav\Framework\Flex\Traits;
use Grav\Framework\Flex\FlexCollection;
use Grav\Framework\Flex\FlexDirectory;
use Grav\Framework\Flex\Interfaces\FlexCollectionInterface;
use Grav\Framework\Flex\Interfaces\FlexObjectInterface;
use RuntimeException;
use function in_array;
@@ -26,7 +26,7 @@ trait FlexRelatedDirectoryTrait
/**
* @param string $type
* @param string $property
* @return FlexCollectionInterface
* @return FlexCollectionInterface<FlexObjectInterface>
*/
protected function getCollectionByProperty($type, $property)
{
@@ -34,9 +34,9 @@ trait FlexRelatedDirectoryTrait
$collection = $directory->getCollection();
$list = $this->getNestedProperty($property) ?: [];
/** @var FlexCollection $collection */
/** @var FlexCollectionInterface<FlexObjectInterface> $collection */
$collection = $collection->filter(static function ($object) use ($list) {
return in_array($object->id, $list, true);
return in_array($object->getKey(), $list, true);
});
return $collection;

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Form
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -343,7 +343,7 @@ class FormFlash implements FormFlashInterface
// Prepare upload data for later save
$data = [
'name' => basename($filename),
'name' => Utils::basename($filename),
'type' => Utils::getMimeByLocalFile($filename),
'size' => filesize($filename),
];

View File

@@ -3,14 +3,17 @@
/**
* @package Grav\Framework\Form
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
namespace Grav\Framework\Form;
use Grav\Common\Security;
use Grav\Common\Utils;
use Grav\Framework\Psr7\Stream;
use InvalidArgumentException;
use JsonSerializable;
use Psr\Http\Message\StreamInterface;
use Psr\Http\Message\UploadedFileInterface;
use RuntimeException;
@@ -23,7 +26,7 @@ use function sprintf;
* Class FormFlashFile
* @package Grav\Framework\Form
*/
class FormFlashFile implements UploadedFileInterface, \JsonSerializable
class FormFlashFile implements UploadedFileInterface, JsonSerializable
{
/** @var string */
private $field;
@@ -175,11 +178,27 @@ class FormFlashFile implements UploadedFileInterface, \JsonSerializable
/**
* @return array
*/
#[\ReturnTypeWillChange]
public function jsonSerialize()
{
return $this->upload;
}
/**
* @return void
*/
public function checkXss(): void
{
$tmpFile = $this->getTmpFile();
$mime = $this->getClientMediaType();
if (Utils::contains($mime, 'svg', false)) {
$response = Security::detectXssFromSvgFile($tmpFile);
if ($response) {
throw new RuntimeException(sprintf('SVG file XSS check failed on %s', $response));
}
}
}
/**
* @return string|null
*/
@@ -199,6 +218,7 @@ class FormFlashFile implements UploadedFileInterface, \JsonSerializable
/**
* @return array
*/
#[\ReturnTypeWillChange]
public function __debugInfo()
{
return [

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
/**
* @package Grav\Framework\Form
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Form
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Form
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Form
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -23,6 +23,7 @@ use Grav\Common\User\Interfaces\UserInterface;
use Grav\Common\Utils;
use Grav\Framework\Compat\Serializable;
use Grav\Framework\ContentBlock\HtmlBlock;
use Grav\Framework\Form\FormFlashFile;
use Grav\Framework\Form\Interfaces\FormFlashInterface;
use Grav\Framework\Form\Interfaces\FormInterface;
use Grav\Framework\Session\SessionInterface;
@@ -65,10 +66,10 @@ trait FormTrait
private $sessionid;
/** @var bool */
private $submitted;
/** @var ArrayAccess|Data|null */
/** @var ArrayAccess<string,mixed>|Data|null */
private $data;
/** @var array|UploadedFileInterface[] */
private $files;
/** @var UploadedFileInterface[] */
private $files = [];
/** @var FormFlashInterface|null */
private $flash;
/** @var string */
@@ -203,7 +204,7 @@ trait FormTrait
*/
public function getFiles(): array
{
return $this->files ?? [];
return $this->files;
}
/**
@@ -221,8 +222,8 @@ trait FormTrait
*/
public function getDefaultValue(string $name)
{
$path = explode('.', $name) ?: [];
$offset = array_shift($path) ?? '';
$path = explode('.', $name);
$offset = array_shift($path);
$current = $this->getDefaultValues();
@@ -692,7 +693,7 @@ trait FormTrait
throw new RuntimeException(sprintf('FlexForm: Bad HTTP method %s', $method));
}
$body = $request->getParsedBody();
$body = (array)$request->getParsedBody();
$data = isset($body['data']) ? $this->decodeData($body['data']) : null;
$flash = $this->getFlash();
@@ -721,6 +722,7 @@ trait FormTrait
* @param ArrayAccess|Data|null $data
* @return void
* @throws ValidationException
* @phpstan-param ArrayAccess<string,mixed>|Data|null $data
* @throws Exception
*/
protected function validateData($data = null): void
@@ -735,6 +737,7 @@ trait FormTrait
*
* @param ArrayAccess|Data|null $data
* @return void
* @phpstan-param ArrayAccess<string,mixed>|Data|null $data
*/
protected function filterData($data = null): void
{
@@ -773,13 +776,16 @@ trait FormTrait
{
// Handle bad filenames.
$filename = $file->getClientFilename();
if ($filename && !Utils::checkFilename($filename)) {
$grav = Grav::instance();
throw new RuntimeException(
sprintf($grav['language']->translate('PLUGIN_FORM.FILEUPLOAD_UNABLE_TO_UPLOAD', null, true), $filename, 'Bad filename')
);
}
if ($file instanceof FormFlashFile) {
$file->checkXss();
}
}
/**
@@ -797,9 +803,7 @@ trait FormTrait
// Decode JSON encoded fields and merge them to data.
if (isset($data['_json'])) {
$data = array_replace_recursive($data, $this->jsonDecode($data['_json']));
if (null === $data) {
throw new RuntimeException(__METHOD__ . '(): Unexpected error');
}
unset($data['_json']);
}

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
/**
* @package Grav\Framework\Interfaces
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Logger
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,15 +3,21 @@
/**
* @package Grav\Framework\Media
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
namespace Grav\Framework\Media\Interfaces;
use ArrayAccess;
use Countable;
use Iterator;
/**
* Class implements media collection interface.
* @extends ArrayAccess<string,MediaObjectInterface>
* @extends Iterator<string,MediaObjectInterface>
*/
interface MediaCollectionInterface extends \ArrayAccess, \Countable, \Iterator
interface MediaCollectionInterface extends ArrayAccess, Countable, Iterator
{
}

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Media
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
/**
* @package Grav\Framework\Media
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Media
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Mime
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Object
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Object
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Object
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Framework\Object
*
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -42,8 +42,8 @@ trait NestedPropertyTrait
public function getNestedProperty($property, $default = null, $separator = null)
{
$separator = $separator ?: '.';
$path = explode($separator, $property) ?: [];
$offset = array_shift($path) ?? '';
$path = explode($separator, $property);
$offset = array_shift($path);
if (!$this->hasProperty($offset)) {
return $default;
@@ -85,8 +85,8 @@ trait NestedPropertyTrait
public function setNestedProperty($property, $value, $separator = null)
{
$separator = $separator ?: '.';
$path = explode($separator, $property) ?: [];
$offset = array_shift($path) ?? '';
$path = explode($separator, $property);
$offset = array_shift($path);
if (!$path) {
$this->setProperty($offset, $value);
@@ -127,8 +127,8 @@ trait NestedPropertyTrait
public function unsetNestedProperty($property, $separator = null)
{
$separator = $separator ?: '.';
$path = explode($separator, $property) ?: [];
$offset = array_shift($path) ?? '';
$path = explode($separator, $property);
$offset = array_shift($path);
if (!$path) {
$this->unsetProperty($offset);

Some files were not shown because too many files have changed in this diff Show More