Upgrade to 3.2.0
This commit is contained in:
@@ -11,12 +11,19 @@ use Kirby\Http\Router;
|
||||
use Kirby\Http\Response;
|
||||
use Kirby\Toolkit\F;
|
||||
use Kirby\Toolkit\Properties;
|
||||
use Kirby\Toolkit\Str;
|
||||
|
||||
/**
|
||||
* The API class is a generic container
|
||||
* for API routes, models and collections and is used
|
||||
* to run our REST API. You can find our API setup
|
||||
* in kirby/config/api.php
|
||||
* in `kirby/config/api.php`.
|
||||
*
|
||||
* @package Kirby Api
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class Api
|
||||
{
|
||||
@@ -179,7 +186,9 @@ class Api
|
||||
*
|
||||
* @param string $name
|
||||
* @param array|null $collection
|
||||
* @return Collection
|
||||
* @return Kirby\Api\Collection
|
||||
*
|
||||
* @throws NotFoundException If no collection for `$name` exists
|
||||
*/
|
||||
public function collection(string $name, $collection = null)
|
||||
{
|
||||
@@ -207,6 +216,8 @@ class Api
|
||||
* @param string|null $key
|
||||
* @param mixed ...$args
|
||||
* @return mixed
|
||||
*
|
||||
* @throws NotFoundException If no data for `$key` exists
|
||||
*/
|
||||
public function data($key = null, ...$args)
|
||||
{
|
||||
@@ -252,7 +263,9 @@ class Api
|
||||
*
|
||||
* @param string $name
|
||||
* @param mixed $object
|
||||
* @return Model
|
||||
* @return Kirby\Api\Model
|
||||
*
|
||||
* @throws NotFoundException If no model for `$name` exists
|
||||
*/
|
||||
public function model(string $name, $object = null)
|
||||
{
|
||||
@@ -362,7 +375,9 @@ class Api
|
||||
* API model or collection representation
|
||||
*
|
||||
* @param mixed $object
|
||||
* @return Model|Collection
|
||||
* @return Kirby\Api\Model|Kirby\Api\Collection
|
||||
*
|
||||
* @throws NotFoundException If `$object` cannot be resolved
|
||||
*/
|
||||
public function resolve($object)
|
||||
{
|
||||
@@ -531,11 +546,17 @@ class Api
|
||||
'route' => $this->route->pattern()
|
||||
] + $e->toArray();
|
||||
} else {
|
||||
// remove the document root from the file path
|
||||
$file = $e->getFile();
|
||||
if (empty($_SERVER['DOCUMENT_ROOT']) === false) {
|
||||
$file = ltrim(Str::after($file, $_SERVER['DOCUMENT_ROOT']), '/');
|
||||
}
|
||||
|
||||
$result = [
|
||||
'status' => 'error',
|
||||
'exception' => get_class($e),
|
||||
'message' => $e->getMessage(),
|
||||
'file' => ltrim($e->getFile(), $_SERVER['DOCUMENT_ROOT'] ?? null),
|
||||
'file' => $file,
|
||||
'line' => $e->getLine(),
|
||||
'code' => empty($e->getCode()) === false ? $e->getCode() : 500,
|
||||
'route' => $this->route ? $this->route->pattern() : null
|
||||
@@ -578,7 +599,8 @@ class Api
|
||||
unset(
|
||||
$result['file'],
|
||||
$result['exception'],
|
||||
$result['line']
|
||||
$result['line'],
|
||||
$result['route']
|
||||
);
|
||||
}
|
||||
|
||||
@@ -602,6 +624,9 @@ class Api
|
||||
* @param Closure $callback
|
||||
* @param boolean $single
|
||||
* @return array
|
||||
*
|
||||
* @throws Exception If request has no files
|
||||
* @throws Exception If there was an error with the upload
|
||||
*/
|
||||
public function upload(Closure $callback, $single = false): array
|
||||
{
|
||||
|
@@ -2,7 +2,6 @@
|
||||
|
||||
namespace Kirby\Api;
|
||||
|
||||
use Closure;
|
||||
use Exception;
|
||||
use Kirby\Toolkit\Str;
|
||||
|
||||
@@ -11,6 +10,12 @@ use Kirby\Toolkit\Str;
|
||||
* around our Kirby Collections and handles
|
||||
* stuff like pagination and proper JSON output
|
||||
* for collections in REST calls.
|
||||
*
|
||||
* @package Kirby Api
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class Collection
|
||||
{
|
||||
|
@@ -2,7 +2,6 @@
|
||||
|
||||
namespace Kirby\Api;
|
||||
|
||||
use Closure;
|
||||
use Exception;
|
||||
|
||||
use Kirby\Toolkit\Str;
|
||||
@@ -15,6 +14,11 @@ use Kirby\Toolkit\Str;
|
||||
* by GraphQLs architecture and makes it possible to load
|
||||
* only the model data that is needed for the current API call.
|
||||
*
|
||||
* @package Kirby Api
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class Model
|
||||
{
|
||||
|
@@ -9,17 +9,17 @@ use APCUIterator;
|
||||
*
|
||||
* @package Kirby Cache
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link http://getkirby.com
|
||||
* @copyright Bastian Allgeier
|
||||
* @license MIT
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://opensource.org/licenses/MIT
|
||||
*/
|
||||
class ApcuCache extends Cache
|
||||
{
|
||||
|
||||
/**
|
||||
* Checks if the current key exists in cache
|
||||
* Determines if an item exists in the cache
|
||||
*
|
||||
* @param string $key
|
||||
* @param string $key
|
||||
* @return boolean
|
||||
*/
|
||||
public function exists(string $key): bool
|
||||
@@ -28,7 +28,8 @@ class ApcuCache extends Cache
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush the entire cache directory
|
||||
* Flushes the entire cache and returns
|
||||
* whether the operation was successful
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
@@ -42,9 +43,10 @@ class ApcuCache extends Cache
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an item from the cache
|
||||
* Removes an item from the cache and returns
|
||||
* whether the operation was successful
|
||||
*
|
||||
* @param string $key
|
||||
* @param string $key
|
||||
* @return boolean
|
||||
*/
|
||||
public function remove(string $key): bool
|
||||
@@ -53,10 +55,11 @@ class ApcuCache extends Cache
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an item from the cache.
|
||||
* Internal method to retrieve the raw cache value;
|
||||
* needs to return a Value object or null if not found
|
||||
*
|
||||
* @param string $key
|
||||
* @return mixed
|
||||
* @param string $key
|
||||
* @return Kirby\Cache\Value|null
|
||||
*/
|
||||
public function retrieve(string $key)
|
||||
{
|
||||
@@ -64,20 +67,21 @@ class ApcuCache extends Cache
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an item to the cache for a given number of minutes.
|
||||
* Writes an item to the cache for a given number of minutes and
|
||||
* returns whether the operation was successful
|
||||
*
|
||||
* <code>
|
||||
* // Put an item in the cache for 15 minutes
|
||||
* Cache::set('value', 'my value', 15);
|
||||
* // put an item in the cache for 15 minutes
|
||||
* $cache->set('value', 'my value', 15);
|
||||
* </code>
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @param int $minutes
|
||||
* @return void
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @param int $minutes
|
||||
* @return boolean
|
||||
*/
|
||||
public function set(string $key, $value, int $minutes = 0)
|
||||
public function set(string $key, $value, int $minutes = 0): bool
|
||||
{
|
||||
return apcu_store($this->key($key), $this->value($value, $minutes)->toJson(), $this->expiration($minutes));
|
||||
return apcu_store($this->key($key), (new Value($value, $minutes))->toJson(), $this->expiration($minutes));
|
||||
}
|
||||
}
|
||||
|
@@ -4,28 +4,27 @@ namespace Kirby\Cache;
|
||||
|
||||
/**
|
||||
* Cache foundation
|
||||
* This class doesn't do anything
|
||||
* and is perfect as foundation for
|
||||
* other cache drivers and to be used
|
||||
* when the cache is disabled
|
||||
* This abstract class is used as
|
||||
* foundation for other cache drivers
|
||||
* by extending it
|
||||
*
|
||||
* @package Kirby Cache
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link http://getkirby.com
|
||||
* @copyright Bastian Allgeier
|
||||
* @license MIT
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://opensource.org/licenses/MIT
|
||||
*/
|
||||
class Cache
|
||||
abstract class Cache
|
||||
{
|
||||
|
||||
/**
|
||||
* stores all options for the driver
|
||||
* Stores all options for the driver
|
||||
* @var array
|
||||
*/
|
||||
protected $options = [];
|
||||
|
||||
/**
|
||||
* Set all parameters which are needed to connect to the cache storage
|
||||
* Sets all parameters which are needed to connect to the cache storage
|
||||
*
|
||||
* @param array $options
|
||||
*/
|
||||
@@ -35,27 +34,26 @@ class Cache
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an item to the cache for a given number of minutes.
|
||||
* Writes an item to the cache for a given number of minutes and
|
||||
* returns whether the operation was successful;
|
||||
* this needs to be defined by the driver
|
||||
*
|
||||
* <code>
|
||||
* // Put an item in the cache for 15 minutes
|
||||
* Cache::set('value', 'my value', 15);
|
||||
* // put an item in the cache for 15 minutes
|
||||
* $cache->set('value', 'my value', 15);
|
||||
* </code>
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @param int $minutes
|
||||
* @return void
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @param int $minutes
|
||||
* @return boolean
|
||||
*/
|
||||
public function set(string $key, $value, int $minutes = 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
abstract public function set(string $key, $value, int $minutes = 0): bool;
|
||||
|
||||
/**
|
||||
* Adds the prefix to the key if given
|
||||
*
|
||||
* @param string $key
|
||||
* @param string $key
|
||||
* @return string
|
||||
*/
|
||||
protected function key(string $key): string
|
||||
@@ -68,30 +66,28 @@ class Cache
|
||||
}
|
||||
|
||||
/**
|
||||
* Private method to retrieve the cache value
|
||||
* This needs to be defined by the driver
|
||||
* Internal method to retrieve the raw cache value;
|
||||
* needs to return a Value object or null if not found;
|
||||
* this needs to be defined by the driver
|
||||
*
|
||||
* @param string $key
|
||||
* @return mixed
|
||||
* @param string $key
|
||||
* @return Kirby\Cache\Value|null
|
||||
*/
|
||||
public function retrieve(string $key)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
abstract public function retrieve(string $key);
|
||||
|
||||
/**
|
||||
* Get an item from the cache.
|
||||
* Gets an item from the cache
|
||||
*
|
||||
* <code>
|
||||
* // Get an item from the cache driver
|
||||
* $value = Cache::get('value');
|
||||
* // get an item from the cache driver
|
||||
* $value = $cache->get('value');
|
||||
*
|
||||
* // Return a default value if the requested item isn't cached
|
||||
* $value = Cache::get('value', 'default value');
|
||||
* // return a default value if the requested item isn't cached
|
||||
* $value = $cache->get('value', 'default value');
|
||||
* </code>
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $default
|
||||
* @param string $key
|
||||
* @param mixed $default
|
||||
* @return mixed
|
||||
*/
|
||||
public function get(string $key, $default = null)
|
||||
@@ -100,34 +96,31 @@ class Cache
|
||||
$value = $this->retrieve($key);
|
||||
|
||||
// check for a valid cache value
|
||||
if (!is_a($value, 'Kirby\Cache\Value')) {
|
||||
if (!is_a($value, Value::class)) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
// remove the item if it is expired
|
||||
if (time() >= $value->expires()) {
|
||||
if ($value->expires() > 0 && time() >= $value->expires()) {
|
||||
$this->remove($key);
|
||||
return $default;
|
||||
}
|
||||
|
||||
// get the pure value
|
||||
$cache = $value->value();
|
||||
|
||||
// return the cache value or the default
|
||||
return $cache ?? $default;
|
||||
// return the pure value
|
||||
return $value->value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the expiration timestamp
|
||||
*
|
||||
* @param int $minutes
|
||||
* @param int $minutes
|
||||
* @return int
|
||||
*/
|
||||
protected function expiration(int $minutes = 0): int
|
||||
{
|
||||
// keep forever if minutes are not defined
|
||||
// 0 = keep forever
|
||||
if ($minutes === 0) {
|
||||
$minutes = 2628000;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// calculate the time
|
||||
@@ -135,10 +128,12 @@ class Cache
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks when an item in the cache expires
|
||||
* Checks when an item in the cache expires;
|
||||
* returns the expiry timestamp on success, null if the
|
||||
* item never expires and false if the item does not exist
|
||||
*
|
||||
* @param string $key
|
||||
* @return mixed
|
||||
* @param string $key
|
||||
* @return int|null|false
|
||||
*/
|
||||
public function expires(string $key)
|
||||
{
|
||||
@@ -146,7 +141,7 @@ class Cache
|
||||
$value = $this->retrieve($key);
|
||||
|
||||
// check for a valid Value object
|
||||
if (!is_a($value, 'Kirby\Cache\Value')) {
|
||||
if (!is_a($value, Value::class)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -157,19 +152,29 @@ class Cache
|
||||
/**
|
||||
* Checks if an item in the cache is expired
|
||||
*
|
||||
* @param string $key
|
||||
* @param string $key
|
||||
* @return boolean
|
||||
*/
|
||||
public function expired(string $key): bool
|
||||
{
|
||||
return $this->expires($key) <= time();
|
||||
$expires = $this->expires($key);
|
||||
|
||||
if ($expires === null) {
|
||||
return false;
|
||||
} elseif (!is_int($expires)) {
|
||||
return true;
|
||||
} else {
|
||||
return time() >= $expires;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks when the cache has been created
|
||||
* Checks when the cache has been created;
|
||||
* returns the creation timestamp on success
|
||||
* and false if the item does not exist
|
||||
*
|
||||
* @param string $key
|
||||
* @return mixed
|
||||
* @param string $key
|
||||
* @return int|false
|
||||
*/
|
||||
public function created(string $key)
|
||||
{
|
||||
@@ -177,7 +182,7 @@ class Cache
|
||||
$value = $this->retrieve($key);
|
||||
|
||||
// check for a valid Value object
|
||||
if (!is_a($value, 'Kirby\Cache\Value')) {
|
||||
if (!is_a($value, Value::class)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -188,8 +193,8 @@ class Cache
|
||||
/**
|
||||
* Alternate version for Cache::created($key)
|
||||
*
|
||||
* @param string $key
|
||||
* @return mixed
|
||||
* @param string $key
|
||||
* @return int|false
|
||||
*/
|
||||
public function modified(string $key)
|
||||
{
|
||||
@@ -197,48 +202,34 @@ class Cache
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Value object
|
||||
* Determines if an item exists in the cache
|
||||
*
|
||||
* @param mixed $value The value, which should be cached
|
||||
* @param int $minutes The number of minutes before expiration
|
||||
* @return Value
|
||||
*/
|
||||
protected function value($value, int $minutes): Value
|
||||
{
|
||||
return new Value($value, $minutes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if an item exists in the cache.
|
||||
*
|
||||
* @param string $key
|
||||
* @param string $key
|
||||
* @return boolean
|
||||
*/
|
||||
public function exists(string $key): bool
|
||||
{
|
||||
return !$this->expired($key);
|
||||
return $this->expired($key) === false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an item from the cache
|
||||
* Removes an item from the cache and returns
|
||||
* whether the operation was successful;
|
||||
* this needs to be defined by the driver
|
||||
*
|
||||
* @param string $key
|
||||
* @param string $key
|
||||
* @return boolean
|
||||
*/
|
||||
public function remove(string $key): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
abstract public function remove(string $key): bool;
|
||||
|
||||
/**
|
||||
* Flush the entire cache
|
||||
* Flushes the entire cache and returns
|
||||
* whether the operation was successful;
|
||||
* this needs to be defined by the driver
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function flush(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
abstract public function flush(): bool;
|
||||
|
||||
/**
|
||||
* Returns all passed cache options
|
||||
|
@@ -2,7 +2,6 @@
|
||||
|
||||
namespace Kirby\Cache;
|
||||
|
||||
use Exception;
|
||||
use Kirby\Toolkit\Dir;
|
||||
use Kirby\Toolkit\F;
|
||||
|
||||
@@ -11,80 +10,107 @@ use Kirby\Toolkit\F;
|
||||
*
|
||||
* @package Kirby Cache
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link http://getkirby.com
|
||||
* @copyright Bastian Allgeier
|
||||
* @license MIT
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://opensource.org/licenses/MIT
|
||||
*/
|
||||
class FileCache extends Cache
|
||||
{
|
||||
|
||||
/**
|
||||
* Set all parameters which are needed for the file cache
|
||||
* see defaults for available parameters
|
||||
*
|
||||
* @param array $params
|
||||
* Full root including prefix
|
||||
* @var string
|
||||
*/
|
||||
public function __construct(array $params)
|
||||
protected $root;
|
||||
|
||||
/**
|
||||
* Sets all parameters which are needed for the file cache
|
||||
*
|
||||
* @param array $options 'root' (required)
|
||||
* 'prefix' (default: none)
|
||||
* 'extension' (file extension for cache files, default: none)
|
||||
*/
|
||||
public function __construct(array $options)
|
||||
{
|
||||
$defaults = [
|
||||
'root' => null,
|
||||
'prefix' => null,
|
||||
'extension' => null
|
||||
];
|
||||
|
||||
parent::__construct(array_merge($defaults, $params));
|
||||
parent::__construct(array_merge($defaults, $options));
|
||||
|
||||
// build the full root including prefix
|
||||
$this->root = $this->options['root'];
|
||||
if (empty($this->options['prefix']) === false) {
|
||||
$this->root .= '/' . $this->options['prefix'];
|
||||
}
|
||||
|
||||
// try to create the directory
|
||||
Dir::make($this->options['root'], true);
|
||||
Dir::make($this->root, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the full path to a file for a given key
|
||||
*
|
||||
* @param string $key
|
||||
* @param string $key
|
||||
* @return string
|
||||
*/
|
||||
protected function file(string $key): string
|
||||
{
|
||||
$extension = isset($this->options['extension']) ? '.' . $this->options['extension'] : '';
|
||||
$file = $this->root . '/' . $key;
|
||||
|
||||
return $this->options['root'] . '/' . $this->key($key) . $extension;
|
||||
if (isset($this->options['extension'])) {
|
||||
return $file . '.' . $this->options['extension'];
|
||||
} else {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an item to the cache for a given number of minutes.
|
||||
* Writes an item to the cache for a given number of minutes and
|
||||
* returns whether the operation was successful
|
||||
*
|
||||
* <code>
|
||||
* // Put an item in the cache for 15 minutes
|
||||
* Cache::set('value', 'my value', 15);
|
||||
* // put an item in the cache for 15 minutes
|
||||
* $cache->set('value', 'my value', 15);
|
||||
* </code>
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @param int $minutes
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @param int $minutes
|
||||
* @return boolean
|
||||
*/
|
||||
public function set(string $key, $value, int $minutes = 0)
|
||||
public function set(string $key, $value, int $minutes = 0): bool
|
||||
{
|
||||
return F::write($this->file($key), $this->value($value, $minutes)->toJson());
|
||||
$file = $this->file($key);
|
||||
|
||||
return F::write($file, (new Value($value, $minutes))->toJson());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an item from the cache.
|
||||
* Internal method to retrieve the raw cache value;
|
||||
* needs to return a Value object or null if not found
|
||||
*
|
||||
* @param string $key
|
||||
* @return mixed
|
||||
* @param string $key
|
||||
* @return Kirby\Cache\Value|null
|
||||
*/
|
||||
public function retrieve(string $key)
|
||||
{
|
||||
return Value::fromJson(F::read($this->file($key)));
|
||||
$file = $this->file($key);
|
||||
|
||||
return Value::fromJson(F::read($file));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks when the cache has been created
|
||||
* Checks when the cache has been created;
|
||||
* returns the creation timestamp on success
|
||||
* and false if the item does not exist
|
||||
*
|
||||
* @param string $key
|
||||
* @return int
|
||||
* @return mixed
|
||||
*/
|
||||
public function created(string $key): int
|
||||
public function created(string $key)
|
||||
{
|
||||
// use the modification timestamp
|
||||
// as indicator when the cache has been created/overwritten
|
||||
@@ -92,37 +118,39 @@ class FileCache extends Cache
|
||||
|
||||
// get the file for this cache key
|
||||
$file = $this->file($key);
|
||||
return file_exists($file) ? filemtime($this->file($key)) : 0;
|
||||
return file_exists($file) ? filemtime($this->file($key)) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an item from the cache
|
||||
* Removes an item from the cache and returns
|
||||
* whether the operation was successful
|
||||
*
|
||||
* @param string $key
|
||||
* @param string $key
|
||||
* @return boolean
|
||||
*/
|
||||
public function remove(string $key): bool
|
||||
{
|
||||
return F::remove($this->file($key));
|
||||
$file = $this->file($key);
|
||||
|
||||
if (is_file($file) === true) {
|
||||
return F::remove($file);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush the entire cache directory
|
||||
* Flushes the entire cache and returns
|
||||
* whether the operation was successful
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function flush(): bool
|
||||
{
|
||||
$root = $this->options['root'];
|
||||
|
||||
if (empty($this->options['prefix']) === false) {
|
||||
$root = $root . '/' . $this->options['prefix'];
|
||||
}
|
||||
|
||||
if (Dir::remove($root) === true && Dir::make($root) === true) {
|
||||
if (Dir::remove($this->root) === true && Dir::make($this->root) === true) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return false; // @codeCoverageIgnore
|
||||
}
|
||||
}
|
||||
|
@@ -3,14 +3,14 @@
|
||||
namespace Kirby\Cache;
|
||||
|
||||
/**
|
||||
* Memcached Driver
|
||||
*
|
||||
* @package Kirby Cache
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link http://getkirby.com
|
||||
* @copyright Bastian Allgeier
|
||||
* @license MIT
|
||||
*/
|
||||
* Memcached Driver
|
||||
*
|
||||
* @package Kirby Cache
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://opensource.org/licenses/MIT
|
||||
*/
|
||||
class MemCached extends Cache
|
||||
{
|
||||
|
||||
@@ -21,12 +21,13 @@ class MemCached extends Cache
|
||||
protected $connection;
|
||||
|
||||
/**
|
||||
* Set all parameters which are needed for the memcache client
|
||||
* see defaults for available parameters
|
||||
* Sets all parameters which are needed to connect to Memcached
|
||||
*
|
||||
* @param array $params
|
||||
* @param array $options 'host' (default: localhost)
|
||||
* 'port' (default: 11211)
|
||||
* 'prefix' (default: null)
|
||||
*/
|
||||
public function __construct(array $params = [])
|
||||
public function __construct(array $options = [])
|
||||
{
|
||||
$defaults = [
|
||||
'host' => 'localhost',
|
||||
@@ -34,47 +35,37 @@ class MemCached extends Cache
|
||||
'prefix' => null,
|
||||
];
|
||||
|
||||
parent::__construct(array_merge($defaults, $params));
|
||||
parent::__construct(array_merge($defaults, $options));
|
||||
|
||||
$this->connection = new \Memcached();
|
||||
$this->connection->addServer($this->options['host'], $this->options['port']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an item to the cache for a given number of minutes.
|
||||
* Writes an item to the cache for a given number of minutes and
|
||||
* returns whether the operation was successful
|
||||
*
|
||||
* <code>
|
||||
* // Put an item in the cache for 15 minutes
|
||||
* Cache::set('value', 'my value', 15);
|
||||
* // put an item in the cache for 15 minutes
|
||||
* $cache->set('value', 'my value', 15);
|
||||
* </code>
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @param int $minutes
|
||||
* @return void
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @param int $minutes
|
||||
* @return boolean
|
||||
*/
|
||||
public function set(string $key, $value, int $minutes = 0)
|
||||
public function set(string $key, $value, int $minutes = 0): bool
|
||||
{
|
||||
return $this->connection->set($this->key($key), $this->value($value, $minutes)->toJson(), $this->expiration($minutes));
|
||||
return $this->connection->set($this->key($key), (new Value($value, $minutes))->toJson(), $this->expiration($minutes));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the full keyname
|
||||
* including the prefix (if set)
|
||||
* Internal method to retrieve the raw cache value;
|
||||
* needs to return a Value object or null if not found
|
||||
*
|
||||
* @param string $key
|
||||
* @return string
|
||||
*/
|
||||
public function key(string $key): string
|
||||
{
|
||||
return $this->options['prefix'] . $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the CacheValue object from the cache.
|
||||
*
|
||||
* @param string $key
|
||||
* @return object CacheValue
|
||||
* @param string $key
|
||||
* @return Kirby\Cache\Value|null
|
||||
*/
|
||||
public function retrieve(string $key)
|
||||
{
|
||||
@@ -82,9 +73,10 @@ class MemCached extends Cache
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an item from the cache
|
||||
* Removes an item from the cache and returns
|
||||
* whether the operation was successful
|
||||
*
|
||||
* @param string $key
|
||||
* @param string $key
|
||||
* @return boolean
|
||||
*/
|
||||
public function remove(string $key): bool
|
||||
@@ -93,40 +85,9 @@ class MemCached extends Cache
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks when an item in the cache expires
|
||||
*
|
||||
* @param string $key
|
||||
* @return int
|
||||
*/
|
||||
public function expires(string $key): int
|
||||
{
|
||||
return parent::expires($this->key($key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an item in the cache is expired
|
||||
*
|
||||
* @param string $key
|
||||
* @return boolean
|
||||
*/
|
||||
public function expired(string $key): bool
|
||||
{
|
||||
return parent::expired($this->key($key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks when the cache has been created
|
||||
*
|
||||
* @param string $key
|
||||
* @return int
|
||||
*/
|
||||
public function created(string $key): int
|
||||
{
|
||||
return parent::created($this->key($key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush the entire cache directory
|
||||
* Flushes the entire cache and returns
|
||||
* whether the operation was successful;
|
||||
* WARNING: Memcached only supports flushing the whole cache at once!
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
|
83
kirby/src/Cache/MemoryCache.php
Executable file
83
kirby/src/Cache/MemoryCache.php
Executable file
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
namespace Kirby\Cache;
|
||||
|
||||
/**
|
||||
* Memory Cache Driver (cache in memory for current request only)
|
||||
*
|
||||
* @package Kirby Cache
|
||||
* @author Lukas Bestle <lukas@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://opensource.org/licenses/MIT
|
||||
*/
|
||||
class MemoryCache extends Cache
|
||||
{
|
||||
|
||||
/**
|
||||
* Cache data
|
||||
* @var array
|
||||
*/
|
||||
protected $store = [];
|
||||
|
||||
/**
|
||||
* Writes an item to the cache for a given number of minutes and
|
||||
* returns whether the operation was successful
|
||||
*
|
||||
* <code>
|
||||
* // put an item in the cache for 15 minutes
|
||||
* $cache->set('value', 'my value', 15);
|
||||
* </code>
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @param int $minutes
|
||||
* @return boolean
|
||||
*/
|
||||
public function set(string $key, $value, int $minutes = 0): bool
|
||||
{
|
||||
$this->store[$key] = new Value($value, $minutes);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal method to retrieve the raw cache value;
|
||||
* needs to return a Value object or null if not found
|
||||
*
|
||||
* @param string $key
|
||||
* @return Kirby\Cache\Value|null
|
||||
*/
|
||||
public function retrieve(string $key)
|
||||
{
|
||||
return $this->store[$key] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an item from the cache and returns
|
||||
* whether the operation was successful
|
||||
*
|
||||
* @param string $key
|
||||
* @return boolean
|
||||
*/
|
||||
public function remove(string $key): bool
|
||||
{
|
||||
if (isset($this->store[$key])) {
|
||||
unset($this->store[$key]);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flushes the entire cache and returns
|
||||
* whether the operation was successful
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function flush(): bool
|
||||
{
|
||||
$this->store = [];
|
||||
return true;
|
||||
}
|
||||
}
|
70
kirby/src/Cache/NullCache.php
Executable file
70
kirby/src/Cache/NullCache.php
Executable file
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
namespace Kirby\Cache;
|
||||
|
||||
/**
|
||||
* Dummy Cache Driver (does not do any caching)
|
||||
*
|
||||
* @package Kirby Cache
|
||||
* @author Lukas Bestle <lukas@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://opensource.org/licenses/MIT
|
||||
*/
|
||||
class NullCache extends Cache
|
||||
{
|
||||
|
||||
/**
|
||||
* Writes an item to the cache for a given number of minutes and
|
||||
* returns whether the operation was successful
|
||||
*
|
||||
* <code>
|
||||
* // put an item in the cache for 15 minutes
|
||||
* $cache->set('value', 'my value', 15);
|
||||
* </code>
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @param int $minutes
|
||||
* @return boolean
|
||||
*/
|
||||
public function set(string $key, $value, int $minutes = 0): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal method to retrieve the raw cache value;
|
||||
* needs to return a Value object or null if not found
|
||||
*
|
||||
* @param string $key
|
||||
* @return Kirby\Cache\Value|null
|
||||
*/
|
||||
public function retrieve(string $key)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an item from the cache and returns
|
||||
* whether the operation was successful
|
||||
*
|
||||
* @param string $key
|
||||
* @return boolean
|
||||
*/
|
||||
public function remove(string $key): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flushes the entire cache and returns
|
||||
* whether the operation was successful
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function flush(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -7,31 +7,31 @@ use Throwable;
|
||||
/**
|
||||
* Cache Value
|
||||
* Stores the value, creation timestamp and expiration timestamp
|
||||
* and makes it possible to store all three with a single cache key.
|
||||
* and makes it possible to store all three with a single cache key
|
||||
*
|
||||
* @package Kirby Cache
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link http://getkirby.com
|
||||
* @copyright Bastian Allgeier
|
||||
* @license MIT
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://opensource.org/licenses/MIT
|
||||
*/
|
||||
class Value
|
||||
{
|
||||
|
||||
/**
|
||||
* the cached value
|
||||
* Cached value
|
||||
* @var mixed
|
||||
*/
|
||||
protected $value;
|
||||
|
||||
/**
|
||||
* the expiration timestamp
|
||||
* the number of minutes until the value expires
|
||||
* @var int
|
||||
*/
|
||||
protected $expires;
|
||||
protected $minutes;
|
||||
|
||||
/**
|
||||
* the creation timestamp
|
||||
* Creation timestamp
|
||||
* @var int
|
||||
*/
|
||||
protected $created;
|
||||
@@ -40,18 +40,13 @@ class Value
|
||||
* Constructor
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param int $minutes the number of minutes until the value expires
|
||||
* @param int $created the unix timestamp when the value has been created
|
||||
* @param int $minutes the number of minutes until the value expires
|
||||
* @param int $created the unix timestamp when the value has been created
|
||||
*/
|
||||
public function __construct($value, int $minutes = 0, $created = null)
|
||||
public function __construct($value, int $minutes = 0, int $created = null)
|
||||
{
|
||||
// keep forever if minutes are not defined
|
||||
if ($minutes === 0) {
|
||||
$minutes = 2628000;
|
||||
}
|
||||
|
||||
$this->value = $value;
|
||||
$this->minutes = $minutes;
|
||||
$this->minutes = $minutes ?? 0;
|
||||
$this->created = $created ?? time();
|
||||
}
|
||||
|
||||
@@ -66,12 +61,18 @@ class Value
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the expiration date as UNIX timestamp
|
||||
* Returns the expiration date as UNIX timestamp or
|
||||
* null if the value never expires
|
||||
*
|
||||
* @return int
|
||||
* @return int|null
|
||||
*/
|
||||
public function expires(): int
|
||||
public function expires(): ?int
|
||||
{
|
||||
// 0 = keep forever
|
||||
if ($this->minutes === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->created + ($this->minutes * 60);
|
||||
}
|
||||
|
||||
@@ -79,32 +80,37 @@ class Value
|
||||
* Creates a value object from an array
|
||||
*
|
||||
* @param array $array
|
||||
* @return array
|
||||
* @return self
|
||||
*/
|
||||
public static function fromArray(array $array): self
|
||||
public static function fromArray(array $array)
|
||||
{
|
||||
return new static($array['value'] ?? null, $array['minutes'] ?? 0, $array['created'] ?? null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a value object from a json string
|
||||
* Creates a value object from a JSON string;
|
||||
* returns null on error
|
||||
*
|
||||
* @param string $json
|
||||
* @return array
|
||||
* @return self|null
|
||||
*/
|
||||
public static function fromJson($json): self
|
||||
public static function fromJson(string $json)
|
||||
{
|
||||
try {
|
||||
$array = json_decode($json, true) ?? [];
|
||||
} catch (Throwable $e) {
|
||||
$array = [];
|
||||
}
|
||||
$array = json_decode($json, true);
|
||||
|
||||
return static::fromArray($array);
|
||||
if (is_array($array)) {
|
||||
return static::fromArray($array);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the object to a json string
|
||||
* Converts the object to a JSON string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
@@ -114,7 +120,7 @@ class Value
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the object to an array
|
||||
* Converts the object to an array
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
@@ -128,7 +134,7 @@ class Value
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value
|
||||
* Returns the pure value
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
|
@@ -7,16 +7,37 @@ use Kirby\Exception\InvalidArgumentException;
|
||||
use Kirby\Exception\NotFoundException;
|
||||
use Kirby\Toolkit\Str;
|
||||
|
||||
/**
|
||||
* Api
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class Api extends BaseApi
|
||||
{
|
||||
/**
|
||||
* @var App
|
||||
*/
|
||||
protected $kirby;
|
||||
|
||||
/**
|
||||
* Execute an API call for the given path,
|
||||
* request method and optional request data
|
||||
*
|
||||
* @param string $path
|
||||
* @param string $method
|
||||
* @param array $requestData
|
||||
* @return mixed
|
||||
*/
|
||||
public function call(string $path = null, string $method = 'GET', array $requestData = [])
|
||||
{
|
||||
$this->setRequestMethod($method);
|
||||
$this->setRequestData($requestData);
|
||||
|
||||
if ($languageCode = $this->requestHeaders('x-language')) {
|
||||
if ($languageCode = $this->language()) {
|
||||
$this->kirby->setCurrentLanguage($languageCode);
|
||||
}
|
||||
|
||||
@@ -27,6 +48,12 @@ class Api extends BaseApi
|
||||
return parent::call($path, $method, $requestData);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $model
|
||||
* @param string $name
|
||||
* @param string $path
|
||||
* @return mixed
|
||||
*/
|
||||
public function fieldApi($model, string $name, string $path = null)
|
||||
{
|
||||
$form = Form::for($model);
|
||||
@@ -59,6 +86,14 @@ class Api extends BaseApi
|
||||
return $fieldApi->call($path, $this->requestMethod(), $this->requestData());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file object for the given
|
||||
* parent path and filename
|
||||
*
|
||||
* @param string $path Path to file's parent model
|
||||
* @param string $filename Filename
|
||||
* @return Kirby\Cms\File|null
|
||||
*/
|
||||
public function file(string $path = null, string $filename)
|
||||
{
|
||||
$filename = urldecode($filename);
|
||||
@@ -75,12 +110,22 @@ class Api extends BaseApi
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the model's object for the given path
|
||||
*
|
||||
* @param string $path Path to parent model
|
||||
* @return Kirby\Cms\Model|null
|
||||
*/
|
||||
public function parent(string $path)
|
||||
{
|
||||
$modelType = $path === 'site' ? 'site' : dirname($path);
|
||||
$modelType = $path === 'site' ? 'site' : trim(dirname($path), '/');
|
||||
$modelTypes = ['site' => 'site', 'users' => 'user', 'pages' => 'page'];
|
||||
$modelName = $modelTypes[$modelType] ?? null;
|
||||
|
||||
if (Str::endsWith($modelType, '/files') === true) {
|
||||
$modelName = 'file';
|
||||
}
|
||||
|
||||
if ($modelName === null) {
|
||||
throw new InvalidArgumentException('Invalid file model type');
|
||||
}
|
||||
@@ -91,7 +136,13 @@ class Api extends BaseApi
|
||||
$modelId = basename($path);
|
||||
|
||||
if ($modelName === 'page') {
|
||||
$modelId = str_replace('+', '/', $modelId);
|
||||
$modelId = str_replace(['+', ' '], '/', $modelId);
|
||||
}
|
||||
|
||||
if ($modelName === 'file') {
|
||||
if ($model = $this->file(...explode('/files/', $path))) {
|
||||
return $model;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,16 +155,32 @@ class Api extends BaseApi
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Kirby instance
|
||||
*
|
||||
* @return Kirby\Cms\App
|
||||
*/
|
||||
public function kirby()
|
||||
{
|
||||
return $this->kirby;
|
||||
}
|
||||
|
||||
public function language()
|
||||
/**
|
||||
* Returns the language request header
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function language(): ?string
|
||||
{
|
||||
return $this->requestHeaders('x-language');
|
||||
return get('language') ?? $this->requestHeaders('x-language');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the page object for the given id
|
||||
*
|
||||
* @param string $id Page's id
|
||||
* @return Kirby\Cms\Page|null
|
||||
*/
|
||||
public function page(string $id)
|
||||
{
|
||||
$id = str_replace('+', '/', $id);
|
||||
@@ -138,17 +205,33 @@ class Api extends BaseApi
|
||||
], $options));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Kirby\Cms\App $kirby
|
||||
*/
|
||||
protected function setKirby(App $kirby)
|
||||
{
|
||||
$this->kirby = $kirby;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the site object
|
||||
*
|
||||
* @return Kirby\Cms\Site
|
||||
*/
|
||||
public function site()
|
||||
{
|
||||
return $this->kirby->site();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the user object for the given id or
|
||||
* returns the current authenticated user if no
|
||||
* id is passed
|
||||
*
|
||||
* @param string $id User's id
|
||||
* @return Kirby\Cms\User|null
|
||||
*/
|
||||
public function user(string $id = null)
|
||||
{
|
||||
// get the authenticated user
|
||||
@@ -169,6 +252,11 @@ class Api extends BaseApi
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the users collection
|
||||
*
|
||||
* @return Kirby\Cms\Users
|
||||
*/
|
||||
public function users()
|
||||
{
|
||||
return $this->kirby->users();
|
||||
|
@@ -2,22 +2,15 @@
|
||||
|
||||
namespace Kirby\Cms;
|
||||
|
||||
use Closure;
|
||||
use Exception;
|
||||
use Throwable;
|
||||
use Kirby\Data\Data;
|
||||
use Kirby\Email\PHPMailer as Emailer;
|
||||
use Kirby\Exception\InvalidArgumentException;
|
||||
use Kirby\Exception\LogicException;
|
||||
use Kirby\Exception\NotFoundException;
|
||||
use Kirby\Form\Field;
|
||||
use Kirby\Http\Route;
|
||||
use Kirby\Http\Router;
|
||||
use Kirby\Http\Request;
|
||||
use Kirby\Http\Server;
|
||||
use Kirby\Http\Visitor;
|
||||
use Kirby\Image\Darkroom;
|
||||
use Kirby\Session\AutoSession as Session;
|
||||
use Kirby\Session\AutoSession;
|
||||
use Kirby\Text\KirbyTag;
|
||||
use Kirby\Toolkit\A;
|
||||
use Kirby\Toolkit\Config;
|
||||
@@ -25,8 +18,6 @@ use Kirby\Toolkit\Controller;
|
||||
use Kirby\Toolkit\F;
|
||||
use Kirby\Toolkit\Dir;
|
||||
use Kirby\Toolkit\Properties;
|
||||
use Kirby\Toolkit\Str;
|
||||
use Kirby\Toolkit\Url;
|
||||
|
||||
/**
|
||||
* The `$kirby` object is the app instance of
|
||||
@@ -37,8 +28,9 @@ use Kirby\Toolkit\Url;
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link http://getkirby.com
|
||||
* @copyright Bastian Allgeier
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class App
|
||||
{
|
||||
@@ -62,6 +54,7 @@ class App
|
||||
protected $defaultLanguage;
|
||||
protected $language;
|
||||
protected $languages;
|
||||
protected $locks;
|
||||
protected $multilang;
|
||||
protected $options;
|
||||
protected $path;
|
||||
@@ -135,7 +128,7 @@ class App
|
||||
}
|
||||
|
||||
/**
|
||||
* Improved var_dump output
|
||||
* Improved `var_dump` output
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
@@ -156,9 +149,9 @@ class App
|
||||
* Returns the Api instance
|
||||
*
|
||||
* @internal
|
||||
* @return Api
|
||||
* @return Kirby\Cms\Api
|
||||
*/
|
||||
public function api(): Api
|
||||
public function api()
|
||||
{
|
||||
if ($this->api !== null) {
|
||||
return $this->api;
|
||||
@@ -182,19 +175,33 @@ class App
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a hook to the given value
|
||||
* Applies a hook to the given value;
|
||||
* the value that gets modified by the hooks
|
||||
* is always the last argument
|
||||
*
|
||||
* @internal
|
||||
* @param string $name
|
||||
* @param mixed $value
|
||||
* @return mixed
|
||||
* @param string $name Hook name
|
||||
* @param mixed $args Arguments to pass to the hooks
|
||||
* @return mixed Resulting value as modified by the hooks
|
||||
*/
|
||||
public function apply(string $name, $value)
|
||||
public function apply(string $name, ...$args)
|
||||
{
|
||||
// split up args into "passive" args and the value
|
||||
$value = array_pop($args);
|
||||
|
||||
if ($functions = $this->extension('hooks', $name)) {
|
||||
foreach ($functions as $function) {
|
||||
// re-assemble args
|
||||
$hookArgs = $args;
|
||||
$hookArgs[] = $value;
|
||||
|
||||
// bind the App object to the hook
|
||||
$value = $function->call($this, $value);
|
||||
$newValue = $function->call($this, ...$hookArgs);
|
||||
|
||||
// update value if one was returned
|
||||
if ($newValue !== null) {
|
||||
$value = $newValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,7 +245,7 @@ class App
|
||||
* @param string $type
|
||||
* @return array
|
||||
*/
|
||||
public function blueprints(string $type = 'pages')
|
||||
public function blueprints(string $type = 'pages'): array
|
||||
{
|
||||
$blueprints = [];
|
||||
|
||||
@@ -262,6 +269,8 @@ class App
|
||||
/**
|
||||
* Calls any Kirby route
|
||||
*
|
||||
* @param string $path
|
||||
* @param string $method
|
||||
* @return mixed
|
||||
*/
|
||||
public function call(string $path = null, string $method = null)
|
||||
@@ -273,7 +282,7 @@ class App
|
||||
};
|
||||
|
||||
$router::$afterEach = function ($route, $path, $method, $result) {
|
||||
$this->trigger('route:after', $route, $path, $method, $result);
|
||||
return $this->apply('route:after', $route, $path, $method, $result);
|
||||
};
|
||||
|
||||
return $router->call($path ?? $this->path(), $method ?? $this->request()->method());
|
||||
@@ -300,9 +309,9 @@ class App
|
||||
/**
|
||||
* Returns all user-defined collections
|
||||
*
|
||||
* @return Collections
|
||||
* @return Kirby\Cms\Collections
|
||||
*/
|
||||
public function collections(): Collections
|
||||
public function collections()
|
||||
{
|
||||
return $this->collections = $this->collections ?? new Collections;
|
||||
}
|
||||
@@ -379,9 +388,9 @@ class App
|
||||
* Try to find a controller by name
|
||||
*
|
||||
* @param string $name
|
||||
* @return Closure|null
|
||||
* @return Kirby\Toolkit\Controller|null
|
||||
*/
|
||||
protected function controllerLookup(string $name, string $contentType = 'html'): ?Controller
|
||||
protected function controllerLookup(string $name, string $contentType = 'html')
|
||||
{
|
||||
if ($contentType !== null && $contentType !== 'html') {
|
||||
$name .= '.' . $contentType;
|
||||
@@ -403,9 +412,9 @@ class App
|
||||
/**
|
||||
* Returns the default language object
|
||||
*
|
||||
* @return Language|null
|
||||
* @return Kirby\Cms\Language|null
|
||||
*/
|
||||
public function defaultLanguage(): ?Language
|
||||
public function defaultLanguage()
|
||||
{
|
||||
return $this->defaultLanguage = $this->defaultLanguage ?? $this->languages()->default();
|
||||
}
|
||||
@@ -416,7 +425,7 @@ class App
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public static function destroy()
|
||||
public static function destroy(): void
|
||||
{
|
||||
static::$plugins = [];
|
||||
static::$instance = null;
|
||||
@@ -425,7 +434,7 @@ class App
|
||||
/**
|
||||
* Detect the prefered language from the visitor object
|
||||
*
|
||||
* @return Language
|
||||
* @return Kirby\Cms\Language
|
||||
*/
|
||||
public function detectedLanguage()
|
||||
{
|
||||
@@ -450,9 +459,9 @@ class App
|
||||
/**
|
||||
* Returns the Email singleton
|
||||
*
|
||||
* @return Email
|
||||
* @return Kirby\Email\PHPMailer
|
||||
*/
|
||||
public function email($preset = [], array $props = []): Emailer
|
||||
public function email($preset = [], array $props = [])
|
||||
{
|
||||
return new Emailer((new Email($preset, $props))->toArray(), $props['debug'] ?? false);
|
||||
}
|
||||
@@ -462,7 +471,7 @@ class App
|
||||
*
|
||||
* @param string $path
|
||||
* @param boolean $drafts
|
||||
* @return File|null
|
||||
* @return Kirby\Cms\File|null
|
||||
*/
|
||||
public function file(string $path, $parent = null, bool $drafts = true)
|
||||
{
|
||||
@@ -502,10 +511,10 @@ class App
|
||||
/**
|
||||
* Returns the current App instance
|
||||
*
|
||||
* @param self $instance
|
||||
* @param Kirby\Cms\App $instance
|
||||
* @return self
|
||||
*/
|
||||
public static function instance(self $instance = null): self
|
||||
public static function instance(self $instance = null)
|
||||
{
|
||||
if ($instance === null) {
|
||||
return static::$instance ?? new static;
|
||||
@@ -520,7 +529,7 @@ class App
|
||||
*
|
||||
* @internal
|
||||
* @param mixed $input
|
||||
* @return Response
|
||||
* @return Kirby\Http\Response
|
||||
*/
|
||||
public function io($input)
|
||||
{
|
||||
@@ -664,9 +673,9 @@ class App
|
||||
* Returns the current language
|
||||
*
|
||||
* @param string|null $code
|
||||
* @return Language|null
|
||||
* @return Kirby\Cms\Language|null
|
||||
*/
|
||||
public function language(string $code = null): ?Language
|
||||
public function language(string $code = null)
|
||||
{
|
||||
if ($this->multilang() === false) {
|
||||
return null;
|
||||
@@ -701,9 +710,9 @@ class App
|
||||
/**
|
||||
* Returns all available site languages
|
||||
*
|
||||
* @return Languages
|
||||
* @return Kirby\Cms\Languages
|
||||
*/
|
||||
public function languages(): Languages
|
||||
public function languages()
|
||||
{
|
||||
if ($this->languages !== null) {
|
||||
return clone $this->languages;
|
||||
@@ -712,6 +721,20 @@ class App
|
||||
return $this->languages = Languages::load();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the app's locks object
|
||||
*
|
||||
* @return Kirby\Cms\ContentLocks
|
||||
*/
|
||||
public function locks(): ContentLocks
|
||||
{
|
||||
if ($this->locks !== null) {
|
||||
return $this->locks;
|
||||
}
|
||||
|
||||
return $this->locks = new ContentLocks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses Markdown
|
||||
*
|
||||
@@ -766,7 +789,7 @@ class App
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function optionsFromProps(array $options = [])
|
||||
protected function optionsFromProps(array $options = []): array
|
||||
{
|
||||
return $this->options = array_replace_recursive($this->options, $options);
|
||||
}
|
||||
@@ -796,9 +819,9 @@ class App
|
||||
* Returns any page from the content folder
|
||||
*
|
||||
* @param string $id
|
||||
* @param Page|null $parent
|
||||
* @param Kirby\Cms\Page|Kirby\Cms\Site|null $parent
|
||||
* @param bool $drafts
|
||||
* @return Page|null
|
||||
* @return Kirby\Cms\Page|null
|
||||
*/
|
||||
public function page(string $id, $parent = null, bool $drafts = true)
|
||||
{
|
||||
@@ -820,7 +843,7 @@ class App
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function path()
|
||||
public function path(): string
|
||||
{
|
||||
if (is_string($this->path) === true) {
|
||||
return $this->path;
|
||||
@@ -840,7 +863,7 @@ class App
|
||||
* Returns the Response object for the
|
||||
* current request
|
||||
*
|
||||
* @return Response
|
||||
* @return Kirby\Http\Response
|
||||
*/
|
||||
public function render(string $path = null, string $method = null)
|
||||
{
|
||||
@@ -850,9 +873,9 @@ class App
|
||||
/**
|
||||
* Returns the Request singleton
|
||||
*
|
||||
* @return Request
|
||||
* @return Kirby\Http\Request
|
||||
*/
|
||||
public function request(): Request
|
||||
public function request()
|
||||
{
|
||||
return $this->request = $this->request ?? new Request;
|
||||
}
|
||||
@@ -931,7 +954,7 @@ class App
|
||||
/**
|
||||
* Response configuration
|
||||
*
|
||||
* @return Responder
|
||||
* @return Kirby\Cms\Responder
|
||||
*/
|
||||
public function response()
|
||||
{
|
||||
@@ -941,9 +964,9 @@ class App
|
||||
/**
|
||||
* Returns all user roles
|
||||
*
|
||||
* @return Roles
|
||||
* @return Kirby\Cms\Roles
|
||||
*/
|
||||
public function roles(): Roles
|
||||
public function roles()
|
||||
{
|
||||
return $this->roles = $this->roles ?? Roles::load($this->root('roles'));
|
||||
}
|
||||
@@ -954,7 +977,7 @@ class App
|
||||
* @param string $type
|
||||
* @return string
|
||||
*/
|
||||
public function root($type = 'index'): string
|
||||
public function root(string $type = 'index'): string
|
||||
{
|
||||
return $this->roots->__get($type);
|
||||
}
|
||||
@@ -962,9 +985,9 @@ class App
|
||||
/**
|
||||
* Returns the directory structure
|
||||
*
|
||||
* @return Ingredients
|
||||
* @return Kirby\Cms\Ingredients
|
||||
*/
|
||||
public function roots(): Ingredients
|
||||
public function roots()
|
||||
{
|
||||
return $this->roots;
|
||||
}
|
||||
@@ -972,7 +995,7 @@ class App
|
||||
/**
|
||||
* Returns the currently active route
|
||||
*
|
||||
* @return Route|null
|
||||
* @return Kirby\Http\Route|null
|
||||
*/
|
||||
public function route()
|
||||
{
|
||||
@@ -983,11 +1006,21 @@ class App
|
||||
* Returns the Router singleton
|
||||
*
|
||||
* @internal
|
||||
* @return Router
|
||||
* @return Kirby\Http\Router
|
||||
*/
|
||||
public function router(): Router
|
||||
public function router()
|
||||
{
|
||||
return $this->router = $this->router ?? new Router($this->routes());
|
||||
$routes = $this->routes();
|
||||
|
||||
if ($this->multilang() === true) {
|
||||
foreach ($routes as $index => $route) {
|
||||
if (empty($route['language']) === false) {
|
||||
unset($routes[$index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->router = $this->router ?? new Router($routes);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1004,19 +1037,20 @@ class App
|
||||
|
||||
$registry = $this->extensions('routes');
|
||||
$system = (include static::$root . '/config/routes.php')($this);
|
||||
$routes = array_merge($system['before'], $registry, $system['after']);
|
||||
|
||||
return $this->routes = array_merge($system['before'], $registry, $system['after']);
|
||||
return $this->routes = $routes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current session object
|
||||
*
|
||||
* @param array $options Additional options, see the session component
|
||||
* @return Session
|
||||
* @return Kirby\Session\Session
|
||||
*/
|
||||
public function session(array $options = [])
|
||||
{
|
||||
$this->session = $this->session ?? new Session($this->root('sessions'), $this->options['session'] ?? []);
|
||||
$this->session = $this->session ?? new AutoSession($this->root('sessions'), $this->options['session'] ?? []);
|
||||
return $this->session->get($options);
|
||||
}
|
||||
|
||||
@@ -1026,7 +1060,7 @@ class App
|
||||
* @param array $languages
|
||||
* @return self
|
||||
*/
|
||||
protected function setLanguages(array $languages = null): self
|
||||
protected function setLanguages(array $languages = null)
|
||||
{
|
||||
if ($languages !== null) {
|
||||
$this->languages = new Languages();
|
||||
@@ -1053,7 +1087,13 @@ class App
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function setRequest(array $request = null): self
|
||||
/**
|
||||
* Sets the request
|
||||
*
|
||||
* @param array $request
|
||||
* @return self
|
||||
*/
|
||||
protected function setRequest(array $request = null)
|
||||
{
|
||||
if ($request !== null) {
|
||||
$this->request = new Request($request);
|
||||
@@ -1068,7 +1108,7 @@ class App
|
||||
* @param array $roles
|
||||
* @return self
|
||||
*/
|
||||
protected function setRoles(array $roles = null): self
|
||||
protected function setRoles(array $roles = null)
|
||||
{
|
||||
if ($roles !== null) {
|
||||
$this->roles = Roles::factory($roles, [
|
||||
@@ -1082,7 +1122,7 @@ class App
|
||||
/**
|
||||
* Sets a custom Site object
|
||||
*
|
||||
* @param array|Site $site
|
||||
* @param Kirby\Cms\Site|array $site
|
||||
* @return self
|
||||
*/
|
||||
protected function setSite($site = null)
|
||||
@@ -1100,9 +1140,9 @@ class App
|
||||
/**
|
||||
* Returns the Server object
|
||||
*
|
||||
* @return Server
|
||||
* @return Kirby\Http\Server
|
||||
*/
|
||||
public function server(): Server
|
||||
public function server()
|
||||
{
|
||||
return $this->server = $this->server ?? new Server;
|
||||
}
|
||||
@@ -1110,9 +1150,9 @@ class App
|
||||
/**
|
||||
* Initializes and returns the Site object
|
||||
*
|
||||
* @return Site
|
||||
* @return Kirby\Cms\Site
|
||||
*/
|
||||
public function site(): Site
|
||||
public function site()
|
||||
{
|
||||
return $this->site = $this->site ?? new Site([
|
||||
'errorPageId' => $this->options['error'] ?? 'error',
|
||||
@@ -1145,9 +1185,9 @@ class App
|
||||
* and return a template snippet
|
||||
*
|
||||
* @internal
|
||||
* @return Snippet
|
||||
* @return string
|
||||
*/
|
||||
public function snippet(string $name, array $data = []): ?string
|
||||
public function snippet($name, array $data = []): ?string
|
||||
{
|
||||
return $this->component('snippet')($this, $name, array_merge($this->data, $data));
|
||||
}
|
||||
@@ -1155,9 +1195,9 @@ class App
|
||||
/**
|
||||
* System check class
|
||||
*
|
||||
* @return System
|
||||
* @return Kirby\Cms\System
|
||||
*/
|
||||
public function system(): System
|
||||
public function system()
|
||||
{
|
||||
return $this->system = $this->system ?? new System($this);
|
||||
}
|
||||
@@ -1167,9 +1207,9 @@ class App
|
||||
* and return the Template object
|
||||
*
|
||||
* @internal
|
||||
* @return Template
|
||||
* @return Kirby\Cms\Template
|
||||
*/
|
||||
public function template(string $name, string $type = 'html', string $defaultType = 'html'): Template
|
||||
public function template(string $name, string $type = 'html', string $defaultType = 'html')
|
||||
{
|
||||
return $this->component('template')($this, $name, $type, $defaultType);
|
||||
}
|
||||
@@ -1228,7 +1268,7 @@ class App
|
||||
* @param string $type
|
||||
* @return string
|
||||
*/
|
||||
public function url($type = 'index'): string
|
||||
public function url(string $type = 'index'): string
|
||||
{
|
||||
return $this->urls->__get($type);
|
||||
}
|
||||
@@ -1236,9 +1276,9 @@ class App
|
||||
/**
|
||||
* Returns the url structure
|
||||
*
|
||||
* @return Ingredients
|
||||
* @return Kirby\Cms\Ingredients
|
||||
*/
|
||||
public function urls(): Ingredients
|
||||
public function urls()
|
||||
{
|
||||
return $this->urls;
|
||||
}
|
||||
@@ -1249,7 +1289,7 @@ class App
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public static function version()
|
||||
public static function version(): ?string
|
||||
{
|
||||
return static::$version = static::$version ?? Data::read(static::$root . '/composer.json')['version'] ?? null;
|
||||
}
|
||||
@@ -1267,9 +1307,9 @@ class App
|
||||
/**
|
||||
* Returns the visitor object
|
||||
*
|
||||
* @return Visitor
|
||||
* @return Kirby\Cms\Visitor
|
||||
*/
|
||||
public function visitor(): Visitor
|
||||
public function visitor()
|
||||
{
|
||||
return $this->visitor = $this->visitor ?? new Visitor();
|
||||
}
|
||||
|
@@ -3,8 +3,18 @@
|
||||
namespace Kirby\Cms;
|
||||
|
||||
use Kirby\Cache\Cache;
|
||||
use Kirby\Cache\NullCache;
|
||||
use Kirby\Exception\InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* AppCaches
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
trait AppCaches
|
||||
{
|
||||
protected $caches = [];
|
||||
@@ -13,7 +23,7 @@ trait AppCaches
|
||||
* Returns a cache instance by key
|
||||
*
|
||||
* @param string $key
|
||||
* @return Cache
|
||||
* @return Kirby\Cache\Cache
|
||||
*/
|
||||
public function cache(string $key)
|
||||
{
|
||||
@@ -25,7 +35,8 @@ trait AppCaches
|
||||
$options = $this->cacheOptions($key);
|
||||
|
||||
if ($options['active'] === false) {
|
||||
return $this->caches[$key] = new Cache;
|
||||
// use a dummy cache that does nothing
|
||||
return $this->caches[$key] = new NullCache;
|
||||
}
|
||||
|
||||
$type = strtolower($options['type']);
|
||||
@@ -41,7 +52,17 @@ trait AppCaches
|
||||
$className = $types[$type];
|
||||
|
||||
// initialize the cache class
|
||||
return $this->caches[$key] = new $className($options);
|
||||
$cache = new $className($options);
|
||||
|
||||
// check if it is a useable cache object
|
||||
if (is_a($cache, Cache::class) !== true) {
|
||||
throw new InvalidArgumentException([
|
||||
'key' => 'app.invalid.cacheType',
|
||||
'data' => ['type' => $type]
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->caches[$key] = $cache;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -60,11 +81,16 @@ trait AppCaches
|
||||
];
|
||||
}
|
||||
|
||||
$prefix = str_replace('/', '_', $this->system()->indexUrl()) .
|
||||
'/' .
|
||||
str_replace('.', '/', $key);
|
||||
|
||||
$defaults = [
|
||||
'active' => true,
|
||||
'type' => 'file',
|
||||
'extension' => 'cache',
|
||||
'root' => $this->root('cache') . '/' . str_replace('.', '/', $key)
|
||||
'root' => $this->root('cache'),
|
||||
'prefix' => $prefix
|
||||
];
|
||||
|
||||
if ($options === true) {
|
||||
@@ -103,7 +129,7 @@ trait AppCaches
|
||||
$cacheName = implode('.', array_slice($parts, 2));
|
||||
|
||||
// check if such a plugin exists
|
||||
if ($plugin = $this->plugin($pluginName)) {
|
||||
if ($this->plugin($pluginName)) {
|
||||
return empty($cacheName) === true ? $pluginPrefix . '.cache' : $pluginPrefix . '.cache.' . $cacheName;
|
||||
}
|
||||
|
||||
|
@@ -2,8 +2,6 @@
|
||||
|
||||
namespace Kirby\Cms;
|
||||
|
||||
use Closure;
|
||||
use Kirby\Exception\Exception;
|
||||
use Kirby\Http\Response;
|
||||
use Whoops\Run as Whoops;
|
||||
use Whoops\Handler\Handler;
|
||||
@@ -11,9 +9,18 @@ use Whoops\Handler\PrettyPageHandler;
|
||||
use Whoops\Handler\PlainTextHandler;
|
||||
use Whoops\Handler\CallbackHandler;
|
||||
|
||||
/**
|
||||
* AppErrors
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
trait AppErrors
|
||||
{
|
||||
protected function handleCliErrors()
|
||||
protected function handleCliErrors(): void
|
||||
{
|
||||
$whoops = new Whoops;
|
||||
$whoops->pushHandler(new PlainTextHandler);
|
||||
|
@@ -4,7 +4,6 @@ namespace Kirby\Cms;
|
||||
|
||||
use Closure;
|
||||
use Kirby\Exception\DuplicateException;
|
||||
use Kirby\Exception\InvalidArgumentException;
|
||||
use Kirby\Form\Field as FormField;
|
||||
use Kirby\Text\KirbyTag;
|
||||
use Kirby\Toolkit\A;
|
||||
@@ -13,6 +12,15 @@ use Kirby\Toolkit\Dir;
|
||||
use Kirby\Toolkit\F;
|
||||
use Kirby\Toolkit\V;
|
||||
|
||||
/**
|
||||
* AppPlugins
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
trait AppPlugins
|
||||
{
|
||||
|
||||
@@ -29,6 +37,10 @@ trait AppPlugins
|
||||
* @var array
|
||||
*/
|
||||
protected $extensions = [
|
||||
// load options first to make them available for the rest
|
||||
'options' => [],
|
||||
|
||||
// other plugin types
|
||||
'api' => [],
|
||||
'blueprints' => [],
|
||||
'cacheTypes' => [],
|
||||
@@ -39,13 +51,13 @@ trait AppPlugins
|
||||
'fieldMethods' => [],
|
||||
'fileMethods' => [],
|
||||
'filesMethods' => [],
|
||||
'fileModels' => [],
|
||||
'fields' => [],
|
||||
'hooks' => [],
|
||||
'options' => [],
|
||||
'pages' => [],
|
||||
'pageMethods' => [],
|
||||
'pageModels' => [],
|
||||
'pagesMethods' => [],
|
||||
'pageModels' => [],
|
||||
'routes' => [],
|
||||
'sections' => [],
|
||||
'siteMethods' => [],
|
||||
@@ -53,6 +65,9 @@ trait AppPlugins
|
||||
'tags' => [],
|
||||
'templates' => [],
|
||||
'translations' => [],
|
||||
'userMethods' => [],
|
||||
'userModels' => [],
|
||||
'usersMethods' => [],
|
||||
'validators' => []
|
||||
];
|
||||
|
||||
@@ -69,7 +84,7 @@ trait AppPlugins
|
||||
*
|
||||
* @internal
|
||||
* @param array $extensions
|
||||
* @param Plugin $plugin The plugin which defined those extensions
|
||||
* @param Kirby\Cms\Plugin $plugin The plugin which defined those extensions
|
||||
* @return array
|
||||
*/
|
||||
public function extend(array $extensions, Plugin $plugin = null): array
|
||||
@@ -83,6 +98,12 @@ trait AppPlugins
|
||||
return $this->extensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers API extensions
|
||||
*
|
||||
* @param array|bool $api
|
||||
* @return array
|
||||
*/
|
||||
protected function extendApi($api): array
|
||||
{
|
||||
if (is_array($api) === true) {
|
||||
@@ -96,56 +117,133 @@ trait AppPlugins
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers additional blueprints
|
||||
*
|
||||
* @param array $blueprints
|
||||
* @return array
|
||||
*/
|
||||
protected function extendBlueprints(array $blueprints): array
|
||||
{
|
||||
return $this->extensions['blueprints'] = array_merge($this->extensions['blueprints'], $blueprints);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers additional cache types
|
||||
*
|
||||
* @param array $cacheTypes
|
||||
* @return array
|
||||
*/
|
||||
protected function extendCacheTypes(array $cacheTypes): array
|
||||
{
|
||||
return $this->extensions['cacheTypes'] = array_merge($this->extensions['cacheTypes'], $cacheTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers additional collection filters
|
||||
*
|
||||
* @param array $filters
|
||||
* @return array
|
||||
*/
|
||||
protected function extendCollectionFilters(array $filters): array
|
||||
{
|
||||
return $this->extensions['collectionFilters'] = Collection::$filters = array_merge(Collection::$filters, $filters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers additional collections
|
||||
*
|
||||
* @param array $collections
|
||||
* @return array
|
||||
*/
|
||||
protected function extendCollections(array $collections): array
|
||||
{
|
||||
return $this->extensions['collections'] = array_merge($this->extensions['collections'], $collections);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers core components
|
||||
*
|
||||
* @param array $components
|
||||
* @return array
|
||||
*/
|
||||
protected function extendComponents(array $components): array
|
||||
{
|
||||
return $this->extensions['components'] = array_merge($this->extensions['components'], $components);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers additional controllers
|
||||
*
|
||||
* @param array $controllers
|
||||
* @return array
|
||||
*/
|
||||
protected function extendControllers(array $controllers): array
|
||||
{
|
||||
return $this->extensions['controllers'] = array_merge($this->extensions['controllers'], $controllers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers additional file methods
|
||||
*
|
||||
* @param array $methods
|
||||
* @return array
|
||||
*/
|
||||
protected function extendFileMethods(array $methods): array
|
||||
{
|
||||
return $this->extensions['fileMethods'] = File::$methods = array_merge(File::$methods, $methods);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers additional files methods
|
||||
*
|
||||
* @param array $methods
|
||||
* @return array
|
||||
*/
|
||||
protected function extendFilesMethods(array $methods): array
|
||||
{
|
||||
return $this->extensions['filesMethods'] = Files::$methods = array_merge(Files::$methods, $methods);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers additional file models
|
||||
*
|
||||
* @param array $models
|
||||
* @return array
|
||||
*/
|
||||
protected function extendFileModels(array $models): array
|
||||
{
|
||||
return $this->extensions['fileModels'] = File::$models = array_merge(File::$models, $models);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers additional field methods
|
||||
*
|
||||
* @param array $methods
|
||||
* @return array
|
||||
*/
|
||||
protected function extendFieldMethods(array $methods): array
|
||||
{
|
||||
return $this->extensions['fieldMethods'] = Field::$methods = array_merge(Field::$methods, array_change_key_case($methods));
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers Panel fields
|
||||
*
|
||||
* @param array $fields
|
||||
* @return array
|
||||
*/
|
||||
protected function extendFields(array $fields): array
|
||||
{
|
||||
return $this->extensions['fields'] = FormField::$types = array_merge(FormField::$types, $fields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers hooks
|
||||
*
|
||||
* @param array $hooks
|
||||
* @return array
|
||||
*/
|
||||
protected function extendHooks(array $hooks): array
|
||||
{
|
||||
foreach ($hooks as $name => $callbacks) {
|
||||
@@ -165,11 +263,24 @@ trait AppPlugins
|
||||
return $this->extensions['hooks'];
|
||||
}
|
||||
|
||||
protected function extendMarkdown(Closure $markdown): array
|
||||
/**
|
||||
* Registers markdown component
|
||||
*
|
||||
* @param Closure $blueprints
|
||||
* @return Closure
|
||||
*/
|
||||
protected function extendMarkdown(Closure $markdown)
|
||||
{
|
||||
return $this->extensions['markdown'] = $markdown;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers additional options
|
||||
*
|
||||
* @param array $options
|
||||
* @param Kirby\Cms\Plugin|null $plugin
|
||||
* @return array
|
||||
*/
|
||||
protected function extendOptions(array $options, Plugin $plugin = null): array
|
||||
{
|
||||
if ($plugin !== null) {
|
||||
@@ -185,21 +296,45 @@ trait AppPlugins
|
||||
return $this->extensions['options'] = $this->options = A::merge($options, $this->options, A::MERGE_REPLACE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers additional page methods
|
||||
*
|
||||
* @param array $methods
|
||||
* @return array
|
||||
*/
|
||||
protected function extendPageMethods(array $methods): array
|
||||
{
|
||||
return $this->extensions['pageMethods'] = Page::$methods = array_merge(Page::$methods, $methods);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers additional pages methods
|
||||
*
|
||||
* @param array $methods
|
||||
* @return array
|
||||
*/
|
||||
protected function extendPagesMethods(array $methods): array
|
||||
{
|
||||
return $this->extensions['pagesMethods'] = Pages::$methods = array_merge(Pages::$methods, $methods);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers additional page models
|
||||
*
|
||||
* @param array $models
|
||||
* @return array
|
||||
*/
|
||||
protected function extendPageModels(array $models): array
|
||||
{
|
||||
return $this->extensions['pageModels'] = Page::$models = array_merge(Page::$models, $models);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers pages
|
||||
*
|
||||
* @param array $pages
|
||||
* @return array
|
||||
*/
|
||||
protected function extendPages(array $pages): array
|
||||
{
|
||||
return $this->extensions['pages'] = array_merge($this->extensions['pages'], $pages);
|
||||
@@ -220,41 +355,122 @@ trait AppPlugins
|
||||
return $this->extensions['routes'] = array_merge($this->extensions['routes'], $routes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers Panel sections
|
||||
*
|
||||
* @param array $sections
|
||||
* @return array
|
||||
*/
|
||||
protected function extendSections(array $sections): array
|
||||
{
|
||||
return $this->extensions['sections'] = Section::$types = array_merge(Section::$types, $sections);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers additional site methods
|
||||
*
|
||||
* @param array $methods
|
||||
* @return array
|
||||
*/
|
||||
protected function extendSiteMethods(array $methods): array
|
||||
{
|
||||
return $this->extensions['siteMethods'] = Site::$methods = array_merge(Site::$methods, $methods);
|
||||
}
|
||||
|
||||
protected function extendSmartypants(Closure $smartypants): array
|
||||
/**
|
||||
* Registers SmartyPants component
|
||||
*
|
||||
* @param Closure $smartypants
|
||||
* @return Closure
|
||||
*/
|
||||
protected function extendSmartypants(Closure $smartypants)
|
||||
{
|
||||
return $this->extensions['smartypants'] = $smartypants;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers additional snippets
|
||||
*
|
||||
* @param array $snippets
|
||||
* @return array
|
||||
*/
|
||||
protected function extendSnippets(array $snippets): array
|
||||
{
|
||||
return $this->extensions['snippets'] = array_merge($this->extensions['snippets'], $snippets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers additional KirbyTags
|
||||
*
|
||||
* @param array $tags
|
||||
* @return array
|
||||
*/
|
||||
protected function extendTags(array $tags): array
|
||||
{
|
||||
return $this->extensions['tags'] = KirbyTag::$types = array_merge(KirbyTag::$types, $tags);
|
||||
return $this->extensions['tags'] = KirbyTag::$types = array_merge(KirbyTag::$types, array_change_key_case($tags));
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers additional templates
|
||||
*
|
||||
* @param array $templates
|
||||
* @return array
|
||||
*/
|
||||
protected function extendTemplates(array $templates): array
|
||||
{
|
||||
return $this->extensions['templates'] = array_merge($this->extensions['templates'], $templates);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers translations
|
||||
*
|
||||
* @param array $translations
|
||||
* @return array
|
||||
*/
|
||||
protected function extendTranslations(array $translations): array
|
||||
{
|
||||
return $this->extensions['translations'] = array_replace_recursive($this->extensions['translations'], $translations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers additional user methods
|
||||
*
|
||||
* @param array $methods
|
||||
* @return array
|
||||
*/
|
||||
protected function extendUserMethods(array $methods): array
|
||||
{
|
||||
return $this->extensions['userMethods'] = User::$methods = array_merge(User::$methods, $methods);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers additional user models
|
||||
*
|
||||
* @param array $models
|
||||
* @return array
|
||||
*/
|
||||
protected function extendUserModels(array $models): array
|
||||
{
|
||||
return $this->extensions['userModels'] = User::$models = array_merge(User::$models, $models);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers additional users methods
|
||||
*
|
||||
* @param array $methods
|
||||
* @return array
|
||||
*/
|
||||
protected function extendUsersMethods(array $methods): array
|
||||
{
|
||||
return $this->extensions['usersMethods'] = Users::$methods = array_merge(Users::$methods, $methods);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers additional custom validators
|
||||
*
|
||||
* @param array $validators
|
||||
* @return array
|
||||
*/
|
||||
protected function extendValidators(array $validators): array
|
||||
{
|
||||
return $this->extensions['validators'] = V::$validators = array_merge(V::$validators, $validators);
|
||||
@@ -367,8 +583,13 @@ trait AppPlugins
|
||||
protected function extensionsFromSystem()
|
||||
{
|
||||
// Form Field Mixins
|
||||
FormField::$mixins['min'] = include static::$root . '/config/fields/mixins/min.php';
|
||||
FormField::$mixins['options'] = include static::$root . '/config/fields/mixins/options.php';
|
||||
FormField::$mixins['filepicker'] = include static::$root . '/config/fields/mixins/filepicker.php';
|
||||
FormField::$mixins['min'] = include static::$root . '/config/fields/mixins/min.php';
|
||||
FormField::$mixins['options'] = include static::$root . '/config/fields/mixins/options.php';
|
||||
FormField::$mixins['pagepicker'] = include static::$root . '/config/fields/mixins/pagepicker.php';
|
||||
FormField::$mixins['picker'] = include static::$root . '/config/fields/mixins/picker.php';
|
||||
FormField::$mixins['upload'] = include static::$root . '/config/fields/mixins/upload.php';
|
||||
FormField::$mixins['userpicker'] = include static::$root . '/config/fields/mixins/userpicker.php';
|
||||
|
||||
// Tag Aliases
|
||||
KirbyTag::$aliases = [
|
||||
@@ -398,6 +619,7 @@ trait AppPlugins
|
||||
'apcu' => 'Kirby\Cache\ApcuCache',
|
||||
'file' => 'Kirby\Cache\FileCache',
|
||||
'memcached' => 'Kirby\Cache\MemCached',
|
||||
'memory' => 'Kirby\Cache\MemoryCache',
|
||||
]);
|
||||
|
||||
$this->extendComponents(include static::$root . '/config/components.php');
|
||||
@@ -433,7 +655,7 @@ trait AppPlugins
|
||||
*
|
||||
* @param string $name
|
||||
* @param array|null $extends If null is passed it will be used as getter. Otherwise as factory.
|
||||
* @return Plugin|null
|
||||
* @return Kirby\Cms\Plugin|null
|
||||
*/
|
||||
public static function plugin(string $name, array $extends = null)
|
||||
{
|
||||
|
@@ -2,8 +2,20 @@
|
||||
|
||||
namespace Kirby\Cms;
|
||||
|
||||
use Kirby\Data\Data;
|
||||
use Kirby\Toolkit\F;
|
||||
use Kirby\Toolkit\I18n;
|
||||
use Kirby\Toolkit\Str;
|
||||
|
||||
/**
|
||||
* AppTranslations
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
trait AppTranslations
|
||||
{
|
||||
protected $translations;
|
||||
@@ -13,9 +25,9 @@ trait AppTranslations
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function i18n()
|
||||
protected function i18n(): void
|
||||
{
|
||||
I18n::$load = function ($locale) {
|
||||
I18n::$load = function ($locale): array {
|
||||
$data = [];
|
||||
|
||||
if ($translation = $this->translation($locale)) {
|
||||
@@ -25,12 +37,16 @@ trait AppTranslations
|
||||
// inject translations from the current language
|
||||
if ($this->multilang() === true && $language = $this->languages()->find($locale)) {
|
||||
$data = array_merge($data, $language->translations());
|
||||
|
||||
// Add language slug rules to Str class
|
||||
Str::$language = $language->rules();
|
||||
}
|
||||
|
||||
|
||||
return $data;
|
||||
};
|
||||
|
||||
I18n::$locale = function () {
|
||||
I18n::$locale = function (): string {
|
||||
if ($this->multilang() === true) {
|
||||
return $this->defaultLanguage()->code();
|
||||
} else {
|
||||
@@ -38,7 +54,7 @@ trait AppTranslations
|
||||
}
|
||||
};
|
||||
|
||||
I18n::$fallback = function () {
|
||||
I18n::$fallback = function (): string {
|
||||
if ($this->multilang() === true) {
|
||||
return $this->defaultLanguage()->code();
|
||||
} else {
|
||||
@@ -47,6 +63,20 @@ trait AppTranslations
|
||||
};
|
||||
|
||||
I18n::$translations = [];
|
||||
|
||||
if (isset($this->options['slugs']) === true) {
|
||||
$file = $this->root('i18n:rules') . '/' . $this->options['slugs'] . '.json';
|
||||
|
||||
if (F::exists($file) === true) {
|
||||
try {
|
||||
$data = Data::read($file);
|
||||
} catch (\Exception $e) {
|
||||
$data = [];
|
||||
}
|
||||
|
||||
Str::$language = $data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -55,7 +85,7 @@ trait AppTranslations
|
||||
*
|
||||
* @internal
|
||||
* @param string $languageCode
|
||||
* @return Language|null
|
||||
* @return Kirby\Cms\Language|null
|
||||
*/
|
||||
public function setCurrentLanguage(string $languageCode = null)
|
||||
{
|
||||
@@ -84,7 +114,7 @@ trait AppTranslations
|
||||
* @param string $translationCode
|
||||
* @return void
|
||||
*/
|
||||
public function setCurrentTranslation(string $translationCode = null)
|
||||
public function setCurrentTranslation(string $translationCode = null): void
|
||||
{
|
||||
I18n::$locale = $translationCode ?? 'en';
|
||||
}
|
||||
@@ -95,7 +125,7 @@ trait AppTranslations
|
||||
* @internal
|
||||
* @param string|array $locale
|
||||
*/
|
||||
public function setLocale($locale)
|
||||
public function setLocale($locale): void
|
||||
{
|
||||
if (is_array($locale) === true) {
|
||||
foreach ($locale as $key => $value) {
|
||||
@@ -110,7 +140,7 @@ trait AppTranslations
|
||||
* Load a specific translation by locale
|
||||
*
|
||||
* @param string|null $locale
|
||||
* @return Translation|null
|
||||
* @return Kirby\Cms\Translation|null
|
||||
*/
|
||||
public function translation(string $locale = null)
|
||||
{
|
||||
@@ -134,7 +164,7 @@ trait AppTranslations
|
||||
/**
|
||||
* Returns all available translations
|
||||
*
|
||||
* @return Translations
|
||||
* @return Kirby\Cms\Translations
|
||||
*/
|
||||
public function translations()
|
||||
{
|
||||
|
@@ -2,6 +2,15 @@
|
||||
|
||||
namespace Kirby\Cms;
|
||||
|
||||
/**
|
||||
* AppUsers
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
trait AppUsers
|
||||
{
|
||||
|
||||
@@ -16,7 +25,7 @@ trait AppUsers
|
||||
* Returns the Authentication layer class
|
||||
*
|
||||
* @internal
|
||||
* @return Auth
|
||||
* @return Kirby\Cms\Auth
|
||||
*/
|
||||
public function auth()
|
||||
{
|
||||
@@ -27,7 +36,7 @@ trait AppUsers
|
||||
* Become any existing user
|
||||
*
|
||||
* @param string|null $who
|
||||
* @return self
|
||||
* @return Kirby\Cms\User|null
|
||||
*/
|
||||
public function impersonate(string $who = null)
|
||||
{
|
||||
@@ -37,10 +46,10 @@ trait AppUsers
|
||||
/**
|
||||
* Set the currently active user id
|
||||
*
|
||||
* @param User|string $user
|
||||
* @return self
|
||||
* @param Kirby\Cms\User|string $user
|
||||
* @return Kirby\Cms\App
|
||||
*/
|
||||
protected function setUser($user = null): self
|
||||
protected function setUser($user = null)
|
||||
{
|
||||
$this->user = $user;
|
||||
return $this;
|
||||
@@ -50,9 +59,9 @@ trait AppUsers
|
||||
* Create your own set of app users
|
||||
*
|
||||
* @param array $users
|
||||
* @return self
|
||||
* @return Kirby\Cms\App
|
||||
*/
|
||||
protected function setUsers(array $users = null): self
|
||||
protected function setUsers(array $users = null)
|
||||
{
|
||||
if ($users !== null) {
|
||||
$this->users = Users::factory($users, [
|
||||
@@ -67,11 +76,10 @@ trait AppUsers
|
||||
* Returns a specific user by id
|
||||
* or the current user if no id is given
|
||||
*
|
||||
* @param string $id
|
||||
* @param \Kirby\Session\Session|array $session Session options or session object for getting the current user
|
||||
* @return User|null
|
||||
* @param string $id
|
||||
* @return Kirby\Cms\User|null
|
||||
*/
|
||||
public function user(string $id = null, $session = null)
|
||||
public function user(string $id = null)
|
||||
{
|
||||
if ($id !== null) {
|
||||
return $this->users()->find($id);
|
||||
@@ -87,9 +95,9 @@ trait AppUsers
|
||||
/**
|
||||
* Returns all users
|
||||
*
|
||||
* @return Users
|
||||
* @return Kirby\Cms\Users
|
||||
*/
|
||||
public function users(): Users
|
||||
public function users()
|
||||
{
|
||||
if (is_a($this->users, 'Kirby\Cms\Users') === true) {
|
||||
return $this->users;
|
||||
|
@@ -10,6 +10,12 @@ use Kirby\Toolkit\Properties;
|
||||
* methods and thumbnail generation as for any other
|
||||
* Kirby files. Pass a relative path to the Asset
|
||||
* object to create the asset.
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class Asset
|
||||
{
|
||||
|
@@ -7,11 +7,16 @@ use Kirby\Exception\PermissionException;
|
||||
use Kirby\Exception\InvalidArgumentException;
|
||||
use Kirby\Exception\NotFoundException;
|
||||
use Kirby\Http\Request\Auth\BasicAuth;
|
||||
use Kirby\Session\Session;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Authentication layer
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class Auth
|
||||
{
|
||||
@@ -20,7 +25,7 @@ class Auth
|
||||
protected $user;
|
||||
|
||||
/**
|
||||
* @param App $kirby
|
||||
* @param Kirby\Cms\App $kirby
|
||||
*/
|
||||
public function __construct(App $kirby)
|
||||
{
|
||||
@@ -53,8 +58,8 @@ class Auth
|
||||
* for a basic authentication header with
|
||||
* valid credentials
|
||||
*
|
||||
* @param BasicAuth|null $auth
|
||||
* @return User|null
|
||||
* @param Kirby\Http\Request\Auth\BasicAuth|null $auth
|
||||
* @return Kirby\Cms\User|null
|
||||
*/
|
||||
public function currentUserFromBasicAuth(BasicAuth $auth = null)
|
||||
{
|
||||
@@ -88,13 +93,13 @@ class Auth
|
||||
* the current session and finding a valid
|
||||
* valid user id in there
|
||||
*
|
||||
* @param Session|null $session
|
||||
* @return User|null
|
||||
* @param Kirby\Cms\Session|array|null $session
|
||||
* @return Kirby\Cms\User|null
|
||||
*/
|
||||
public function currentUserFromSession($session = null)
|
||||
{
|
||||
// use passed session options or session object if set
|
||||
if (is_array($session)) {
|
||||
if (is_array($session) === true) {
|
||||
$session = $this->kirby->session($session);
|
||||
}
|
||||
|
||||
@@ -123,7 +128,7 @@ class Auth
|
||||
* Become any existing user
|
||||
*
|
||||
* @param string|null $who
|
||||
* @return User|null
|
||||
* @return Kirby\Cms\User|null
|
||||
*/
|
||||
public function impersonate(string $who = null)
|
||||
{
|
||||
@@ -185,7 +190,7 @@ class Auth
|
||||
* @param string $email
|
||||
* @param string $password
|
||||
* @param boolean $long
|
||||
* @return User|false
|
||||
* @return Kirby\Cms\User|false
|
||||
*/
|
||||
public function login(string $email, string $password, bool $long = false)
|
||||
{
|
||||
@@ -311,10 +316,10 @@ class Auth
|
||||
/**
|
||||
* Validates the currently logged in user
|
||||
*
|
||||
* @param array|Session|null $session
|
||||
* @return User|null
|
||||
* @param Kirby\Session\Sessionarray||null $session
|
||||
* @return Kirby\Cms\User|null
|
||||
*/
|
||||
public function user($session = null): ?User
|
||||
public function user($session = null)
|
||||
{
|
||||
if ($this->impersonate !== null) {
|
||||
return $this->impersonate;
|
||||
|
@@ -10,13 +10,18 @@ use Kirby\Form\Field;
|
||||
use Kirby\Toolkit\A;
|
||||
use Kirby\Toolkit\F;
|
||||
use Kirby\Toolkit\I18n;
|
||||
use Kirby\Toolkit\Obj;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* The Blueprint class normalizes an array from a
|
||||
* blueprint file and converts sections, columns, fields
|
||||
* etc. into a correct tab layout.
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class Blueprint
|
||||
{
|
||||
@@ -81,13 +86,13 @@ class Blueprint
|
||||
}
|
||||
|
||||
/**
|
||||
* Improved var_dump output
|
||||
* Improved `var_dump` output
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function __debuginfo(): array
|
||||
{
|
||||
return $this->props;
|
||||
return $this->props ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -217,7 +222,7 @@ class Blueprint
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $fallback
|
||||
* @param Model $model
|
||||
* @param Kirby\Cms\Model $model
|
||||
* @return self
|
||||
*/
|
||||
public static function factory(string $name, string $fallback = null, Model $model)
|
||||
@@ -311,11 +316,9 @@ class Blueprint
|
||||
* Loads a blueprint from file or array
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $fallback
|
||||
* @param Model $model
|
||||
* @return array
|
||||
*/
|
||||
public static function load(string $name)
|
||||
public static function load(string $name): array
|
||||
{
|
||||
if (isset(static::$loaded[$name]) === true) {
|
||||
return static::$loaded[$name];
|
||||
@@ -349,7 +352,7 @@ class Blueprint
|
||||
/**
|
||||
* Returns the parent model
|
||||
*
|
||||
* @return Model
|
||||
* @return Kirby\Cms\Model
|
||||
*/
|
||||
public function model()
|
||||
{
|
||||
@@ -402,7 +405,7 @@ class Blueprint
|
||||
return $columns;
|
||||
}
|
||||
|
||||
public static function helpList(array $items)
|
||||
public static function helpList(array $items): string
|
||||
{
|
||||
$md = [];
|
||||
|
||||
@@ -503,6 +506,12 @@ class Blueprint
|
||||
$fieldProps = [];
|
||||
}
|
||||
|
||||
// unset / remove field if its propperty is false
|
||||
if ($fieldProps === false) {
|
||||
unset($fields[$fieldName]);
|
||||
continue;
|
||||
}
|
||||
|
||||
// inject the name
|
||||
$fieldProps['name'] = $fieldName;
|
||||
|
||||
@@ -580,6 +589,12 @@ class Blueprint
|
||||
{
|
||||
foreach ($sections as $sectionName => $sectionProps) {
|
||||
|
||||
// unset / remove section if its propperty is false
|
||||
if ($sectionProps === false) {
|
||||
unset($sections[$sectionName]);
|
||||
continue;
|
||||
}
|
||||
|
||||
// inject all section extensions
|
||||
$sectionProps = $this->extend($sectionProps);
|
||||
|
||||
@@ -648,6 +663,12 @@ class Blueprint
|
||||
|
||||
foreach ($tabs as $tabName => $tabProps) {
|
||||
|
||||
// unset / remove tab if its propperty is false
|
||||
if ($tabProps === false) {
|
||||
unset($tabs[$tabName]);
|
||||
continue;
|
||||
}
|
||||
|
||||
// inject all tab extensions
|
||||
$tabProps = $this->extend($tabProps);
|
||||
|
||||
@@ -691,9 +712,9 @@ class Blueprint
|
||||
* Returns a single section by name
|
||||
*
|
||||
* @param string $name
|
||||
* @return Section|null
|
||||
* @return Kirby\Cms\Section|null
|
||||
*/
|
||||
public function section(string $name): ?Section
|
||||
public function section(string $name)
|
||||
{
|
||||
if (empty($this->sections[$name]) === true) {
|
||||
return null;
|
||||
|
@@ -19,8 +19,9 @@ use Kirby\Toolkit\Str;
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link http://getkirby.com
|
||||
* @copyright Bastian Allgeier
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class Collection extends BaseCollection
|
||||
{
|
||||
@@ -100,9 +101,9 @@ class Collection extends BaseCollection
|
||||
/**
|
||||
* Appends an element to the data array
|
||||
*
|
||||
* @param mixed $key
|
||||
* @param mixed $item
|
||||
* @return Collection
|
||||
* @param mixed $key
|
||||
* @param mixed $item
|
||||
* @return Kirby\Cms\Collection
|
||||
*/
|
||||
public function append(...$args)
|
||||
{
|
||||
@@ -120,11 +121,12 @@ class Collection extends BaseCollection
|
||||
}
|
||||
|
||||
/**
|
||||
* Groups the items by a given field
|
||||
* Groups the items by a given field. Returns a collection
|
||||
* with an item for each group and a collection for each group.
|
||||
*
|
||||
* @param string $field
|
||||
* @param bool $i (ignore upper/lowercase for group names)
|
||||
* @return Collection A collection with an item for each group and a Collection for each group
|
||||
* @param bool $i Ignore upper/lowercase for group names
|
||||
* @return Kirby\Cms\Collection
|
||||
*/
|
||||
public function groupBy($field, bool $i = true)
|
||||
{
|
||||
@@ -195,8 +197,8 @@ class Collection extends BaseCollection
|
||||
/**
|
||||
* Returns a Collection without the given element(s)
|
||||
*
|
||||
* @param args any number of keys, passed as individual arguments
|
||||
* @return Collection
|
||||
* @param mixxed[] $keys any number of keys, passed as individual arguments
|
||||
* @return Kirby\Cms\Collection
|
||||
*/
|
||||
public function not(...$keys)
|
||||
{
|
||||
@@ -213,9 +215,9 @@ class Collection extends BaseCollection
|
||||
}
|
||||
|
||||
/**
|
||||
* Add pagination
|
||||
* Add pagination and return a sliced set of data.
|
||||
*
|
||||
* @return Collection a sliced set of data
|
||||
* @return Kirby\Cms\Collection
|
||||
*/
|
||||
public function paginate(...$arguments)
|
||||
{
|
||||
@@ -228,7 +230,7 @@ class Collection extends BaseCollection
|
||||
/**
|
||||
* Returns the parent model
|
||||
*
|
||||
* @return Model
|
||||
* @return Kirby\Cms\Model
|
||||
*/
|
||||
public function parent()
|
||||
{
|
||||
|
@@ -2,7 +2,6 @@
|
||||
|
||||
namespace Kirby\Cms;
|
||||
|
||||
use Closure;
|
||||
use Kirby\Exception\NotFoundException;
|
||||
use Kirby\Toolkit\Controller;
|
||||
|
||||
@@ -16,8 +15,9 @@ use Kirby\Toolkit\Controller;
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link http://getkirby.com
|
||||
* @copyright Bastian Allgeier
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class Collections
|
||||
{
|
||||
@@ -45,7 +45,7 @@ class Collections
|
||||
*
|
||||
* @param string $name
|
||||
* @param array $arguments
|
||||
* @return Collection|null
|
||||
* @return Kirby\Cms\Collection|null
|
||||
*/
|
||||
public function __call(string $name, array $arguments = [])
|
||||
{
|
||||
@@ -57,7 +57,7 @@ class Collections
|
||||
*
|
||||
* @param string $name
|
||||
* @param array $data
|
||||
* @return Collection|null
|
||||
* @return Kirby\Cms\Collection|null
|
||||
*/
|
||||
public function get(string $name, array $data = [])
|
||||
{
|
||||
|
@@ -2,16 +2,15 @@
|
||||
|
||||
namespace Kirby\Cms;
|
||||
|
||||
use Closure;
|
||||
|
||||
/**
|
||||
* The Content class handles all fields
|
||||
* for content from pages, the site and users
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link http://getkirby.com
|
||||
* @copyright Bastian Allgeier
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class Content
|
||||
{
|
||||
@@ -39,7 +38,7 @@ class Content
|
||||
* for testing, but field methods might
|
||||
* need it.
|
||||
*
|
||||
* @var Page|File|User|Site
|
||||
* @var Model
|
||||
*/
|
||||
protected $parent;
|
||||
|
||||
@@ -48,9 +47,9 @@ class Content
|
||||
*
|
||||
* @param string $name
|
||||
* @param array $arguments
|
||||
* @return Field
|
||||
* @return Kirby\Cms\Field
|
||||
*/
|
||||
public function __call(string $name, array $arguments = []): Field
|
||||
public function __call(string $name, array $arguments = [])
|
||||
{
|
||||
return $this->get($name);
|
||||
}
|
||||
@@ -58,10 +57,10 @@ class Content
|
||||
/**
|
||||
* Creates a new Content object
|
||||
*
|
||||
* @param array $data
|
||||
* @param object $parent
|
||||
* @param array|null $data
|
||||
* @param object|null $parent
|
||||
*/
|
||||
public function __construct($data = [], $parent = null)
|
||||
public function __construct(array $data = [], $parent = null)
|
||||
{
|
||||
$this->data = $data;
|
||||
$this->parent = $parent;
|
||||
@@ -69,7 +68,7 @@ class Content
|
||||
|
||||
/**
|
||||
* Same as `self::data()` to improve
|
||||
* var_dump output
|
||||
* `var_dump` output
|
||||
*
|
||||
* @see self::data()
|
||||
* @return array
|
||||
@@ -149,7 +148,7 @@ class Content
|
||||
* or all registered fields
|
||||
*
|
||||
* @param string $key
|
||||
* @return Field|array
|
||||
* @return Kirby\Cms\Field|array
|
||||
*/
|
||||
public function get(string $key = null)
|
||||
{
|
||||
@@ -202,7 +201,7 @@ class Content
|
||||
* @param string ...$keys
|
||||
* @return self
|
||||
*/
|
||||
public function not(...$keys): self
|
||||
public function not(...$keys)
|
||||
{
|
||||
$copy = clone $this;
|
||||
$copy->fields = null;
|
||||
@@ -218,7 +217,7 @@ class Content
|
||||
* Returns the parent
|
||||
* Site, Page, File or User object
|
||||
*
|
||||
* @return Site|Page|File|User
|
||||
* @return Kirby\Cms\Model
|
||||
*/
|
||||
public function parent()
|
||||
{
|
||||
@@ -228,10 +227,10 @@ class Content
|
||||
/**
|
||||
* Set the parent model
|
||||
*
|
||||
* @param Model $parent
|
||||
* @param Kirby\Cms\Model $parent
|
||||
* @return self
|
||||
*/
|
||||
public function setParent(Model $parent): self
|
||||
public function setParent(Model $parent)
|
||||
{
|
||||
$this->parent = $parent;
|
||||
return $this;
|
||||
@@ -256,7 +255,7 @@ class Content
|
||||
* @param bool $overwrite
|
||||
* @return self
|
||||
*/
|
||||
public function update(array $content = null, bool $overwrite = false): self
|
||||
public function update(array $content = null, bool $overwrite = false)
|
||||
{
|
||||
$this->data = $overwrite === true ? (array)$content : array_merge($this->data, (array)$content);
|
||||
return $this;
|
||||
|
220
kirby/src/Cms/ContentLock.php
Executable file
220
kirby/src/Cms/ContentLock.php
Executable file
@@ -0,0 +1,220 @@
|
||||
<?php
|
||||
|
||||
namespace Kirby\Cms;
|
||||
|
||||
use Kirby\Exception\DuplicateException;
|
||||
use Kirby\Exception\LogicException;
|
||||
use Kirby\Exception\PermissionException;
|
||||
|
||||
/**
|
||||
* Takes care of content lock and unlock information
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Nico Hoffmann <nico@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class ContentLock
|
||||
{
|
||||
|
||||
/**
|
||||
* Lock data
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $data;
|
||||
|
||||
/**
|
||||
* The model to manage locking/unlocking for
|
||||
*
|
||||
* @var ModelWithContent
|
||||
*/
|
||||
protected $model;
|
||||
|
||||
/**
|
||||
* @param Kirby\Cms\ModelWithContent $model
|
||||
*/
|
||||
public function __construct(ModelWithContent $model)
|
||||
{
|
||||
$this->model = $model;
|
||||
$this->data = $this->kirby()->locks()->get($model);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets lock with the current user
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function create(): bool
|
||||
{
|
||||
// check if model is already locked by another user
|
||||
if (
|
||||
isset($this->data['lock']) === true &&
|
||||
$this->data['lock']['user'] !== $this->user()->id()
|
||||
) {
|
||||
$id = ContentLocks::id($this->model);
|
||||
throw new DuplicateException($id . ' is already locked');
|
||||
}
|
||||
|
||||
$this->data['lock'] = [
|
||||
'user' => $this->user()->id(),
|
||||
'time' => time()
|
||||
];
|
||||
|
||||
return $this->kirby()->locks()->set($this->model, $this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns array with `locked` flag and,
|
||||
* if needed, `user`, `email`, `time`, `canUnlock`
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get(): array
|
||||
{
|
||||
$data = $this->data['lock'] ?? [];
|
||||
|
||||
if (
|
||||
empty($data) === false &&
|
||||
$data['user'] !== $this->user()->id() &&
|
||||
$user = $this->kirby()->user($data['user'])
|
||||
) {
|
||||
$time = intval($data['time']);
|
||||
|
||||
return [
|
||||
'locked' => true,
|
||||
'user' => $user->id(),
|
||||
'email' => $user->email(),
|
||||
'time' => $time,
|
||||
'canUnlock' => $time + $this->kirby()->option('lock.duration', 60 * 2) <= time()
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'locked' => false
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if the model is locked by another user
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isLocked(): bool
|
||||
{
|
||||
$lock = $this->get();
|
||||
|
||||
if (
|
||||
$lock['locked'] === true &&
|
||||
$lock['user'] !== $this->user()->id()
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if the current user's lock has been removed by another user
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isUnlocked(): bool
|
||||
{
|
||||
$data = $this->data['unlock'] ?? [];
|
||||
|
||||
return in_array($this->user()->id(), $data) === true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the app instance
|
||||
*
|
||||
* @return Kirby\Cms\App
|
||||
*/
|
||||
protected function kirby(): App
|
||||
{
|
||||
return $this->model->kirby();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes lock of current user
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function remove(): bool
|
||||
{
|
||||
// if no lock exists, skip
|
||||
if (isset($this->data['lock']) === false) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// check if lock was set by another user
|
||||
if ($this->data['lock']['user'] !== $this->user()->id()) {
|
||||
throw new LogicException('The content lock can only be removed by the user who created it. Use unlock instead.', 409);
|
||||
}
|
||||
|
||||
// remove lock
|
||||
unset($this->data['lock']);
|
||||
|
||||
return $this->kirby()->locks()->set($this->model, $this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes unlock information for current user
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function resolve(): bool
|
||||
{
|
||||
// if no unlocks exist, skip
|
||||
if (isset($this->data['unlock']) === false) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// remove user from unlock array
|
||||
$this->data['unlock'] = array_diff(
|
||||
$this->data['unlock'],
|
||||
[$this->user()->id()]
|
||||
);
|
||||
|
||||
return $this->kirby()->locks()->set($this->model, $this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes current lock and adds lock user to unlock data
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function unlock(): bool
|
||||
{
|
||||
// if no lock exists, skip
|
||||
if (isset($this->data['lock']) === false) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// add lock user to unlocked data
|
||||
$this->data['unlock'] = $this->data['unlock'] ?? [];
|
||||
$this->data['unlock'][] = $this->data['lock']['user'];
|
||||
|
||||
// remove lock
|
||||
unset($this->data['lock']);
|
||||
|
||||
return $this->kirby()->locks()->set($this->model, $this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns currently authenticated user;
|
||||
* throws exception if none is authenticated
|
||||
*
|
||||
* @return Kirby\Cms\User
|
||||
*/
|
||||
protected function user(): User
|
||||
{
|
||||
if ($user = $this->kirby()->user()) {
|
||||
return $user;
|
||||
}
|
||||
|
||||
throw new PermissionException('No user authenticated.');
|
||||
}
|
||||
}
|
226
kirby/src/Cms/ContentLocks.php
Executable file
226
kirby/src/Cms/ContentLocks.php
Executable file
@@ -0,0 +1,226 @@
|
||||
<?php
|
||||
|
||||
namespace Kirby\Cms;
|
||||
|
||||
use Kirby\Data\Yaml;
|
||||
use Kirby\Exception\Exception;
|
||||
use Kirby\Toolkit\F;
|
||||
|
||||
/**
|
||||
* Manages all content lock files
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Nico Hoffmann <nico@getkirby.com>,
|
||||
* Lukas Bestle <lukas@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class ContentLocks
|
||||
{
|
||||
|
||||
/**
|
||||
* Data from the `.lock` files
|
||||
* that have been read so far
|
||||
* cached by `.lock` file path
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $data = [];
|
||||
|
||||
/**
|
||||
* PHP file handles for all currently
|
||||
* open `.lock` files
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $handles = [];
|
||||
|
||||
/**
|
||||
* Closes the open file handles
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
foreach ($this->handles as $file => $handle) {
|
||||
$this->closeHandle($file);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the file lock and closes the file handle
|
||||
*
|
||||
* @param string $file
|
||||
* @return void
|
||||
*/
|
||||
protected function closeHandle(string $file)
|
||||
{
|
||||
if (isset($this->handles[$file]) === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
$handle = $this->handles[$file];
|
||||
$result = flock($handle, LOCK_UN) && fclose($handle);
|
||||
|
||||
if ($result !== true) {
|
||||
throw new Exception('Unexpected file system error.'); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
unset($this->handles[$file]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path to a model's lock file
|
||||
*
|
||||
* @param Kirby\Cms\ModelWithContent $model
|
||||
* @return string
|
||||
*/
|
||||
public static function file(ModelWithContent $model): string
|
||||
{
|
||||
return $model->contentFileDirectory() . '/.lock';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the lock/unlock data for the specified model
|
||||
*
|
||||
* @param Kirby\Cms\ModelWithContent $model
|
||||
* @return array
|
||||
*/
|
||||
public function get(ModelWithContent $model): array
|
||||
{
|
||||
$file = static::file($model);
|
||||
$id = static::id($model);
|
||||
|
||||
// return from cache if file was already loaded
|
||||
if (isset($this->data[$file]) === true) {
|
||||
return $this->data[$file][$id] ?? [];
|
||||
}
|
||||
|
||||
// first get a handle to ensure a file system lock
|
||||
$handle = $this->handle($file);
|
||||
|
||||
if (is_resource($handle) === true) {
|
||||
// read data from file
|
||||
clearstatcache();
|
||||
$filesize = filesize($file);
|
||||
|
||||
if ($filesize > 0) {
|
||||
// always read the whole file
|
||||
rewind($handle);
|
||||
$string = fread($handle, $filesize);
|
||||
$data = Yaml::decode($string);
|
||||
}
|
||||
}
|
||||
|
||||
$this->data[$file] = $data ?? [];
|
||||
|
||||
return $this->data[$file][$id] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file handle to a `.lock` file
|
||||
*
|
||||
* @param string $file
|
||||
* @param boolean $create Whether to create the file if it does not exist
|
||||
* @return resource|null File handle
|
||||
*/
|
||||
protected function handle(string $file, bool $create = false)
|
||||
{
|
||||
// check for an already open handle
|
||||
if (isset($this->handles[$file]) === true) {
|
||||
return $this->handles[$file];
|
||||
}
|
||||
|
||||
// don't create a file if not requested
|
||||
if (is_file($file) !== true && $create !== true) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$handle = @fopen($file, 'c+b');
|
||||
if (is_resource($handle) === false) {
|
||||
throw new Exception('Lock file ' . $file . ' could not be opened.'); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
// lock the lock file exclusively to prevent changes by other threads
|
||||
$result = flock($handle, LOCK_EX);
|
||||
if ($result !== true) {
|
||||
throw new Exception('Unexpected file system error.'); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
return $this->handles[$file] = $handle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns model ID used as the key for the data array;
|
||||
* prepended with a slash because the $site otherwise won't have an ID
|
||||
*
|
||||
* @param Kirby\Cms\ModelWithContent $model
|
||||
* @return string
|
||||
*/
|
||||
public static function id(ModelWithContent $model): string
|
||||
{
|
||||
return '/' . $model->id();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets and writes the lock/unlock data for the specified model
|
||||
*
|
||||
* @param Kirby\Cms\ModelWithContent $model
|
||||
* @param array $data
|
||||
* @return boolean
|
||||
*/
|
||||
public function set(ModelWithContent $model, array $data): bool
|
||||
{
|
||||
$file = static::file($model);
|
||||
$id = static::id($model);
|
||||
$handle = $this->handle($file, true);
|
||||
|
||||
$this->data[$file][$id] = $data;
|
||||
|
||||
// make sure to unset model id entries,
|
||||
// if no lock data for the model exists
|
||||
foreach ($this->data[$file] as $id => $data) {
|
||||
// there is no data for that model whatsoever
|
||||
if (
|
||||
isset($data['lock']) === false &&
|
||||
(isset($data['unlock']) === false ||
|
||||
count($data['unlock']) === 0)
|
||||
) {
|
||||
unset($this->data[$file][$id]);
|
||||
|
||||
// there is empty unlock data, but still lock data
|
||||
} elseif (
|
||||
isset($data['unlock']) === true &&
|
||||
count($data['unlock']) === 0
|
||||
) {
|
||||
unset($this->data[$file][$id]['unlock']);
|
||||
}
|
||||
}
|
||||
|
||||
// there is no data left in the file whatsoever, delete the file
|
||||
if (count($this->data[$file]) === 0) {
|
||||
unset($this->data[$file]);
|
||||
|
||||
// close the file handle, otherwise we can't delete it on Windows
|
||||
$this->closeHandle($file);
|
||||
|
||||
return F::remove($file);
|
||||
}
|
||||
|
||||
$yaml = Yaml::encode($this->data[$file]);
|
||||
|
||||
// delete all file contents first
|
||||
if (rewind($handle) !== true || ftruncate($handle, 0) !== true) {
|
||||
throw new Exception('Could not write lock file ' . $file . '.'); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
// write the new contents
|
||||
$result = fwrite($handle, $yaml);
|
||||
if (is_int($result) === false || $result === 0) {
|
||||
throw new Exception('Could not write lock file ' . $file . '.'); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -2,16 +2,18 @@
|
||||
|
||||
namespace Kirby\Cms;
|
||||
|
||||
use Exception;
|
||||
use Kirby\Data\Data;
|
||||
use Kirby\Exception\PermissionException;
|
||||
use Kirby\Toolkit\F;
|
||||
use Kirby\Toolkit\Properties;
|
||||
|
||||
/**
|
||||
* Each page, file or site can have multiple
|
||||
* translated versions of their content,
|
||||
* represented by this class
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class ContentTranslation
|
||||
{
|
||||
@@ -33,7 +35,7 @@ class ContentTranslation
|
||||
protected $contentFile;
|
||||
|
||||
/**
|
||||
* @var Page|Site|File
|
||||
* @var Model
|
||||
*/
|
||||
protected $parent;
|
||||
|
||||
@@ -54,7 +56,7 @@ class ContentTranslation
|
||||
}
|
||||
|
||||
/**
|
||||
* Improve var_dump() output
|
||||
* Improve `var_dump` output
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
@@ -127,9 +129,9 @@ class ContentTranslation
|
||||
/**
|
||||
* Returns the translation code as id
|
||||
*
|
||||
* @return void
|
||||
* @return string
|
||||
*/
|
||||
public function id()
|
||||
public function id(): string
|
||||
{
|
||||
return $this->code();
|
||||
}
|
||||
@@ -150,9 +152,9 @@ class ContentTranslation
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parent Page, File or Site object
|
||||
* Returns the parent page, file or site object
|
||||
*
|
||||
* @return Page|File|Site
|
||||
* @return Kirby\Cms\Model
|
||||
*/
|
||||
public function parent()
|
||||
{
|
||||
@@ -163,7 +165,7 @@ class ContentTranslation
|
||||
* @param string $code
|
||||
* @return self
|
||||
*/
|
||||
protected function setCode(string $code): self
|
||||
protected function setCode(string $code)
|
||||
{
|
||||
$this->code = $code;
|
||||
return $this;
|
||||
@@ -173,17 +175,17 @@ class ContentTranslation
|
||||
* @param array $content
|
||||
* @return self
|
||||
*/
|
||||
protected function setContent(array $content = null): self
|
||||
protected function setContent(array $content = null)
|
||||
{
|
||||
$this->content = $content;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model $parent
|
||||
* @param Kirby\Cms\Model $parent
|
||||
* @return self
|
||||
*/
|
||||
protected function setParent(Model $parent): self
|
||||
protected function setParent(Model $parent)
|
||||
{
|
||||
$this->parent = $parent;
|
||||
return $this;
|
||||
@@ -193,7 +195,7 @@ class ContentTranslation
|
||||
* @param string $slug
|
||||
* @return self
|
||||
*/
|
||||
protected function setSlug(string $slug = null): self
|
||||
protected function setSlug(string $slug = null)
|
||||
{
|
||||
$this->slug = $slug;
|
||||
return $this;
|
||||
|
@@ -2,14 +2,17 @@
|
||||
|
||||
namespace Kirby\Cms;
|
||||
|
||||
use Exception;
|
||||
use Kirby\Toolkit\F;
|
||||
|
||||
/**
|
||||
* Extension of the Toolkit Dir class with a new
|
||||
* Dir::inventory method, that handles scanning directories
|
||||
* Extension of the Toolkit `Dir` class with a new
|
||||
* `Dir::inventory` method, that handles scanning directories
|
||||
* and converts the results into our children, files and
|
||||
* other page stuff.
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class Dir extends \Kirby\Toolkit\Dir
|
||||
{
|
||||
@@ -107,7 +110,7 @@ class Dir extends \Kirby\Toolkit\Dir
|
||||
$content = array_unique($content);
|
||||
}
|
||||
|
||||
$inventory = static::inventoryContent($dir, $inventory, $content);
|
||||
$inventory = static::inventoryContent($inventory, $content);
|
||||
$inventory = static::inventoryModels($inventory, $contentExtension, $multilang);
|
||||
|
||||
return $inventory;
|
||||
@@ -122,7 +125,7 @@ class Dir extends \Kirby\Toolkit\Dir
|
||||
* @param array $content
|
||||
* @return array
|
||||
*/
|
||||
protected static function inventoryContent(string $dir, array $inventory, array $content): array
|
||||
protected static function inventoryContent(array $inventory, array $content): array
|
||||
{
|
||||
|
||||
// filter meta files from the content file
|
||||
|
@@ -3,13 +3,18 @@
|
||||
namespace Kirby\Cms;
|
||||
|
||||
use Kirby\Exception\NotFoundException;
|
||||
use Kirby\Toolkit\Tpl;
|
||||
|
||||
/**
|
||||
* Wrapper around our PHPMailer package, which
|
||||
* handles all the magic connections between Kirby
|
||||
* and sending emails, like email templates, file
|
||||
* attachments, etc.
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class Email
|
||||
{
|
||||
@@ -28,7 +33,7 @@ class Email
|
||||
|
||||
public function __construct($preset = [], array $props = [])
|
||||
{
|
||||
$this->options = $options = App::instance()->option('email');
|
||||
$this->options = App::instance()->option('email');
|
||||
|
||||
// load presets from options
|
||||
$this->preset = $this->preset($preset);
|
||||
@@ -46,7 +51,11 @@ class Email
|
||||
$this->template();
|
||||
}
|
||||
|
||||
protected function preset($preset)
|
||||
/**
|
||||
* @param string|array $preset
|
||||
* @return array
|
||||
*/
|
||||
protected function preset($preset): array
|
||||
{
|
||||
// only passed props, not preset name
|
||||
if (is_string($preset) !== true) {
|
||||
@@ -64,7 +73,7 @@ class Email
|
||||
return $this->options['presets'][$preset];
|
||||
}
|
||||
|
||||
protected function template()
|
||||
protected function template(): void
|
||||
{
|
||||
if (isset($this->props['template']) === true) {
|
||||
|
||||
@@ -93,6 +102,13 @@ class Email
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
* @param string $name
|
||||
* @param string|null $type
|
||||
* @return Kirby\Cms\Template
|
||||
*/
|
||||
protected function getTemplate(string $name, string $type = null)
|
||||
{
|
||||
return App::instance()->template('emails/' . $name, $type, 'text');
|
||||
@@ -130,7 +146,7 @@ class Email
|
||||
}
|
||||
}
|
||||
|
||||
protected function transformProp($prop, $model)
|
||||
protected function transformProp(string $prop, string $model): void
|
||||
{
|
||||
if (isset($this->props[$prop]) === true) {
|
||||
$this->props[$prop] = $this->{'transform' . ucfirst($model)}($this->props[$prop]);
|
||||
|
@@ -21,8 +21,9 @@ use Kirby\Exception\InvalidArgumentException;
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link http://getkirby.com
|
||||
* @copyright Bastian Allgeier
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class Field
|
||||
{
|
||||
@@ -53,7 +54,7 @@ class Field
|
||||
* This will be the page, site, user or file
|
||||
* to which the content belongs
|
||||
*
|
||||
* @var Site|Page|File|User
|
||||
* @var Model
|
||||
*/
|
||||
protected $parent;
|
||||
|
||||
@@ -169,7 +170,7 @@ class Field
|
||||
|
||||
/**
|
||||
* @see Field::parent()
|
||||
* @return Page|File|Site|User
|
||||
* @return Kirby\Cms\Model|null
|
||||
*/
|
||||
public function model()
|
||||
{
|
||||
@@ -200,7 +201,7 @@ class Field
|
||||
/**
|
||||
* Returns the parent object of the field
|
||||
*
|
||||
* @return Page|File|Site|User
|
||||
* @return Kirby\Cms\Model|null
|
||||
*/
|
||||
public function parent()
|
||||
{
|
||||
@@ -228,12 +229,12 @@ class Field
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the field content
|
||||
* Returns the field content. If a new value is passed,
|
||||
* the modified field will be returned. Otherwise it
|
||||
* will return the field value.
|
||||
*
|
||||
* @param string|Closure $value
|
||||
* @return mixed If a new value is passed, the modified
|
||||
* field will be returned. Otherwise it
|
||||
* will return the field value.
|
||||
* @return mixed
|
||||
*/
|
||||
public function value($value = null)
|
||||
{
|
||||
|
@@ -2,14 +2,10 @@
|
||||
|
||||
namespace Kirby\Cms;
|
||||
|
||||
use Kirby\Data\Data;
|
||||
use Kirby\Exception\Exception;
|
||||
use Kirby\Exception\InvalidArgumentException;
|
||||
use Kirby\Image\Image;
|
||||
use Kirby\Toolkit\A;
|
||||
use Kirby\Toolkit\F;
|
||||
use Kirby\Toolkit\Str;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* The `$file` object provides a set
|
||||
@@ -27,8 +23,9 @@ use Throwable;
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link http://getkirby.com
|
||||
* @copyright Bastian Allgeier
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class File extends ModelWithContent
|
||||
{
|
||||
@@ -45,14 +42,14 @@ class File extends ModelWithContent
|
||||
* This is used to do actual file
|
||||
* method calls, like size, mime, etc.
|
||||
*
|
||||
* @var Image
|
||||
* @var Kirby\Image\Image
|
||||
*/
|
||||
protected $asset;
|
||||
|
||||
/**
|
||||
* Cache for the initialized blueprint object
|
||||
*
|
||||
* @var FileBlueprint
|
||||
* @var Kirby\Cms\FileBlueprint
|
||||
*/
|
||||
protected $blueprint;
|
||||
|
||||
@@ -73,10 +70,18 @@ class File extends ModelWithContent
|
||||
*/
|
||||
public static $methods = [];
|
||||
|
||||
/**
|
||||
* Registry with all File models
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $models = [];
|
||||
|
||||
|
||||
/**
|
||||
* The parent object
|
||||
*
|
||||
* @var Model
|
||||
* @var Kirby\Cms\Model
|
||||
*/
|
||||
protected $parent;
|
||||
|
||||
@@ -140,7 +145,7 @@ class File extends ModelWithContent
|
||||
}
|
||||
|
||||
/**
|
||||
* Improved var_dump() output
|
||||
* Improved `var_dump` output
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
@@ -168,9 +173,9 @@ class File extends ModelWithContent
|
||||
* Returns the Image object
|
||||
*
|
||||
* @internal
|
||||
* @return Image
|
||||
* @return Kirby\Image\Image
|
||||
*/
|
||||
public function asset(): Image
|
||||
public function asset()
|
||||
{
|
||||
return $this->asset = $this->asset ?? new Image($this->root());
|
||||
}
|
||||
@@ -178,9 +183,9 @@ class File extends ModelWithContent
|
||||
/**
|
||||
* Returns the FileBlueprint object for the file
|
||||
*
|
||||
* @return FileBlueprint
|
||||
* @return Kirby\Cms\FileBlueprint
|
||||
*/
|
||||
public function blueprint(): FileBlueprint
|
||||
public function blueprint()
|
||||
{
|
||||
if (is_a($this->blueprint, 'Kirby\Cms\FileBlueprint') === true) {
|
||||
return $this->blueprint;
|
||||
@@ -260,6 +265,22 @@ class File extends ModelWithContent
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a File object and also
|
||||
* takes File models into account.
|
||||
*
|
||||
* @internal
|
||||
* @return self
|
||||
*/
|
||||
public static function factory($props)
|
||||
{
|
||||
if (empty($props['model']) === false) {
|
||||
return static::model($props['model'], $props);
|
||||
}
|
||||
|
||||
return new static($props);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the filename with extension
|
||||
*
|
||||
@@ -273,9 +294,9 @@ class File extends ModelWithContent
|
||||
/**
|
||||
* Returns the parent Files collection
|
||||
*
|
||||
* @return Files
|
||||
* @return Kirby\Cms\Files
|
||||
*/
|
||||
public function files(): Files
|
||||
public function files()
|
||||
{
|
||||
return $this->siblingsCollection();
|
||||
}
|
||||
@@ -303,7 +324,7 @@ class File extends ModelWithContent
|
||||
/**
|
||||
* Compares the current object with the given file object
|
||||
*
|
||||
* @param File $file
|
||||
* @param Kirby\Cms\File $file
|
||||
* @return bool
|
||||
*/
|
||||
public function is(File $file): bool
|
||||
@@ -319,7 +340,7 @@ class File extends ModelWithContent
|
||||
*/
|
||||
public function mediaHash(): string
|
||||
{
|
||||
return crc32($this->filename()) . '-' . $this->modified();
|
||||
return crc32($this->filename()) . '-' . $this->modifiedFile();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -347,24 +368,32 @@ class File extends ModelWithContent
|
||||
/**
|
||||
* @deprecated 3.0.0 Use `File::content()` instead
|
||||
*
|
||||
* @return Content
|
||||
* @return Kirby\Cms\Content
|
||||
*/
|
||||
public function meta(): Content
|
||||
public function meta()
|
||||
{
|
||||
return $this->content();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parent model.
|
||||
* This is normally the parent page
|
||||
* or the site object.
|
||||
* Creates a file model if it has been registered
|
||||
*
|
||||
* @internal
|
||||
* @return Site|Page
|
||||
* @param string $name
|
||||
* @param array $props
|
||||
* @return Kirby\Cms\File
|
||||
*/
|
||||
public function model()
|
||||
public static function model(string $name, array $props = [])
|
||||
{
|
||||
return $this->parent();
|
||||
if ($class = (static::$models[$name] ?? null)) {
|
||||
$object = new $class($props);
|
||||
|
||||
if (is_a($object, 'Kirby\Cms\File') === true) {
|
||||
return $object;
|
||||
}
|
||||
}
|
||||
|
||||
return new static($props);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -376,8 +405,8 @@ class File extends ModelWithContent
|
||||
*/
|
||||
public function modified(string $format = null, string $handler = null)
|
||||
{
|
||||
$file = F::modified($this->root());
|
||||
$content = F::modified($this->contentFile());
|
||||
$file = $this->modifiedFile();
|
||||
$content = $this->modifiedContent();
|
||||
$modified = max($file, $content);
|
||||
|
||||
if (is_null($format) === true) {
|
||||
@@ -389,10 +418,32 @@ class File extends ModelWithContent
|
||||
return $handler($format, $modified);
|
||||
}
|
||||
|
||||
/**
|
||||
* Timestamp of the last modification
|
||||
* of the content file
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
protected function modifiedContent(): int
|
||||
{
|
||||
return F::modified($this->contentFile());
|
||||
}
|
||||
|
||||
/**
|
||||
* Timestamp of the last modification
|
||||
* of the source file
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
protected function modifiedFile(): int
|
||||
{
|
||||
return F::modified($this->root());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parent Page object
|
||||
*
|
||||
* @return Page
|
||||
* @return Kirby\Cms\Page|null
|
||||
*/
|
||||
public function page()
|
||||
{
|
||||
@@ -440,53 +491,26 @@ class File extends ModelWithContent
|
||||
|
||||
$definition = array_merge($types[$this->type()] ?? [], $extensions[$this->extension()] ?? []);
|
||||
|
||||
return [
|
||||
'type' => $definition['type'] ?? 'file',
|
||||
'color' => $definition['color'] ?? $colorWhite,
|
||||
'back' => $params['back'] ?? 'pattern',
|
||||
'ratio' => $params['ratio'] ?? null,
|
||||
];
|
||||
$params['type'] = $definition['type'] ?? 'file';
|
||||
$params['color'] = $definition['color'] ?? $colorWhite;
|
||||
|
||||
return parent::panelIcon($params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Panel image definition
|
||||
* Returns the image file object based on provided query
|
||||
*
|
||||
* @internal
|
||||
* @param string|array|false $settings
|
||||
* @param array $thumbSettings
|
||||
* @return array
|
||||
* @param string|null $query
|
||||
* @return Kirby\Cms\File|Kirby\Cms\Asset|null
|
||||
*/
|
||||
public function panelImage($settings = null, array $thumbSettings = null): ?array
|
||||
protected function panelImageSource(string $query = null)
|
||||
{
|
||||
$defaults = [
|
||||
'ratio' => '3/2',
|
||||
'back' => 'pattern',
|
||||
'cover' => false
|
||||
];
|
||||
|
||||
// switch the image off
|
||||
if ($settings === false) {
|
||||
return null;
|
||||
if ($query === null && $this->isViewable()) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
if (is_string($settings) === true) {
|
||||
$settings = [
|
||||
'query' => $settings
|
||||
];
|
||||
}
|
||||
|
||||
$image = $this->query($settings['query'] ?? null, 'Kirby\Cms\File');
|
||||
|
||||
if ($image === null && $this->isViewable() === true) {
|
||||
$image = $this;
|
||||
}
|
||||
|
||||
if ($image) {
|
||||
$settings['url'] = $image->thumb($thumbSettings)->url(true);
|
||||
unset($settings['query']);
|
||||
}
|
||||
|
||||
return array_merge($defaults, (array)$settings);
|
||||
return parent::panelImageSource($query);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -500,6 +524,38 @@ class File extends ModelWithContent
|
||||
return 'files/' . $this->filename();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the response data for file pickers
|
||||
* and file fields
|
||||
*
|
||||
* @param array|null $params
|
||||
* @return array
|
||||
*/
|
||||
public function panelPickerData(array $params = []): array
|
||||
{
|
||||
$image = $this->panelImage($params['image'] ?? []);
|
||||
$icon = $this->panelIcon($image);
|
||||
$uuid = $this->id();
|
||||
|
||||
if (empty($params['model']) === false) {
|
||||
$uuid = $this->parent() === $params['model'] ? $this->filename() : $this->id();
|
||||
}
|
||||
|
||||
return [
|
||||
'filename' => $this->filename(),
|
||||
'dragText' => $this->dragText(),
|
||||
'icon' => $icon,
|
||||
'id' => $this->id(),
|
||||
'image' => $image,
|
||||
'info' => $this->toString($params['info'] ?? false),
|
||||
'link' => $this->panelUrl(true),
|
||||
'text' => $this->toString($params['text'] ?? '{{ file.filename }}'),
|
||||
'type' => $this->type(),
|
||||
'url' => $this->url(),
|
||||
'uuid' => $uuid,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the url to the editing view
|
||||
* in the panel
|
||||
@@ -516,7 +572,7 @@ class File extends ModelWithContent
|
||||
/**
|
||||
* Returns the parent Model object
|
||||
*
|
||||
* @return Model
|
||||
* @return Kirby\Cms\Model
|
||||
*/
|
||||
public function parent()
|
||||
{
|
||||
@@ -541,9 +597,9 @@ class File extends ModelWithContent
|
||||
/**
|
||||
* Returns a collection of all parent pages
|
||||
*
|
||||
* @return Pages
|
||||
* @return Kirby\Cms\Pages
|
||||
*/
|
||||
public function parents(): Pages
|
||||
public function parents()
|
||||
{
|
||||
if (is_a($this->parent(), 'Kirby\Cms\Page') === true) {
|
||||
return $this->parent()->parents()->prepend($this->parent()->id(), $this->parent());
|
||||
@@ -555,40 +611,13 @@ class File extends ModelWithContent
|
||||
/**
|
||||
* Returns the permissions object for this file
|
||||
*
|
||||
* @return FilePermissions
|
||||
* @return Kirby\Cms\FilePermissions
|
||||
*/
|
||||
public function permissions()
|
||||
{
|
||||
return new FilePermissions($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a string query, starting from the model
|
||||
*
|
||||
* @internal
|
||||
* @param string|null $query
|
||||
* @param string|null $expect
|
||||
* @return mixed
|
||||
*/
|
||||
public function query(string $query = null, string $expect = null)
|
||||
{
|
||||
if ($query === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$result = Str::query($query, [
|
||||
'kirby' => $this->kirby(),
|
||||
'site' => $this->site(),
|
||||
'file' => $this
|
||||
]);
|
||||
|
||||
if ($expect !== null && is_a($result, $expect) !== true) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the absolute root to the file
|
||||
*
|
||||
@@ -603,7 +632,7 @@ class File extends ModelWithContent
|
||||
* Returns the FileRules class to
|
||||
* validate any important action.
|
||||
*
|
||||
* @return FileRules
|
||||
* @return Kirby\Cms\FileRules
|
||||
*/
|
||||
protected function rules()
|
||||
{
|
||||
@@ -616,7 +645,7 @@ class File extends ModelWithContent
|
||||
* @param array|null $blueprint
|
||||
* @return self
|
||||
*/
|
||||
protected function setBlueprint(array $blueprint = null): self
|
||||
protected function setBlueprint(array $blueprint = null)
|
||||
{
|
||||
if ($blueprint !== null) {
|
||||
$blueprint['model'] = $this;
|
||||
@@ -632,7 +661,7 @@ class File extends ModelWithContent
|
||||
* @param string $filename
|
||||
* @return self
|
||||
*/
|
||||
protected function setFilename(string $filename): self
|
||||
protected function setFilename(string $filename)
|
||||
{
|
||||
$this->filename = $filename;
|
||||
return $this;
|
||||
@@ -641,10 +670,10 @@ class File extends ModelWithContent
|
||||
/**
|
||||
* Sets the parent model object
|
||||
*
|
||||
* @param Model $parent
|
||||
* @param Kirby\Cms\Model $parent
|
||||
* @return self
|
||||
*/
|
||||
protected function setParent(Model $parent = null): self
|
||||
protected function setParent(Model $parent = null)
|
||||
{
|
||||
$this->parent = $parent;
|
||||
return $this;
|
||||
@@ -667,7 +696,7 @@ class File extends ModelWithContent
|
||||
* @param string $template
|
||||
* @return self
|
||||
*/
|
||||
protected function setTemplate(string $template = null): self
|
||||
protected function setTemplate(string $template = null)
|
||||
{
|
||||
$this->template = $template;
|
||||
return $this;
|
||||
@@ -679,7 +708,7 @@ class File extends ModelWithContent
|
||||
* @param string $url
|
||||
* @return self
|
||||
*/
|
||||
protected function setUrl(string $url = null): self
|
||||
protected function setUrl(string $url = null)
|
||||
{
|
||||
$this->url = $url;
|
||||
return $this;
|
||||
@@ -689,7 +718,7 @@ class File extends ModelWithContent
|
||||
* Returns the parent Files collection
|
||||
* @internal
|
||||
*
|
||||
* @return Files
|
||||
* @return Kirby\Cms\Files
|
||||
*/
|
||||
protected function siblingsCollection()
|
||||
{
|
||||
@@ -699,9 +728,9 @@ class File extends ModelWithContent
|
||||
/**
|
||||
* Returns the parent Site object
|
||||
*
|
||||
* @return Site
|
||||
* @return Kirby\Cms\Site
|
||||
*/
|
||||
public function site(): Site
|
||||
public function site()
|
||||
{
|
||||
return is_a($this->parent(), 'Kirby\Cms\Site') === true ? $this->parent() : $this->kirby()->site();
|
||||
}
|
||||
@@ -720,7 +749,7 @@ class File extends ModelWithContent
|
||||
* Returns siblings with the same template
|
||||
*
|
||||
* @param bool $self
|
||||
* @return self
|
||||
* @return Kirby\Cms\Files
|
||||
*/
|
||||
public function templateSiblings(bool $self = true)
|
||||
{
|
||||
@@ -739,25 +768,6 @@ class File extends ModelWithContent
|
||||
return array_merge($this->asset()->toArray(), parent::toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* String template builder
|
||||
*
|
||||
* @param string|null $template
|
||||
* @return string
|
||||
*/
|
||||
public function toString(string $template = null): string
|
||||
{
|
||||
if ($template === null) {
|
||||
return $this->id();
|
||||
}
|
||||
|
||||
return Str::template($template, [
|
||||
'file' => $this,
|
||||
'site' => $this->site(),
|
||||
'kirby' => $this->kirby()
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Url
|
||||
*
|
||||
|
@@ -3,13 +3,20 @@
|
||||
namespace Kirby\Cms;
|
||||
|
||||
use Closure;
|
||||
use Kirby\Data\Data;
|
||||
use Kirby\Exception\InvalidArgumentException;
|
||||
use Kirby\Exception\LogicException;
|
||||
use Kirby\Image\Image;
|
||||
use Kirby\Toolkit\F;
|
||||
use Kirby\Toolkit\Str;
|
||||
|
||||
/**
|
||||
* FileActions
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
trait FileActions
|
||||
{
|
||||
|
||||
@@ -21,7 +28,7 @@ trait FileActions
|
||||
* @param bool $sanitize
|
||||
* @return self
|
||||
*/
|
||||
public function changeName(string $name, bool $sanitize = true): self
|
||||
public function changeName(string $name, bool $sanitize = true)
|
||||
{
|
||||
if ($sanitize === true) {
|
||||
$name = F::safeName($name);
|
||||
@@ -45,6 +52,9 @@ trait FileActions
|
||||
throw new LogicException('The new file exists and cannot be overwritten');
|
||||
}
|
||||
|
||||
// remove the lock of the old file
|
||||
$oldFile->lock()->remove();
|
||||
|
||||
// remove all public versions
|
||||
$oldFile->unpublish();
|
||||
|
||||
@@ -108,6 +118,29 @@ trait FileActions
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the file to the given page
|
||||
*
|
||||
* @param Kirby\Cms\Page $page
|
||||
* @return Kirby\Cms\File
|
||||
*/
|
||||
public function copy(Page $page)
|
||||
{
|
||||
F::copy($this->root(), $page->root() . '/' . $this->filename());
|
||||
|
||||
if ($this->kirby()->multilang() === true) {
|
||||
foreach ($this->kirby()->languages() as $language) {
|
||||
$contentFile = $this->contentFile($language->code());
|
||||
F::copy($contentFile, $page->root() . '/' . basename($contentFile));
|
||||
}
|
||||
} else {
|
||||
$contentFile = $this->contentFile();
|
||||
F::copy($contentFile, $page->root() . '/' . basename($contentFile));
|
||||
}
|
||||
|
||||
return $page->clone()->file($this->filename());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new file on disk and returns the
|
||||
* File object. The store is used to handle file
|
||||
@@ -117,7 +150,7 @@ trait FileActions
|
||||
* @param array $props
|
||||
* @return self
|
||||
*/
|
||||
public static function create(array $props): self
|
||||
public static function create(array $props)
|
||||
{
|
||||
if (isset($props['source'], $props['parent']) === false) {
|
||||
throw new InvalidArgumentException('Please provide the "source" and "parent" props for the File');
|
||||
@@ -126,8 +159,10 @@ trait FileActions
|
||||
// prefer the filename from the props
|
||||
$props['filename'] = F::safeName($props['filename'] ?? basename($props['source']));
|
||||
|
||||
$props['model'] = strtolower($props['template'] ?? 'default');
|
||||
|
||||
// create the basic file and a test upload object
|
||||
$file = new static($props);
|
||||
$file = File::factory($props);
|
||||
$upload = new Image($props['source']);
|
||||
|
||||
// create a form for the file
|
||||
@@ -176,8 +211,13 @@ trait FileActions
|
||||
public function delete(): bool
|
||||
{
|
||||
return $this->commit('delete', [$this], function ($file) {
|
||||
|
||||
// remove all versions in the media folder
|
||||
$file->unpublish();
|
||||
|
||||
// remove the lock of the old file
|
||||
$file->lock()->remove();
|
||||
|
||||
if ($file->kirby()->multilang() === true) {
|
||||
foreach ($file->translations() as $translation) {
|
||||
F::remove($file->contentFile($translation->code()));
|
||||
@@ -198,7 +238,7 @@ trait FileActions
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function publish(): self
|
||||
public function publish()
|
||||
{
|
||||
Media::publish($this->root(), $this->mediaRoot());
|
||||
return $this;
|
||||
@@ -226,7 +266,7 @@ trait FileActions
|
||||
* @param string $source
|
||||
* @return self
|
||||
*/
|
||||
public function replace(string $source): self
|
||||
public function replace(string $source)
|
||||
{
|
||||
return $this->commit('replace', [$this, new Image($source)], function ($file, $upload) {
|
||||
|
||||
@@ -248,7 +288,7 @@ trait FileActions
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function unpublish(): self
|
||||
public function unpublish()
|
||||
{
|
||||
Media::unpublish($this->parent()->mediaRoot(), $this->filename());
|
||||
return $this;
|
||||
|
@@ -5,6 +5,12 @@ namespace Kirby\Cms;
|
||||
/**
|
||||
* Extension of the basic blueprint class
|
||||
* to handle all blueprints for files.
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class FileBlueprint extends Blueprint
|
||||
{
|
||||
@@ -29,12 +35,18 @@ class FileBlueprint extends Blueprint
|
||||
$this->props['accept'] = $this->normalizeAccept($this->props['accept'] ?? []);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function accept(): array
|
||||
{
|
||||
return $this->props['accept'];
|
||||
}
|
||||
|
||||
protected function normalizeAccept($accept = null)
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
protected function normalizeAccept($accept = null): array
|
||||
{
|
||||
if (is_string($accept) === true) {
|
||||
$accept = [
|
||||
|
@@ -5,10 +5,15 @@ namespace Kirby\Cms;
|
||||
use Kirby\Exception\BadMethodCallException;
|
||||
use Kirby\Image\Image;
|
||||
use Kirby\Toolkit\F;
|
||||
use Kirby\Toolkit\Properties;
|
||||
|
||||
/**
|
||||
* Foundation for all file objects
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
trait FileFoundation
|
||||
{
|
||||
@@ -66,10 +71,10 @@ trait FileFoundation
|
||||
|
||||
/**
|
||||
* Returns the Image object
|
||||
*^
|
||||
* @return Image
|
||||
*
|
||||
* @return Kirby\Image\Image
|
||||
*/
|
||||
public function asset(): Image
|
||||
public function asset()
|
||||
{
|
||||
return $this->asset = $this->asset ?? new Image($this->root());
|
||||
}
|
||||
@@ -150,9 +155,9 @@ trait FileFoundation
|
||||
/**
|
||||
* Returns the app instance
|
||||
*
|
||||
* @return App
|
||||
* @return Kirby\Cms\App
|
||||
*/
|
||||
public function kirby(): App
|
||||
public function kirby()
|
||||
{
|
||||
return App::instance();
|
||||
}
|
||||
@@ -225,7 +230,7 @@ trait FileFoundation
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function type()
|
||||
public function type(): ?string
|
||||
{
|
||||
return F::type($this->root());
|
||||
}
|
||||
|
@@ -2,8 +2,16 @@
|
||||
|
||||
namespace Kirby\Cms;
|
||||
|
||||
use Kirby\Exception\InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Resizing, blurring etc
|
||||
* Resizing, blurring etc.
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
trait FileModifications
|
||||
{
|
||||
@@ -12,7 +20,7 @@ trait FileModifications
|
||||
* Blurs the image by the given amount of pixels
|
||||
*
|
||||
* @param boolean $pixels
|
||||
* @return self
|
||||
* @return Kirby\Cms\FileVersion|Kirby\Cms\File
|
||||
*/
|
||||
public function blur($pixels = true)
|
||||
{
|
||||
@@ -22,7 +30,7 @@ trait FileModifications
|
||||
/**
|
||||
* Converts the image to black and white
|
||||
*
|
||||
* @return self
|
||||
* @return Kirby\Cms\FileVersion|Kirby\Cms\File
|
||||
*/
|
||||
public function bw()
|
||||
{
|
||||
@@ -35,7 +43,7 @@ trait FileModifications
|
||||
* @param integer $width
|
||||
* @param integer $height
|
||||
* @param string|array $options
|
||||
* @return self
|
||||
* @return Kirby\Cms\FileVersion|Kirby\Cms\File
|
||||
*/
|
||||
public function crop(int $width, int $height = null, $options = null)
|
||||
{
|
||||
@@ -65,7 +73,7 @@ trait FileModifications
|
||||
* Sets the JPEG compression quality
|
||||
*
|
||||
* @param integer $quality
|
||||
* @return self
|
||||
* @return Kirby\Cms\FileVersion|Kirby\Cms\File
|
||||
*/
|
||||
public function quality(int $quality)
|
||||
{
|
||||
@@ -79,7 +87,7 @@ trait FileModifications
|
||||
* @param integer $width
|
||||
* @param integer $height
|
||||
* @param integer $quality
|
||||
* @return self
|
||||
* @return Kirby\Cms\FileVersion|Kirby\Cms\File
|
||||
*/
|
||||
public function resize(int $width = null, int $height = null, int $quality = null)
|
||||
{
|
||||
@@ -97,7 +105,7 @@ trait FileModifications
|
||||
* @since 3.1.0
|
||||
*
|
||||
* @param array|string $sizes
|
||||
* @return string
|
||||
* @return string|null
|
||||
*/
|
||||
public function srcset($sizes = null): ?string
|
||||
{
|
||||
@@ -116,15 +124,22 @@ trait FileModifications
|
||||
$set = [];
|
||||
|
||||
foreach ($sizes as $key => $value) {
|
||||
if (is_string($value) === true) {
|
||||
$size = $key;
|
||||
$attr = $value;
|
||||
if (is_array($value)) {
|
||||
$options = $value;
|
||||
$condition = $key;
|
||||
} elseif (is_string($value) === true) {
|
||||
$options = [
|
||||
'width' => $key
|
||||
];
|
||||
$condition = $value;
|
||||
} else {
|
||||
$size = $value;
|
||||
$attr = $value . 'w';
|
||||
$options = [
|
||||
'width' => $value
|
||||
];
|
||||
$condition = $value . 'w';
|
||||
}
|
||||
|
||||
$set[] = $this->resize($size)->url() . ' ' . $attr;
|
||||
$set[] = $this->thumb($options)->url() . ' ' . $condition;
|
||||
}
|
||||
|
||||
return implode(', ', $set);
|
||||
@@ -135,12 +150,12 @@ trait FileModifications
|
||||
* The media manager takes care of generating
|
||||
* those modified versions and putting them
|
||||
* in the right place. This is normally the
|
||||
* /media folder of your installation, but
|
||||
* `/media` folder of your installation, but
|
||||
* could potentially also be a CDN or any other
|
||||
* place.
|
||||
*
|
||||
* @param array|null|string $options
|
||||
* @return FileVersion|File
|
||||
* @return Kirby\Cms\FileVersion|Kirby\Cms\File
|
||||
*/
|
||||
public function thumb($options = null)
|
||||
{
|
||||
|
@@ -2,6 +2,15 @@
|
||||
|
||||
namespace Kirby\Cms;
|
||||
|
||||
/**
|
||||
* FilePermissions
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class FilePermissions extends ModelPermissions
|
||||
{
|
||||
protected $category = 'files';
|
||||
|
@@ -12,6 +12,12 @@ use Kirby\Toolkit\V;
|
||||
|
||||
/**
|
||||
* Validators for all file actions
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class FileRules
|
||||
{
|
||||
|
@@ -4,6 +4,15 @@ namespace Kirby\Cms;
|
||||
|
||||
use Kirby\Toolkit\Properties;
|
||||
|
||||
/**
|
||||
* FileVersion
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class FileVersion
|
||||
{
|
||||
use FileFoundation;
|
||||
@@ -39,7 +48,10 @@ class FileVersion
|
||||
return dirname($this->original()->id()) . '/' . $this->filename();
|
||||
}
|
||||
|
||||
public function kirby(): App
|
||||
/**
|
||||
* @return Kirby\Cms\App
|
||||
*/
|
||||
public function kirby()
|
||||
{
|
||||
return $this->original()->kirby();
|
||||
}
|
||||
|
@@ -22,8 +22,9 @@ use Kirby\Toolkit\Str;
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link http://getkirby.com
|
||||
* @copyright Bastian Allgeier
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class Filename
|
||||
{
|
||||
|
@@ -12,8 +12,9 @@ namespace Kirby\Cms;
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link http://getkirby.com
|
||||
* @copyright Bastian Allgeier
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class Files extends Collection
|
||||
{
|
||||
@@ -31,7 +32,7 @@ class Files extends Collection
|
||||
* current collection
|
||||
*
|
||||
* @param mixed $item
|
||||
* @return Files
|
||||
* @return self
|
||||
*/
|
||||
public function add($object)
|
||||
{
|
||||
@@ -75,9 +76,9 @@ class Files extends Collection
|
||||
* Creates a files collection from an array of props
|
||||
*
|
||||
* @param array $files
|
||||
* @param Model $parent
|
||||
* @param Kirby\Cms\Model $parent
|
||||
* @param array $inject
|
||||
* @return Files
|
||||
* @return self
|
||||
*/
|
||||
public static function factory(array $files, Model $parent)
|
||||
{
|
||||
@@ -89,7 +90,7 @@ class Files extends Collection
|
||||
$props['kirby'] = $kirby;
|
||||
$props['parent'] = $parent;
|
||||
|
||||
$file = new File($props);
|
||||
$file = File::factory($props);
|
||||
|
||||
$collection->data[$file->id()] = $file;
|
||||
}
|
||||
@@ -101,9 +102,9 @@ class Files extends Collection
|
||||
* Tries to find a file by id/filename
|
||||
*
|
||||
* @param string $id
|
||||
* @return File|null
|
||||
* @return Kirby\Cms\File|null
|
||||
*/
|
||||
public function findById($id)
|
||||
public function findById(string $id)
|
||||
{
|
||||
return $this->get(ltrim($this->parent->id() . '/' . $id, '/'));
|
||||
}
|
||||
@@ -114,9 +115,9 @@ class Files extends Collection
|
||||
* map the get method correctly.
|
||||
*
|
||||
* @param string $key
|
||||
* @return File|null
|
||||
* @return Kirby\Cms\File|null
|
||||
*/
|
||||
public function findByKey($key)
|
||||
public function findByKey(string $key)
|
||||
{
|
||||
return $this->findById($key);
|
||||
}
|
||||
@@ -127,7 +128,7 @@ class Files extends Collection
|
||||
* @param null|string|array $template
|
||||
* @return self
|
||||
*/
|
||||
public function template($template): self
|
||||
public function template($template)
|
||||
{
|
||||
if (empty($template) === true) {
|
||||
return $this;
|
||||
|
@@ -8,6 +8,12 @@ use Kirby\Form\Form as BaseForm;
|
||||
* Extension of `Kirby\Form\Form` that introduces
|
||||
* a Form::for method that creates a proper form
|
||||
* definition for any Cms Model.
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class Form extends BaseForm
|
||||
{
|
||||
@@ -38,6 +44,11 @@ class Form extends BaseForm
|
||||
parent::__construct($props);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Kirby\Cms\Model $model
|
||||
* @param array $props
|
||||
* @return self
|
||||
*/
|
||||
public static function for(Model $model, array $props = [])
|
||||
{
|
||||
// get the original model data
|
||||
|
@@ -4,27 +4,36 @@ namespace Kirby\Cms;
|
||||
|
||||
use Kirby\Toolkit\Str;
|
||||
|
||||
/**
|
||||
* HasChildren
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
trait HasChildren
|
||||
{
|
||||
|
||||
/**
|
||||
* The Pages collection
|
||||
*
|
||||
* @var Pages
|
||||
* @var Kirby\Cms\Pages
|
||||
*/
|
||||
public $children;
|
||||
|
||||
/**
|
||||
* The list of available drafts
|
||||
*
|
||||
* @var Pages
|
||||
* @var Kirby\Cms\Pages
|
||||
*/
|
||||
public $drafts;
|
||||
|
||||
/**
|
||||
* Returns the Pages collection
|
||||
*
|
||||
* @return Pages
|
||||
* @return Kirby\Cms\Pages
|
||||
*/
|
||||
public function children()
|
||||
{
|
||||
@@ -38,7 +47,7 @@ trait HasChildren
|
||||
/**
|
||||
* Returns all children and drafts at the same time
|
||||
*
|
||||
* @return Pages
|
||||
* @return Kirby\Cms\Pages
|
||||
*/
|
||||
public function childrenAndDrafts()
|
||||
{
|
||||
@@ -60,7 +69,7 @@ trait HasChildren
|
||||
* Searches for a child draft by id
|
||||
*
|
||||
* @param string $path
|
||||
* @return Page|null
|
||||
* @return Kirby\Cms\Page|null
|
||||
*/
|
||||
public function draft(string $path)
|
||||
{
|
||||
@@ -93,7 +102,7 @@ trait HasChildren
|
||||
/**
|
||||
* Return all drafts of the model
|
||||
*
|
||||
* @return Pages
|
||||
* @return Kirby\Cms\Pages
|
||||
*/
|
||||
public function drafts()
|
||||
{
|
||||
@@ -118,7 +127,7 @@ trait HasChildren
|
||||
* Finds one or multiple children by id
|
||||
*
|
||||
* @param string ...$arguments
|
||||
* @return Pages
|
||||
* @return Kirby\Cms\Page|Kirby\Cms\Pages
|
||||
*/
|
||||
public function find(...$arguments)
|
||||
{
|
||||
@@ -128,7 +137,7 @@ trait HasChildren
|
||||
/**
|
||||
* Finds a single page or draft
|
||||
*
|
||||
* @return Page|null
|
||||
* @return Kirby\Cms\Page|null
|
||||
*/
|
||||
public function findPageOrDraft(string $path)
|
||||
{
|
||||
@@ -138,9 +147,9 @@ trait HasChildren
|
||||
/**
|
||||
* Returns a collection of all children of children
|
||||
*
|
||||
* @return Pages
|
||||
* @return Kirby\Cms\Pages
|
||||
*/
|
||||
public function grandChildren(): Pages
|
||||
public function grandChildren()
|
||||
{
|
||||
return $this->children()->children();
|
||||
}
|
||||
@@ -171,7 +180,7 @@ trait HasChildren
|
||||
*/
|
||||
public function hasInvisibleChildren(): bool
|
||||
{
|
||||
return $this->children()->invisible()->count() > 0;
|
||||
return $this->hasUnlistedChildren();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -200,16 +209,16 @@ trait HasChildren
|
||||
*/
|
||||
public function hasVisibleChildren(): bool
|
||||
{
|
||||
return $this->children()->listed()->count() > 0;
|
||||
return $this->hasListedChildren();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a flat child index
|
||||
*
|
||||
* @param bool $drafts
|
||||
* @return Pages
|
||||
* @return Kirby\Cms\Pages
|
||||
*/
|
||||
public function index(bool $drafts = false): Pages
|
||||
public function index(bool $drafts = false)
|
||||
{
|
||||
if ($drafts === true) {
|
||||
return $this->childrenAndDrafts()->index($drafts);
|
||||
|
@@ -2,24 +2,31 @@
|
||||
|
||||
namespace Kirby\Cms;
|
||||
|
||||
use Kirby\Toolkit\Str;
|
||||
|
||||
/**
|
||||
* HasFiles
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
trait HasFiles
|
||||
{
|
||||
|
||||
/**
|
||||
* The Files collection
|
||||
*
|
||||
* @var Files
|
||||
* @var Kirby\Cms\Files
|
||||
*/
|
||||
protected $files;
|
||||
|
||||
/**
|
||||
* Filters the Files collection by type audio
|
||||
*
|
||||
* @return Files
|
||||
* @return Kirby\Cms\Files
|
||||
*/
|
||||
public function audio(): Files
|
||||
public function audio()
|
||||
{
|
||||
return $this->files()->filterBy('type', '==', 'audio');
|
||||
}
|
||||
@@ -27,9 +34,9 @@ trait HasFiles
|
||||
/**
|
||||
* Filters the Files collection by type code
|
||||
*
|
||||
* @return Files
|
||||
* @return Kirby\Cms\Files
|
||||
*/
|
||||
public function code(): Files
|
||||
public function code()
|
||||
{
|
||||
return $this->files()->filterBy('type', '==', 'code');
|
||||
}
|
||||
@@ -49,7 +56,7 @@ trait HasFiles
|
||||
* Creates a new file
|
||||
*
|
||||
* @param array $props
|
||||
* @return File
|
||||
* @return Kirby\Cms\File
|
||||
*/
|
||||
public function createFile(array $props)
|
||||
{
|
||||
@@ -64,9 +71,9 @@ trait HasFiles
|
||||
/**
|
||||
* Filters the Files collection by type documents
|
||||
*
|
||||
* @return Files
|
||||
* @return Kirby\Cms\Files
|
||||
*/
|
||||
public function documents(): Files
|
||||
public function documents()
|
||||
{
|
||||
return $this->files()->filterBy('type', '==', 'document');
|
||||
}
|
||||
@@ -76,7 +83,7 @@ trait HasFiles
|
||||
*
|
||||
* @param string $filename
|
||||
* @param string $in
|
||||
* @return File
|
||||
* @return Kirby\Cms\File|null
|
||||
*/
|
||||
public function file(string $filename = null, string $in = 'files')
|
||||
{
|
||||
@@ -101,9 +108,9 @@ trait HasFiles
|
||||
/**
|
||||
* Returns the Files collection
|
||||
*
|
||||
* @return Files
|
||||
* @return Kirby\Cms\Files
|
||||
*/
|
||||
public function files(): Files
|
||||
public function files()
|
||||
{
|
||||
if (is_a($this->files, 'Kirby\Cms\Files') === true) {
|
||||
return $this->files;
|
||||
@@ -176,7 +183,7 @@ trait HasFiles
|
||||
* Returns a specific image by filename or the first one
|
||||
*
|
||||
* @param string $filename
|
||||
* @return File
|
||||
* @return Kirby\Cms\File|null
|
||||
*/
|
||||
public function image(string $filename = null)
|
||||
{
|
||||
@@ -186,9 +193,9 @@ trait HasFiles
|
||||
/**
|
||||
* Filters the Files collection by type image
|
||||
*
|
||||
* @return Files
|
||||
* @return Kirby\Cms\Files
|
||||
*/
|
||||
public function images(): Files
|
||||
public function images()
|
||||
{
|
||||
return $this->files()->filterBy('type', '==', 'image');
|
||||
}
|
||||
@@ -196,10 +203,10 @@ trait HasFiles
|
||||
/**
|
||||
* Sets the Files collection
|
||||
*
|
||||
* @param Files|null $files
|
||||
* @param Kirby\Cms\Files|null $files
|
||||
* @return self
|
||||
*/
|
||||
protected function setFiles(array $files = null): self
|
||||
protected function setFiles(array $files = null)
|
||||
{
|
||||
if ($files !== null) {
|
||||
$this->files = Files::factory($files, $this);
|
||||
@@ -211,9 +218,9 @@ trait HasFiles
|
||||
/**
|
||||
* Filters the Files collection by type videos
|
||||
*
|
||||
* @return Files
|
||||
* @return Kirby\Cms\Files
|
||||
*/
|
||||
public function videos(): Files
|
||||
public function videos()
|
||||
{
|
||||
return $this->files()->filterBy('type', '==', 'video');
|
||||
}
|
||||
|
@@ -2,6 +2,15 @@
|
||||
|
||||
namespace Kirby\Cms;
|
||||
|
||||
/**
|
||||
* HasMethods
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
trait HasMethods
|
||||
{
|
||||
|
||||
|
@@ -8,8 +8,9 @@ namespace Kirby\Cms;
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link http://getkirby.com
|
||||
* @copyright Bastian Allgeier
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
trait HasSiblings
|
||||
{
|
||||
@@ -27,7 +28,7 @@ trait HasSiblings
|
||||
/**
|
||||
* Returns the next item in the collection if available
|
||||
*
|
||||
* @return Model|null
|
||||
* @return Kirby\Cms\Model|null
|
||||
*/
|
||||
public function next()
|
||||
{
|
||||
@@ -37,7 +38,7 @@ trait HasSiblings
|
||||
/**
|
||||
* Returns the end of the collection starting after the current item
|
||||
*
|
||||
* @return Collection
|
||||
* @return Kirby\Cms\Collection
|
||||
*/
|
||||
public function nextAll()
|
||||
{
|
||||
@@ -47,7 +48,7 @@ trait HasSiblings
|
||||
/**
|
||||
* Returns the previous item in the collection if available
|
||||
*
|
||||
* @return Model|null
|
||||
* @return Kirby\Cms\Model|null
|
||||
*/
|
||||
public function prev()
|
||||
{
|
||||
@@ -57,7 +58,7 @@ trait HasSiblings
|
||||
/**
|
||||
* Returns the beginning of the collection before the current item
|
||||
*
|
||||
* @return Collection
|
||||
* @return Kirby\Cms\Collection
|
||||
*/
|
||||
public function prevAll()
|
||||
{
|
||||
@@ -68,7 +69,7 @@ trait HasSiblings
|
||||
* Returns all sibling elements
|
||||
*
|
||||
* @param bool $self
|
||||
* @return Collection
|
||||
* @return Kirby\Cms\Collection
|
||||
*/
|
||||
public function siblings(bool $self = true)
|
||||
{
|
||||
|
@@ -9,21 +9,22 @@ namespace Kirby\Cms;
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link http://getkirby.com
|
||||
* @copyright Bastian Allgeier
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class Html extends \Kirby\Toolkit\Html
|
||||
{
|
||||
/**
|
||||
* Generates an a tag with an absolute Url
|
||||
* Generates an `a` tag with an absolute Url
|
||||
*
|
||||
* @param string $href Relative or absolute Url
|
||||
* @param string|array|null $text If null, the link will be used as link text. If an array is passed, each element will be added unencoded
|
||||
* @param string|array|null $text If `null`, the link will be used as link text. If an array is passed, each element will be added unencoded
|
||||
* @param array $attr Additional attributes for the a tag.
|
||||
* @return string
|
||||
*/
|
||||
public static function a(string $href = null, $text = null, array $attr = []): string
|
||||
public static function link(string $href = null, $text = null, array $attr = []): string
|
||||
{
|
||||
return parent::a(Url::to($href), $text, $attr);
|
||||
return parent::link(Url::to($href), $text, $attr);
|
||||
}
|
||||
}
|
||||
|
@@ -2,13 +2,17 @@
|
||||
|
||||
namespace Kirby\Cms;
|
||||
|
||||
use Closure;
|
||||
|
||||
/**
|
||||
* The Ingredients class is the foundation for
|
||||
* $kirby->urls() and $kirby->roots() objects.
|
||||
* `$kirby->urls()` and `$kirby->roots()` objects.
|
||||
* Those are configured in `kirby/config/urls.php`
|
||||
* and `kirby/config/roots.php`
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class Ingredients
|
||||
{
|
||||
@@ -41,7 +45,7 @@ class Ingredients
|
||||
}
|
||||
|
||||
/**
|
||||
* Improved var_dump output
|
||||
* Improved `var_dump` output
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
@@ -69,7 +73,7 @@ class Ingredients
|
||||
* @param array $ingredients
|
||||
* @return self
|
||||
*/
|
||||
public static function bake(array $ingredients): self
|
||||
public static function bake(array $ingredients)
|
||||
{
|
||||
foreach ($ingredients as $name => $ingredient) {
|
||||
if (is_a($ingredient, 'Closure') === true) {
|
||||
|
@@ -5,6 +5,12 @@ namespace Kirby\Cms;
|
||||
/**
|
||||
* Extended KirbyTag class to provide
|
||||
* common helpers for tag objects
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class KirbyTag extends \Kirby\Text\KirbyTag
|
||||
{
|
||||
@@ -16,9 +22,9 @@ class KirbyTag extends \Kirby\Text\KirbyTag
|
||||
* Afterwards it uses Kirby's global file finder.
|
||||
*
|
||||
* @param string $path
|
||||
* @return File|null
|
||||
* @return Kirby\Cms\File|null
|
||||
*/
|
||||
public function file(string $path): ?File
|
||||
public function file(string $path)
|
||||
{
|
||||
$parent = $this->parent();
|
||||
|
||||
@@ -36,9 +42,9 @@ class KirbyTag extends \Kirby\Text\KirbyTag
|
||||
/**
|
||||
* Returns the current Kirby instance
|
||||
*
|
||||
* @return App
|
||||
* @return Kirby\Cms\App
|
||||
*/
|
||||
public function kirby(): App
|
||||
public function kirby()
|
||||
{
|
||||
return $this->data['kirby'] ?? App::instance();
|
||||
}
|
||||
@@ -46,7 +52,7 @@ class KirbyTag extends \Kirby\Text\KirbyTag
|
||||
/**
|
||||
* Returns the parent model
|
||||
*
|
||||
* @return Page|Site|File|User
|
||||
* @return Kirby\Cms\Model|null
|
||||
*/
|
||||
public function parent()
|
||||
{
|
||||
|
@@ -2,11 +2,15 @@
|
||||
|
||||
namespace Kirby\Cms;
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Extension of `Kirby\Text\KirbyTags` that introduces
|
||||
* `kirbytags:before` and `kirbytags:after` hooks
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class KirbyTags extends \Kirby\Text\KirbyTags
|
||||
{
|
||||
@@ -42,9 +46,9 @@ class KirbyTags extends \Kirby\Text\KirbyTags
|
||||
* @param string $text
|
||||
* @param array $data
|
||||
* @param array $options
|
||||
* @return string
|
||||
* @return string|null
|
||||
*/
|
||||
protected static function hooks(array $hooks, string $text = null, array $data, array $options)
|
||||
protected static function hooks(array $hooks, string $text = null, array $data, array $options): ?string
|
||||
{
|
||||
foreach ($hooks as $hook) {
|
||||
$text = $hook->call($data['kirby'], $text, $data, $options);
|
||||
|
@@ -6,7 +6,6 @@ use Kirby\Data\Data;
|
||||
use Kirby\Exception\DuplicateException;
|
||||
use Kirby\Exception\Exception;
|
||||
use Kirby\Exception\InvalidArgumentException;
|
||||
use Kirby\Exception\LogicException;
|
||||
use Kirby\Exception\PermissionException;
|
||||
use Kirby\Toolkit\F;
|
||||
use Kirby\Toolkit\Str;
|
||||
@@ -24,8 +23,9 @@ use Throwable;
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link http://getkirby.com
|
||||
* @copyright Bastian Allgeier
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class Language extends Model
|
||||
{
|
||||
@@ -55,6 +55,11 @@ class Language extends Model
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* @var array|null
|
||||
*/
|
||||
protected $slugs;
|
||||
|
||||
/**
|
||||
* @var array|null
|
||||
*/
|
||||
@@ -81,13 +86,14 @@ class Language extends Model
|
||||
'direction',
|
||||
'locale',
|
||||
'name',
|
||||
'slugs',
|
||||
'translations',
|
||||
'url',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Improved var_dump output
|
||||
* Improved `var_dump` output
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
@@ -167,12 +173,11 @@ class Language extends Model
|
||||
* @param array $props
|
||||
* @return self
|
||||
*/
|
||||
public static function create(array $props): self
|
||||
public static function create(array $props)
|
||||
{
|
||||
$props['code'] = Str::slug($props['code'] ?? null);
|
||||
$kirby = App::instance();
|
||||
$languages = $kirby->languages();
|
||||
$site = $kirby->site();
|
||||
|
||||
// make the first language the default language
|
||||
if ($languages->count() === 0) {
|
||||
@@ -181,9 +186,8 @@ class Language extends Model
|
||||
|
||||
$language = new static($props);
|
||||
|
||||
if ($language->exists() === true) {
|
||||
throw new DuplicateException('The language already exists');
|
||||
}
|
||||
// validate the new language
|
||||
LanguageRules::create($language);
|
||||
|
||||
$language->save();
|
||||
|
||||
@@ -209,7 +213,6 @@ class Language extends Model
|
||||
|
||||
$kirby = App::instance();
|
||||
$languages = $kirby->languages();
|
||||
$site = $kirby->site();
|
||||
$code = $this->code();
|
||||
|
||||
if (F::remove($this->root()) !== true) {
|
||||
@@ -347,13 +350,50 @@ class Language extends Model
|
||||
return App::instance()->root('languages') . '/' . $this->code() . '.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the LanguageRouter instance
|
||||
* which is used to handle language specific
|
||||
* routes.
|
||||
*
|
||||
* @return Kirby\Cms\LanguageRouter
|
||||
*/
|
||||
public function router()
|
||||
{
|
||||
return new LanguageRouter($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get slug rules for language
|
||||
*
|
||||
* @internal
|
||||
* @return array
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
$code = $this->locale(LC_CTYPE);
|
||||
$code = Str::contains($code, '.') ? Str::before($code, '.') : $code;
|
||||
$file = $this->kirby()->root('i18n:rules') . '/' . $code . '.json';
|
||||
|
||||
if (F::exists($file) === false) {
|
||||
$file = $this->kirby()->root('i18n:rules') . '/' . Str::before($code, '_') . '.json';
|
||||
}
|
||||
|
||||
try {
|
||||
$data = Data::read($file);
|
||||
} catch (\Exception $e) {
|
||||
$data = [];
|
||||
}
|
||||
|
||||
return array_merge($data, $this->slugs());
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the language settings in the languages folder
|
||||
*
|
||||
* @internal
|
||||
* @return self
|
||||
*/
|
||||
public function save(): self
|
||||
public function save()
|
||||
{
|
||||
try {
|
||||
$existingData = Data::read($this->root());
|
||||
@@ -384,9 +424,9 @@ class Language extends Model
|
||||
* @param string $code
|
||||
* @return self
|
||||
*/
|
||||
protected function setCode(string $code): self
|
||||
protected function setCode(string $code)
|
||||
{
|
||||
$this->code = $code;
|
||||
$this->code = trim($code);
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -394,7 +434,7 @@ class Language extends Model
|
||||
* @param boolean $default
|
||||
* @return self
|
||||
*/
|
||||
protected function setDefault(bool $default = false): self
|
||||
protected function setDefault(bool $default = false)
|
||||
{
|
||||
$this->default = $default;
|
||||
return $this;
|
||||
@@ -404,7 +444,7 @@ class Language extends Model
|
||||
* @param string $direction
|
||||
* @return self
|
||||
*/
|
||||
protected function setDirection(string $direction = 'ltr'): self
|
||||
protected function setDirection(string $direction = 'ltr')
|
||||
{
|
||||
$this->direction = $direction === 'rtl' ? 'rtl' : 'ltr';
|
||||
return $this;
|
||||
@@ -414,7 +454,7 @@ class Language extends Model
|
||||
* @param string|array $locale
|
||||
* @return self
|
||||
*/
|
||||
protected function setLocale($locale = null): self
|
||||
protected function setLocale($locale = null)
|
||||
{
|
||||
if (is_array($locale)) {
|
||||
$this->locale = $locale;
|
||||
@@ -433,9 +473,19 @@ class Language extends Model
|
||||
* @param string $name
|
||||
* @return self
|
||||
*/
|
||||
protected function setName(string $name = null): self
|
||||
protected function setName(string $name = null)
|
||||
{
|
||||
$this->name = $name ?? $this->code;
|
||||
$this->name = trim($name ?? $this->code);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $slug
|
||||
* @return self
|
||||
*/
|
||||
protected function setSlugs(array $slugs = null)
|
||||
{
|
||||
$this->slugs = $slugs ?? [];
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -443,7 +493,7 @@ class Language extends Model
|
||||
* @param array $translations
|
||||
* @return self
|
||||
*/
|
||||
protected function setTranslations(array $translations = null): self
|
||||
protected function setTranslations(array $translations = null)
|
||||
{
|
||||
$this->translations = $translations ?? [];
|
||||
return $this;
|
||||
@@ -453,12 +503,22 @@ class Language extends Model
|
||||
* @param string $url
|
||||
* @return self
|
||||
*/
|
||||
protected function setUrl(string $url = null): self
|
||||
protected function setUrl(string $url = null)
|
||||
{
|
||||
$this->url = $url;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the custom slug rules for this language
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function slugs(): array
|
||||
{
|
||||
return $this->slugs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the most important
|
||||
* properties as array
|
||||
@@ -473,6 +533,7 @@ class Language extends Model
|
||||
'direction' => $this->direction(),
|
||||
'locale' => $this->locale(),
|
||||
'name' => $this->name(),
|
||||
'rules' => $this->rules(),
|
||||
'url' => $this->url()
|
||||
];
|
||||
}
|
||||
@@ -504,7 +565,7 @@ class Language extends Model
|
||||
* @param array $props
|
||||
* @return self
|
||||
*/
|
||||
public function update(array $props = null): self
|
||||
public function update(array $props = null)
|
||||
{
|
||||
$props['slug'] = Str::slug($props['slug'] ?? null);
|
||||
$kirby = App::instance();
|
||||
|
132
kirby/src/Cms/LanguageRouter.php
Executable file
132
kirby/src/Cms/LanguageRouter.php
Executable file
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
namespace Kirby\Cms;
|
||||
|
||||
use Exception;
|
||||
use Kirby\Exception\NotFoundException;
|
||||
use Kirby\Http\Router;
|
||||
use Kirby\Toolkit\A;
|
||||
use Kirby\Toolkit\Str;
|
||||
|
||||
/**
|
||||
* The language router is used internally
|
||||
* to handle language-specific (scoped) routes
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class LanguageRouter
|
||||
{
|
||||
|
||||
/**
|
||||
* The parent language
|
||||
*
|
||||
* @var Language
|
||||
*/
|
||||
protected $language;
|
||||
|
||||
/**
|
||||
* The router instance
|
||||
*
|
||||
* @var Router
|
||||
*/
|
||||
protected $router;
|
||||
|
||||
/**
|
||||
* Creates a new language router instance
|
||||
* for the given language
|
||||
*
|
||||
* @param Kirby\Cms\Language $language
|
||||
*/
|
||||
public function __construct(Language $language)
|
||||
{
|
||||
$this->language = $language;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches all scoped routes for the
|
||||
* current language from the Kirby instance
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function routes(): array
|
||||
{
|
||||
$language = $this->language;
|
||||
$kirby = $language->kirby();
|
||||
$routes = $kirby->routes();
|
||||
|
||||
// only keep the scoped language routes
|
||||
$routes = array_values(array_filter($routes, function ($route) use ($language) {
|
||||
|
||||
// no language scope
|
||||
if (empty($route['language']) === true) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// wildcard
|
||||
if ($route['language'] === '*') {
|
||||
return true;
|
||||
}
|
||||
|
||||
// get all applicable languages
|
||||
$languages = Str::split(strtolower($route['language']), '|');
|
||||
|
||||
// validate the language
|
||||
return in_array($language->code(), $languages) === true;
|
||||
}));
|
||||
|
||||
// add the page-scope if necessary
|
||||
foreach ($routes as $index => $route) {
|
||||
if ($pageId = ($route['page'] ?? null)) {
|
||||
if ($page = $kirby->page($pageId)) {
|
||||
|
||||
// convert string patterns to arrays
|
||||
$patterns = A::wrap($route['pattern']);
|
||||
|
||||
// prefix all patterns with the page slug
|
||||
$patterns = array_map(function ($pattern) use ($page, $language) {
|
||||
return $page->uri($language) . '/' . $pattern;
|
||||
}, $patterns);
|
||||
|
||||
// reinject the pattern and the full page object
|
||||
$routes[$index]['pattern'] = $patterns;
|
||||
$routes[$index]['page'] = $page;
|
||||
} else {
|
||||
throw new NotFoundException('The page "' . $pageId . '" does not exist');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $routes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper around the Router::call method
|
||||
* that injects the Language instance and
|
||||
* if needed also the Page as arguments.
|
||||
*
|
||||
* @param string|null $path
|
||||
* @return mixed
|
||||
*/
|
||||
public function call(string $path = null)
|
||||
{
|
||||
$language = $this->language;
|
||||
$kirby = $language->kirby();
|
||||
$router = new Router($this->routes());
|
||||
|
||||
try {
|
||||
return $router->call($path, $kirby->request()->method(), function ($route) use ($language) {
|
||||
if ($page = $route->page()) {
|
||||
return $route->action()->call($route, $language, $page, ...$route->arguments());
|
||||
} else {
|
||||
return $route->action()->call($route, $language, ...$route->arguments());
|
||||
}
|
||||
});
|
||||
} catch (Exception $e) {
|
||||
return $kirby->resolve($path, $language->code());
|
||||
}
|
||||
}
|
||||
}
|
55
kirby/src/Cms/LanguageRules.php
Executable file
55
kirby/src/Cms/LanguageRules.php
Executable file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Kirby\Cms;
|
||||
|
||||
use Kirby\Exception\DuplicateException;
|
||||
use Kirby\Exception\InvalidArgumentException;
|
||||
use Kirby\Exception\LogicException;
|
||||
use Kirby\Exception\PermissionException;
|
||||
use Kirby\Toolkit\Str;
|
||||
|
||||
/**
|
||||
* Validators for all language actions
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class LanguageRules
|
||||
{
|
||||
public static function create(Language $language): bool
|
||||
{
|
||||
if (Str::length($language->code()) < 2) {
|
||||
throw new InvalidArgumentException([
|
||||
'key' => 'language.code',
|
||||
'data' => [
|
||||
'code' => $language->code(),
|
||||
'name' => $language->name()
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
if (Str::length($language->name()) < 1) {
|
||||
throw new InvalidArgumentException([
|
||||
'key' => 'language.name',
|
||||
'data' => [
|
||||
'code' => $language->code(),
|
||||
'name' => $language->name()
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
if ($language->exists() === true) {
|
||||
throw new DuplicateException([
|
||||
'key' => 'language.duplicate',
|
||||
'data' => [
|
||||
'code' => $language->code()
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -6,6 +6,12 @@ use Kirby\Toolkit\F;
|
||||
|
||||
/**
|
||||
* A collection of all defined site languages
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class Languages extends Collection
|
||||
{
|
||||
@@ -25,9 +31,9 @@ class Languages extends Collection
|
||||
*
|
||||
* @internal
|
||||
* @param array $props
|
||||
* @return Language
|
||||
* @return Kirby\Cms\Language
|
||||
*/
|
||||
public function create(array $props): Language
|
||||
public function create(array $props)
|
||||
{
|
||||
return Language::create($props);
|
||||
}
|
||||
@@ -35,9 +41,9 @@ class Languages extends Collection
|
||||
/**
|
||||
* Returns the default language
|
||||
*
|
||||
* @return Language|null
|
||||
* @return Kirby\Cms\Language|null
|
||||
*/
|
||||
public function default(): ?Language
|
||||
public function default()
|
||||
{
|
||||
if ($language = $this->findBy('isDefault', true)) {
|
||||
return $language;
|
||||
@@ -48,9 +54,9 @@ class Languages extends Collection
|
||||
|
||||
/**
|
||||
* @deprecated 3.0.0 Use `Languages::default()`instead
|
||||
* @return Language|null
|
||||
* @return Kirby\Cms\Language|null
|
||||
*/
|
||||
public function findDefault(): ?Language
|
||||
public function findDefault()
|
||||
{
|
||||
return $this->default();
|
||||
}
|
||||
@@ -61,7 +67,7 @@ class Languages extends Collection
|
||||
* @internal
|
||||
* @return self
|
||||
*/
|
||||
public static function load(): self
|
||||
public static function load()
|
||||
{
|
||||
$languages = new static;
|
||||
$files = glob(App::instance()->root('languages') . '/*.php');
|
||||
|
@@ -5,71 +5,29 @@ namespace Kirby\Cms;
|
||||
use Kirby\Data\Data;
|
||||
use Kirby\Toolkit\Dir;
|
||||
use Kirby\Toolkit\F;
|
||||
use Kirby\Toolkit\Str;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Handles all tasks to get the Media API
|
||||
* up and running and link files correctly
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class Media
|
||||
{
|
||||
|
||||
/**
|
||||
* Tries to find a job file for the
|
||||
* given filename and then calls the thumb
|
||||
* component to create a thumbnail accordingly
|
||||
*
|
||||
* @param Model $model
|
||||
* @param string $hash
|
||||
* @param string $filename
|
||||
* @return Response|false
|
||||
*/
|
||||
public static function thumb($model, string $hash, string $filename)
|
||||
{
|
||||
$kirby = App::instance();
|
||||
|
||||
if (is_string($model) === true) {
|
||||
// assets
|
||||
$root = $kirby->root('media') . '/assets/' . $model . '/' . $hash;
|
||||
} else {
|
||||
// model files
|
||||
$root = $model->mediaRoot() . '/' . $hash;
|
||||
}
|
||||
|
||||
try {
|
||||
$thumb = $root . '/' . $filename;
|
||||
$job = $root . '/.jobs/' . $filename . '.json';
|
||||
$options = Data::read($job);
|
||||
|
||||
if (empty($options) === true) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_string($model) === true) {
|
||||
$source = $kirby->root('index') . '/' . $model . '/' . $options['filename'];
|
||||
} else {
|
||||
$source = $model->file($options['filename'])->root();
|
||||
}
|
||||
|
||||
$kirby->thumb($source, $thumb, $options);
|
||||
|
||||
F::remove($job);
|
||||
|
||||
return Response::file($thumb);
|
||||
} catch (Throwable $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to find a file by model and filename
|
||||
* and to copy it to the media folder.
|
||||
*
|
||||
* @param Model $model
|
||||
* @param Kirby\Cms\Model $model
|
||||
* @param string $hash
|
||||
* @param string $filename
|
||||
* @return Response|false
|
||||
* @return Kirby\Cms\Response|false
|
||||
*/
|
||||
public static function link(Model $model = null, string $hash, string $filename)
|
||||
{
|
||||
@@ -117,6 +75,56 @@ class Media
|
||||
return F::copy($src, $dest, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to find a job file for the
|
||||
* given filename and then calls the thumb
|
||||
* component to create a thumbnail accordingly
|
||||
*
|
||||
* @param Kirby\Cms\Model $model
|
||||
* @param string $hash
|
||||
* @param string $filename
|
||||
* @return Kirby\Cms\Response|false
|
||||
*/
|
||||
public static function thumb($model, string $hash, string $filename)
|
||||
{
|
||||
$kirby = App::instance();
|
||||
|
||||
if (is_string($model) === true) {
|
||||
// assets
|
||||
$root = $kirby->root('media') . '/assets/' . $model . '/' . $hash;
|
||||
} else {
|
||||
// model files
|
||||
$root = $model->mediaRoot() . '/' . $hash;
|
||||
}
|
||||
|
||||
try {
|
||||
$thumb = $root . '/' . $filename;
|
||||
$job = $root . '/.jobs/' . $filename . '.json';
|
||||
$options = Data::read($job);
|
||||
|
||||
if (empty($options) === true) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_string($model) === true) {
|
||||
$source = $kirby->root('index') . '/' . $model . '/' . $options['filename'];
|
||||
} else {
|
||||
$source = $model->file($options['filename'])->root();
|
||||
}
|
||||
|
||||
try {
|
||||
$kirby->thumb($source, $thumb, $options);
|
||||
F::remove($job);
|
||||
return Response::file($thumb);
|
||||
} catch (Throwable $e) {
|
||||
F::remove($thumb);
|
||||
return Response::file($source);
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all versions of the given filename
|
||||
* within the parent directory
|
||||
|
@@ -2,13 +2,16 @@
|
||||
|
||||
namespace Kirby\Cms;
|
||||
|
||||
use stdClass;
|
||||
use ReflectionMethod;
|
||||
use Kirby\Toolkit\Properties;
|
||||
use Kirby\Toolkit\Str;
|
||||
|
||||
/**
|
||||
* Foundation for Page, Site, File and User models.
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
abstract class Model
|
||||
{
|
||||
@@ -17,14 +20,14 @@ abstract class Model
|
||||
/**
|
||||
* The parent Kirby instance
|
||||
*
|
||||
* @var App
|
||||
* @var Kirby\Cms\App
|
||||
*/
|
||||
public static $kirby;
|
||||
|
||||
/**
|
||||
* The parent Site instance
|
||||
* The parent site instance
|
||||
*
|
||||
* @var Site
|
||||
* @var Kirby\Cms\Site
|
||||
*/
|
||||
protected $site;
|
||||
|
||||
@@ -34,7 +37,7 @@ abstract class Model
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
public function __toString(): string
|
||||
{
|
||||
return $this->id();
|
||||
}
|
||||
@@ -52,9 +55,9 @@ abstract class Model
|
||||
/**
|
||||
* Returns the parent Kirby instance
|
||||
*
|
||||
* @return App|null
|
||||
* @return Kirby\Cms\App
|
||||
*/
|
||||
public function kirby(): App
|
||||
public function kirby()
|
||||
{
|
||||
return static::$kirby = static::$kirby ?? App::instance();
|
||||
}
|
||||
@@ -62,7 +65,7 @@ abstract class Model
|
||||
/**
|
||||
* Returns the parent Site instance
|
||||
*
|
||||
* @return Site|null
|
||||
* @return Kirby\Cms\Site
|
||||
*/
|
||||
public function site()
|
||||
{
|
||||
@@ -72,7 +75,7 @@ abstract class Model
|
||||
/**
|
||||
* Setter for the parent Kirby object
|
||||
*
|
||||
* @param Kirby|null $kirby
|
||||
* @param Kirby\Cms\App|null $kirby
|
||||
* @return self
|
||||
*/
|
||||
protected function setKirby(App $kirby = null)
|
||||
@@ -82,10 +85,10 @@ abstract class Model
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for the parent Site object
|
||||
* Setter for the parent site object
|
||||
*
|
||||
* @internal
|
||||
* @param Site|null $site
|
||||
* @param Kirby\Cms\Site|null $site
|
||||
* @return self
|
||||
*/
|
||||
public function setSite(Site $site = null)
|
||||
|
@@ -2,6 +2,17 @@
|
||||
|
||||
namespace Kirby\Cms;
|
||||
|
||||
use Kirby\Toolkit\A;
|
||||
|
||||
/**
|
||||
* ModelPermissions
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
abstract class ModelPermissions
|
||||
{
|
||||
protected $category;
|
||||
@@ -10,7 +21,7 @@ abstract class ModelPermissions
|
||||
protected $permissions;
|
||||
protected $user;
|
||||
|
||||
public function __call(string $method, array $arguments = [])
|
||||
public function __call(string $method, array $arguments = []): bool
|
||||
{
|
||||
return $this->can($method);
|
||||
}
|
||||
@@ -24,7 +35,7 @@ abstract class ModelPermissions
|
||||
}
|
||||
|
||||
/**
|
||||
* Improved var_dump output
|
||||
* Improved `var_dump` output
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
@@ -35,16 +46,32 @@ abstract class ModelPermissions
|
||||
|
||||
public function can(string $action): bool
|
||||
{
|
||||
if ($this->user->role()->id() === 'nobody') {
|
||||
$role = $this->user->role()->id();
|
||||
|
||||
if ($role === 'nobody') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// check for a custom overall can method
|
||||
if (method_exists($this, 'can' . $action) === true && $this->{'can' . $action}() === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($this->options[$action]) === true && $this->options[$action] === false) {
|
||||
return false;
|
||||
// evaluate the blueprint options block
|
||||
if (isset($this->options[$action]) === true) {
|
||||
$options = $this->options[$action];
|
||||
|
||||
if ($options === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($options === true) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (is_array($options) === true && A::isAssociative($options) === true) {
|
||||
return $options[$role] ?? $options['*'] ?? false;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->permissions->for($this->category, $action);
|
||||
|
@@ -4,33 +4,38 @@ namespace Kirby\Cms;
|
||||
|
||||
use Closure;
|
||||
use Kirby\Data\Data;
|
||||
use Kirby\Exception\Exception;
|
||||
use Kirby\Exception\InvalidArgumentException;
|
||||
use Kirby\Exception\LogicException;
|
||||
use Kirby\Toolkit\A;
|
||||
use Kirby\Toolkit\F;
|
||||
use Kirby\Toolkit\Str;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* ModelWithContent
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
abstract class ModelWithContent extends Model
|
||||
{
|
||||
|
||||
/**
|
||||
* The content
|
||||
*
|
||||
* @var Content
|
||||
* @var Kirby\Cms\Content
|
||||
*/
|
||||
public $content;
|
||||
|
||||
/**
|
||||
* @var Translations
|
||||
* @var Kirby\Cms\Translations
|
||||
*/
|
||||
public $translations;
|
||||
|
||||
/**
|
||||
* Returns the blueprint of the model
|
||||
*
|
||||
* @return Blueprint
|
||||
* @return Kirby\Cms\Blueprint
|
||||
*/
|
||||
abstract public function blueprint();
|
||||
|
||||
@@ -48,9 +53,9 @@ abstract class ModelWithContent extends Model
|
||||
* Returns the content
|
||||
*
|
||||
* @param string $languageCode
|
||||
* @return Content
|
||||
* @return Kirby\Cms\Content
|
||||
*/
|
||||
public function content(string $languageCode = null): Content
|
||||
public function content(string $languageCode = null)
|
||||
{
|
||||
|
||||
// single language support
|
||||
@@ -120,6 +125,26 @@ abstract class ModelWithContent extends Model
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array with all content files
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function contentFiles(): array
|
||||
{
|
||||
if ($this->kirby()->multilang() === true) {
|
||||
$files = [];
|
||||
foreach ($this->kirby()->languages()->codes() as $code) {
|
||||
$files[] = $this->contentFile($code);
|
||||
}
|
||||
return $files;
|
||||
} else {
|
||||
return [
|
||||
$this->contentFile()
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the content that should be written
|
||||
* to the text file
|
||||
@@ -232,6 +257,148 @@ abstract class ModelWithContent extends Model
|
||||
return Form::for($this)->hasErrors() === false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the lock object for this model
|
||||
*
|
||||
* @return Kirby\Cms\ContentLock
|
||||
*/
|
||||
public function lock()
|
||||
{
|
||||
return new ContentLock($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the panel icon definition
|
||||
*
|
||||
* @internal
|
||||
* @param array $params
|
||||
* @return array
|
||||
*/
|
||||
public function panelIcon(array $params = null): array
|
||||
{
|
||||
$defaults = [
|
||||
'type' => 'page',
|
||||
'ratio' => null,
|
||||
'back' => 'pattern',
|
||||
'color' => '#c5c9c6',
|
||||
];
|
||||
|
||||
return array_merge($defaults, $params ?? []);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param string|array|false $settings
|
||||
* @return array|null
|
||||
*/
|
||||
public function panelImage($settings = null): ?array
|
||||
{
|
||||
$defaults = [
|
||||
'ratio' => '3/2',
|
||||
'back' => 'pattern',
|
||||
'cover' => false
|
||||
];
|
||||
|
||||
// switch the image off
|
||||
if ($settings === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (is_string($settings) === true) {
|
||||
$settings = [
|
||||
'query' => $settings
|
||||
];
|
||||
}
|
||||
|
||||
if ($image = $this->panelImageSource($settings['query'] ?? null)) {
|
||||
|
||||
// main url
|
||||
$settings['url'] = $image->url();
|
||||
|
||||
// for cards
|
||||
$settings['cards'] = [
|
||||
'url' => 'data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw',
|
||||
'srcset' => $image->srcset([
|
||||
352,
|
||||
864,
|
||||
1408,
|
||||
])
|
||||
];
|
||||
|
||||
// for lists
|
||||
$settings['list'] = [
|
||||
'url' => 'data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw',
|
||||
'srcset' => $image->srcset([
|
||||
'1x' => [
|
||||
'width' => 38,
|
||||
'height' => 38,
|
||||
'crop' => 'center'
|
||||
],
|
||||
'2x' => [
|
||||
'width' => 76,
|
||||
'height' => 76,
|
||||
'crop' => 'center'
|
||||
],
|
||||
])
|
||||
];
|
||||
|
||||
unset($settings['query']);
|
||||
}
|
||||
|
||||
return array_merge($defaults, (array)$settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the image file object based on provided query
|
||||
*
|
||||
* @internal
|
||||
* @param string|null $query
|
||||
* @return Kirby\Cms\File|Kirby\Cms\Asset|null
|
||||
*/
|
||||
protected function panelImageSource(string $query = null)
|
||||
{
|
||||
$image = $this->query($query ?? null);
|
||||
|
||||
// validate the query result
|
||||
if (is_a($image, File::class) === false && is_a($image, Asset::class) === false) {
|
||||
$image = null;
|
||||
}
|
||||
|
||||
// fallback for files
|
||||
if ($image === null && is_a($this, File::class) === true && $this->isViewable() === true) {
|
||||
$image = $this;
|
||||
}
|
||||
|
||||
return $image;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a string query, starting from the model
|
||||
*
|
||||
* @internal
|
||||
* @param string|null $query
|
||||
* @param string|null $expect
|
||||
* @return mixed
|
||||
*/
|
||||
public function query(string $query = null, string $expect = null)
|
||||
{
|
||||
if ($query === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$result = Str::query($query, [
|
||||
'kirby' => $this->kirby(),
|
||||
'site' => is_a($this, Site::class) ? $this : $this->site(),
|
||||
static::CLASS_ALIAS => $this
|
||||
]);
|
||||
|
||||
if ($expect !== null && is_a($result, $expect) !== true) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the content from the content file
|
||||
*
|
||||
@@ -251,7 +418,7 @@ abstract class ModelWithContent extends Model
|
||||
/**
|
||||
* Returns the absolute path to the model
|
||||
*
|
||||
* @return string
|
||||
* @return string|null
|
||||
*/
|
||||
abstract public function root(): ?string;
|
||||
|
||||
@@ -330,7 +497,7 @@ abstract class ModelWithContent extends Model
|
||||
/**
|
||||
* Sets the Content object
|
||||
*
|
||||
* @param Content|null $content
|
||||
* @param array|null $content
|
||||
* @return self
|
||||
*/
|
||||
protected function setContent(array $content = null)
|
||||
@@ -364,12 +531,33 @@ abstract class ModelWithContent extends Model
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* String template builder
|
||||
*
|
||||
* @param string|null $template
|
||||
* @return string
|
||||
*/
|
||||
public function toString(string $template = null): string
|
||||
{
|
||||
if ($template === null) {
|
||||
return $this->id();
|
||||
}
|
||||
|
||||
$result = Str::template($template, [
|
||||
'kirby' => $this->kirby(),
|
||||
'site' => is_a($this, Site::class) ? $this : $this->site(),
|
||||
static::CLASS_ALIAS => $this
|
||||
]);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a single translation by language code
|
||||
* If no code is specified the current translation is returned
|
||||
*
|
||||
* @param string $languageCode
|
||||
* @return Translation|null
|
||||
* @param string|null $languageCode
|
||||
* @return Kirby\Cms\ContentTranslation|null
|
||||
*/
|
||||
public function translation(string $languageCode = null)
|
||||
{
|
||||
@@ -379,7 +567,7 @@ abstract class ModelWithContent extends Model
|
||||
/**
|
||||
* Returns the translations collection
|
||||
*
|
||||
* @return Collection
|
||||
* @return Kirby\Cms\Collection
|
||||
*/
|
||||
public function translations()
|
||||
{
|
||||
|
@@ -2,8 +2,6 @@
|
||||
|
||||
namespace Kirby\Cms;
|
||||
|
||||
use Kirby\Toolkit\Obj;
|
||||
|
||||
/**
|
||||
* The Nest class converts any array type
|
||||
* into a Kirby style collection/object. This
|
||||
@@ -11,6 +9,12 @@ use Kirby\Toolkit\Obj;
|
||||
* with Kirby queries.
|
||||
*
|
||||
* REFACTOR: move this to the toolkit
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class Nest
|
||||
{
|
||||
|
@@ -5,6 +5,15 @@ namespace Kirby\Cms;
|
||||
use Closure;
|
||||
use Kirby\Toolkit\Collection as BaseCollection;
|
||||
|
||||
/**
|
||||
* NestCollection
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class NestCollection extends BaseCollection
|
||||
{
|
||||
|
||||
|
@@ -4,6 +4,15 @@ namespace Kirby\Cms;
|
||||
|
||||
use Kirby\Toolkit\Obj;
|
||||
|
||||
/**
|
||||
* NestObject
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class NestObject extends Obj
|
||||
{
|
||||
|
||||
|
@@ -2,15 +2,12 @@
|
||||
|
||||
namespace Kirby\Cms;
|
||||
|
||||
use Closure;
|
||||
use Kirby\Data\Data;
|
||||
use Kirby\Exception\Exception;
|
||||
use Kirby\Exception\NotFoundException;
|
||||
use Kirby\Http\Uri;
|
||||
use Kirby\Toolkit\A;
|
||||
use Kirby\Toolkit\F;
|
||||
use Kirby\Toolkit\Str;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* The `$page` object is the heart and
|
||||
@@ -20,8 +17,9 @@ use Throwable;
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link http://getkirby.com
|
||||
* @copyright Bastian Allgeier
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class Page extends ModelWithContent
|
||||
{
|
||||
@@ -51,7 +49,7 @@ class Page extends ModelWithContent
|
||||
/**
|
||||
* The PageBlueprint object
|
||||
*
|
||||
* @var PageBlueprint
|
||||
* @var Kirby\Cms\PageBlueprint
|
||||
*/
|
||||
protected $blueprint;
|
||||
|
||||
@@ -94,7 +92,7 @@ class Page extends ModelWithContent
|
||||
* The template, that should be loaded
|
||||
* if it exists
|
||||
*
|
||||
* @var Template
|
||||
* @var Kirby\Cms\Template
|
||||
*/
|
||||
protected $intendedTemplate;
|
||||
|
||||
@@ -113,7 +111,7 @@ class Page extends ModelWithContent
|
||||
/**
|
||||
* The parent page
|
||||
*
|
||||
* @var Page|null
|
||||
* @var Kirby\Cms\Page|null
|
||||
*/
|
||||
protected $parent;
|
||||
|
||||
@@ -127,7 +125,7 @@ class Page extends ModelWithContent
|
||||
/**
|
||||
* The parent Site object
|
||||
*
|
||||
* @var Site|null
|
||||
* @var Kirby\Cms\Site|null
|
||||
*/
|
||||
protected $site;
|
||||
|
||||
@@ -190,7 +188,7 @@ class Page extends ModelWithContent
|
||||
}
|
||||
|
||||
/**
|
||||
* Improved var_dump output
|
||||
* Improved `var_dump` output
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
@@ -224,9 +222,9 @@ class Page extends ModelWithContent
|
||||
/**
|
||||
* Returns the blueprint object
|
||||
*
|
||||
* @return PageBlueprint
|
||||
* @return Kirby\Cms\PageBlueprint
|
||||
*/
|
||||
public function blueprint(): PageBlueprint
|
||||
public function blueprint()
|
||||
{
|
||||
if (is_a($this->blueprint, 'Kirby\Cms\PageBlueprint') === true) {
|
||||
return $this->blueprint;
|
||||
@@ -247,7 +245,7 @@ class Page extends ModelWithContent
|
||||
}
|
||||
|
||||
$blueprints = [];
|
||||
$templates = $this->blueprint()->options()['changeTemplate'] ?? [];
|
||||
$templates = $this->blueprint()->changeTemplate() ?? $this->blueprint()->options()['changeTemplate'] ?? [];
|
||||
$currentTemplate = $this->intendedTemplate()->name();
|
||||
|
||||
if (is_array($templates) === false) {
|
||||
@@ -394,7 +392,7 @@ class Page extends ModelWithContent
|
||||
}
|
||||
|
||||
if ($parent = $this->parent()) {
|
||||
return $this->diruri = $this->parent()->diruri() . '/' . $dirname;
|
||||
return $this->diruri = $parent->diruri() . '/' . $dirname;
|
||||
} else {
|
||||
return $this->diruri = $dirname;
|
||||
}
|
||||
@@ -436,7 +434,7 @@ class Page extends ModelWithContent
|
||||
* @internal
|
||||
* @return self
|
||||
*/
|
||||
public static function factory($props): self
|
||||
public static function factory($props)
|
||||
{
|
||||
if (empty($props['model']) === false) {
|
||||
return static::model($props['model'], $props);
|
||||
@@ -479,7 +477,7 @@ class Page extends ModelWithContent
|
||||
* Returns the template that should be
|
||||
* loaded if it exists.
|
||||
*
|
||||
* @return Template
|
||||
* @return Kirby\Cms\Template
|
||||
*/
|
||||
public function intendedTemplate()
|
||||
{
|
||||
@@ -516,7 +514,7 @@ class Page extends ModelWithContent
|
||||
/**
|
||||
* Compares the current object with the given page object
|
||||
*
|
||||
* @param Page|string $page
|
||||
* @param Kirby\Cms\Page|string $page
|
||||
* @return bool
|
||||
*/
|
||||
public function is($page): bool
|
||||
@@ -619,7 +617,7 @@ class Page extends ModelWithContent
|
||||
/**
|
||||
* Checks if the page is a child of the given page
|
||||
*
|
||||
* @param string|Page $parent
|
||||
* @param Kirby\Cms\Page|string $parent
|
||||
* @return boolean
|
||||
*/
|
||||
public function isChildOf($parent): bool
|
||||
@@ -634,7 +632,7 @@ class Page extends ModelWithContent
|
||||
/**
|
||||
* Checks if the page is a descendant of the given page
|
||||
*
|
||||
* @param string|Page $parent
|
||||
* @param Kirby\Cms\Page|string $parent
|
||||
* @return boolean
|
||||
*/
|
||||
public function isDescendantOf($parent): bool
|
||||
@@ -785,6 +783,15 @@ class Page extends ModelWithContent
|
||||
return $this->isListed() === false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated 3.0.0 Use `Page::isListed()` intead
|
||||
* @return bool
|
||||
*/
|
||||
public function isVisible(): bool
|
||||
{
|
||||
return $this->isListed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the page access is verified.
|
||||
* This is only used for drafts so far.
|
||||
@@ -795,7 +802,10 @@ class Page extends ModelWithContent
|
||||
*/
|
||||
public function isVerified(string $token = null)
|
||||
{
|
||||
if ($this->isDraft() === false && !$draft = $this->parents()->findBy('status', 'draft')) {
|
||||
if (
|
||||
$this->isDraft() === false &&
|
||||
$this->parents()->findBy('status', 'draft') === null
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -806,15 +816,6 @@ class Page extends ModelWithContent
|
||||
return $this->token() === $token;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated 3.0.0 Use `Page::isListed()` intead
|
||||
* @return bool
|
||||
*/
|
||||
public function isVisible(): bool
|
||||
{
|
||||
return $this->isListed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the root to the media folder for the page
|
||||
*
|
||||
@@ -843,7 +844,7 @@ class Page extends ModelWithContent
|
||||
* @internal
|
||||
* @param string $name
|
||||
* @param array $props
|
||||
* @return Page
|
||||
* @return self
|
||||
*/
|
||||
public static function model(string $name, array $props = [])
|
||||
{
|
||||
@@ -875,7 +876,7 @@ class Page extends ModelWithContent
|
||||
*
|
||||
* @return integer|null
|
||||
*/
|
||||
public function num()
|
||||
public function num(): ?int
|
||||
{
|
||||
return $this->num;
|
||||
}
|
||||
@@ -890,22 +891,16 @@ class Page extends ModelWithContent
|
||||
*/
|
||||
public function panelIcon(array $params = null): array
|
||||
{
|
||||
$options = [
|
||||
'type' => 'page',
|
||||
'ratio' => $params['ratio'] ?? null,
|
||||
'back' => $params['back'] ?? 'black',
|
||||
];
|
||||
|
||||
if ($icon = $this->blueprint()->icon()) {
|
||||
$options['type'] = $icon;
|
||||
$params['type'] = $icon;
|
||||
|
||||
// check for emojis
|
||||
if (strlen($icon) !== Str::length($icon)) {
|
||||
$options['emoji'] = true;
|
||||
$params['emoji'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return $options;
|
||||
return parent::panelIcon($params);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -921,37 +916,19 @@ class Page extends ModelWithContent
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the image file object based on provided query
|
||||
*
|
||||
* @internal
|
||||
* @param string|array|false $settings
|
||||
* @param array|null $thumbSettings
|
||||
* @return array|null
|
||||
* @param string|null $query
|
||||
* @return Kirby\Cms\File|Kirby\Cms\Asset|null
|
||||
*/
|
||||
public function panelImage($settings = null, array $thumbSettings = null): ?array
|
||||
protected function panelImageSource(string $query = null)
|
||||
{
|
||||
$defaults = [
|
||||
'ratio' => '3/2',
|
||||
'back' => 'pattern',
|
||||
'cover' => false
|
||||
];
|
||||
|
||||
// switch the image off
|
||||
if ($settings === false) {
|
||||
return null;
|
||||
if ($query === null) {
|
||||
$query = 'page.image';
|
||||
}
|
||||
|
||||
if (is_string($settings) === true) {
|
||||
$settings = [
|
||||
'query' => $settings
|
||||
];
|
||||
}
|
||||
|
||||
if ($image = $this->query($settings['query'] ?? 'page.image', 'Kirby\Cms\File')) {
|
||||
$settings['url'] = $image->thumb($thumbSettings)->url(true) . '?t=' . $image->modified();
|
||||
|
||||
unset($settings['query']);
|
||||
}
|
||||
|
||||
return array_merge($defaults, (array)$settings);
|
||||
return parent::panelImageSource($query);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -965,6 +942,31 @@ class Page extends ModelWithContent
|
||||
return 'pages/' . $this->panelId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the response data for page pickers
|
||||
* and page fields
|
||||
*
|
||||
* @param array|null $params
|
||||
* @return array
|
||||
*/
|
||||
public function panelPickerData(array $params = []): array
|
||||
{
|
||||
$image = $this->panelImage($params['image'] ?? []);
|
||||
$icon = $this->panelIcon($image);
|
||||
|
||||
return [
|
||||
'dragText' => $this->dragText(),
|
||||
'hasChildren' => $this->hasChildren(),
|
||||
'icon' => $icon,
|
||||
'id' => $this->id(),
|
||||
'image' => $image,
|
||||
'info' => $this->toString($params['info'] ?? false),
|
||||
'link' => $this->panelUrl(true),
|
||||
'text' => $this->toString($params['text'] ?? '{{ page.title }}'),
|
||||
'url' => $this->url(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the url to the editing view
|
||||
* in the panel
|
||||
@@ -984,7 +986,7 @@ class Page extends ModelWithContent
|
||||
/**
|
||||
* Returns the parent Page object
|
||||
*
|
||||
* @return Page|null
|
||||
* @return Kirby\Cms\Page|null
|
||||
*/
|
||||
public function parent()
|
||||
{
|
||||
@@ -1012,7 +1014,7 @@ class Page extends ModelWithContent
|
||||
* or the Site
|
||||
*
|
||||
* @internal
|
||||
* @return Page|Site
|
||||
* @return Kirby\Cms\Page|Kirby\Cms\Site
|
||||
*/
|
||||
public function parentModel()
|
||||
{
|
||||
@@ -1022,9 +1024,9 @@ class Page extends ModelWithContent
|
||||
/**
|
||||
* Returns a list of all parents and their parents recursively
|
||||
*
|
||||
* @return Pages
|
||||
* @return Kirby\Cms\Pages
|
||||
*/
|
||||
public function parents(): Pages
|
||||
public function parents()
|
||||
{
|
||||
$parents = new Pages;
|
||||
$page = $this->parent();
|
||||
@@ -1040,7 +1042,7 @@ class Page extends ModelWithContent
|
||||
/**
|
||||
* Returns the permissions object for this page
|
||||
*
|
||||
* @return PagePermissions
|
||||
* @return Kirby\Cms\PagePermissions
|
||||
*/
|
||||
public function permissions()
|
||||
{
|
||||
@@ -1077,33 +1079,6 @@ class Page extends ModelWithContent
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a string query, starting from the model
|
||||
*
|
||||
* @internal
|
||||
* @param string|null $query
|
||||
* @param string|null $expect
|
||||
* @return mixed
|
||||
*/
|
||||
public function query(string $query = null, string $expect = null)
|
||||
{
|
||||
if ($query === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$result = Str::query($query, [
|
||||
'kirby' => $this->kirby(),
|
||||
'site' => $this->site(),
|
||||
'page' => $this
|
||||
]);
|
||||
|
||||
if ($expect !== null && is_a($result, $expect) !== true) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the page with the given data.
|
||||
*
|
||||
@@ -1171,12 +1146,12 @@ class Page extends ModelWithContent
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @return Template
|
||||
* @return Kirby\Cms\Template
|
||||
*/
|
||||
public function representation($type)
|
||||
{
|
||||
$kirby = $this->kirby();
|
||||
$template = $this->template();
|
||||
$template = $this->intendedTemplate();
|
||||
$representation = $kirby->template($template->name(), $type);
|
||||
|
||||
if ($representation->exists() === true) {
|
||||
@@ -1202,7 +1177,7 @@ class Page extends ModelWithContent
|
||||
* which is being used in various methods
|
||||
* to check for valid actions and input.
|
||||
*
|
||||
* @return PageRules
|
||||
* @return Kirby\Cms\PageRules
|
||||
*/
|
||||
protected function rules()
|
||||
{
|
||||
@@ -1214,7 +1189,7 @@ class Page extends ModelWithContent
|
||||
*
|
||||
* @param string $query
|
||||
* @param array $params
|
||||
* @return Pages
|
||||
* @return Kirby\Cms\Pages
|
||||
*/
|
||||
public function search(string $query = null, $params = [])
|
||||
{
|
||||
@@ -1227,7 +1202,7 @@ class Page extends ModelWithContent
|
||||
* @param array|null $blueprint
|
||||
* @return self
|
||||
*/
|
||||
protected function setBlueprint(array $blueprint = null): self
|
||||
protected function setBlueprint(array $blueprint = null)
|
||||
{
|
||||
if ($blueprint !== null) {
|
||||
$blueprint['model'] = $this;
|
||||
@@ -1245,7 +1220,7 @@ class Page extends ModelWithContent
|
||||
* @param string $dirname
|
||||
* @return self
|
||||
*/
|
||||
protected function setDirname(string $dirname = null): self
|
||||
protected function setDirname(string $dirname = null)
|
||||
{
|
||||
$this->dirname = $dirname;
|
||||
return $this;
|
||||
@@ -1257,7 +1232,7 @@ class Page extends ModelWithContent
|
||||
* @param boolean $isDraft
|
||||
* @return self
|
||||
*/
|
||||
protected function setIsDraft(bool $isDraft = null): self
|
||||
protected function setIsDraft(bool $isDraft = null)
|
||||
{
|
||||
$this->isDraft = $isDraft ?? false;
|
||||
return $this;
|
||||
@@ -1269,7 +1244,7 @@ class Page extends ModelWithContent
|
||||
* @param integer $num
|
||||
* @return self
|
||||
*/
|
||||
protected function setNum(int $num = null): self
|
||||
protected function setNum(int $num = null)
|
||||
{
|
||||
$this->num = $num === null ? $num : intval($num);
|
||||
return $this;
|
||||
@@ -1278,10 +1253,10 @@ class Page extends ModelWithContent
|
||||
/**
|
||||
* Sets the parent page object
|
||||
*
|
||||
* @param Page|null $parent
|
||||
* @param Kirby\Cms\Page|null $parent
|
||||
* @return self
|
||||
*/
|
||||
protected function setParent(Page $parent = null): self
|
||||
protected function setParent(Page $parent = null)
|
||||
{
|
||||
$this->parent = $parent;
|
||||
return $this;
|
||||
@@ -1293,7 +1268,7 @@ class Page extends ModelWithContent
|
||||
* @param string|null $root
|
||||
* @return self
|
||||
*/
|
||||
protected function setRoot(string $root = null): self
|
||||
protected function setRoot(string $root = null)
|
||||
{
|
||||
$this->root = $root;
|
||||
return $this;
|
||||
@@ -1305,7 +1280,7 @@ class Page extends ModelWithContent
|
||||
* @param string $slug
|
||||
* @return self
|
||||
*/
|
||||
protected function setSlug(string $slug): self
|
||||
protected function setSlug(string $slug)
|
||||
{
|
||||
$this->slug = $slug;
|
||||
return $this;
|
||||
@@ -1317,7 +1292,7 @@ class Page extends ModelWithContent
|
||||
* @param string $template
|
||||
* @return self
|
||||
*/
|
||||
protected function setTemplate(string $template = null): self
|
||||
protected function setTemplate(string $template = null)
|
||||
{
|
||||
if ($template !== null) {
|
||||
$this->intendedTemplate = $this->kirby()->template($template);
|
||||
@@ -1332,7 +1307,7 @@ class Page extends ModelWithContent
|
||||
* @param string $url
|
||||
* @return self
|
||||
*/
|
||||
protected function setUrl(string $url = null): self
|
||||
protected function setUrl(string $url = null)
|
||||
{
|
||||
if (is_string($url) === true) {
|
||||
$url = rtrim($url, '/');
|
||||
@@ -1369,7 +1344,7 @@ class Page extends ModelWithContent
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function status()
|
||||
public function status(): string
|
||||
{
|
||||
if ($this->isDraft() === true) {
|
||||
return 'draft';
|
||||
@@ -1385,7 +1360,7 @@ class Page extends ModelWithContent
|
||||
/**
|
||||
* Returns the final template
|
||||
*
|
||||
* @return Template
|
||||
* @return Kirby\Cms\Template
|
||||
*/
|
||||
public function template()
|
||||
{
|
||||
@@ -1405,9 +1380,9 @@ class Page extends ModelWithContent
|
||||
/**
|
||||
* Returns the title field or the slug as fallback
|
||||
*
|
||||
* @return Field
|
||||
* @return Kirby\Cms\Field
|
||||
*/
|
||||
public function title(): Field
|
||||
public function title()
|
||||
{
|
||||
return $this->content()->get('title')->or($this->slug());
|
||||
}
|
||||
@@ -1449,25 +1424,6 @@ class Page extends ModelWithContent
|
||||
return sha1($this->id() . $this->template());
|
||||
}
|
||||
|
||||
/**
|
||||
* String template builder
|
||||
*
|
||||
* @param string|null $template
|
||||
* @return string
|
||||
*/
|
||||
public function toString(string $template = null): string
|
||||
{
|
||||
if ($template === null) {
|
||||
return $this->id();
|
||||
}
|
||||
|
||||
return Str::template($template, [
|
||||
'page' => $this,
|
||||
'site' => $this->site(),
|
||||
'kirby' => $this->kirby()
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the UID of the page.
|
||||
* The UID is basically the same as the
|
||||
|
@@ -3,7 +3,7 @@
|
||||
namespace Kirby\Cms;
|
||||
|
||||
use Closure;
|
||||
use Kirby\Data\Data;
|
||||
use Kirby\Exception\DuplicateException;
|
||||
use Kirby\Exception\Exception;
|
||||
use Kirby\Exception\InvalidArgumentException;
|
||||
use Kirby\Exception\LogicException;
|
||||
@@ -12,6 +12,15 @@ use Kirby\Toolkit\A;
|
||||
use Kirby\Toolkit\F;
|
||||
use Kirby\Toolkit\Str;
|
||||
|
||||
/**
|
||||
* PageActions
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
trait PageActions
|
||||
{
|
||||
|
||||
@@ -23,7 +32,7 @@ trait PageActions
|
||||
* @param int $num
|
||||
* @return self
|
||||
*/
|
||||
public function changeNum(int $num = null): self
|
||||
public function changeNum(int $num = null)
|
||||
{
|
||||
if ($this->isDraft() === true) {
|
||||
throw new LogicException('Drafts cannot change their sorting number');
|
||||
@@ -63,7 +72,7 @@ trait PageActions
|
||||
* @param string $language
|
||||
* @return self
|
||||
*/
|
||||
public function changeSlug(string $slug, string $languageCode = null): self
|
||||
public function changeSlug(string $slug, string $languageCode = null)
|
||||
{
|
||||
// always sanitize the slug
|
||||
$slug = Str::slug($slug);
|
||||
@@ -90,8 +99,11 @@ trait PageActions
|
||||
'root' => null
|
||||
]);
|
||||
|
||||
// actually move stuff on disk
|
||||
if ($oldPage->exists() === true) {
|
||||
// remove the lock of the old page
|
||||
$oldPage->lock()->remove();
|
||||
|
||||
// actually move stuff on disk
|
||||
if (Dir::move($oldPage->root(), $newPage->root()) !== true) {
|
||||
throw new LogicException('The page directory cannot be moved');
|
||||
}
|
||||
@@ -117,7 +129,7 @@ trait PageActions
|
||||
* @param string $language
|
||||
* @return self
|
||||
*/
|
||||
protected function changeSlugForLanguage(string $slug, string $languageCode = null): self
|
||||
protected function changeSlugForLanguage(string $slug, string $languageCode = null)
|
||||
{
|
||||
$language = $this->kirby()->language($languageCode);
|
||||
|
||||
@@ -145,9 +157,9 @@ trait PageActions
|
||||
*
|
||||
* @param string $status "draft", "listed" or "unlisted"
|
||||
* @param integer $position Optional sorting number
|
||||
* @return Page
|
||||
* @return self
|
||||
*/
|
||||
public function changeStatus(string $status, int $position = null): self
|
||||
public function changeStatus(string $status, int $position = null)
|
||||
{
|
||||
switch ($status) {
|
||||
case 'draft':
|
||||
@@ -161,7 +173,7 @@ trait PageActions
|
||||
}
|
||||
}
|
||||
|
||||
protected function changeStatusToDraft(): self
|
||||
protected function changeStatusToDraft()
|
||||
{
|
||||
$page = $this->commit('changeStatus', [$this, 'draft'], function ($page) {
|
||||
return $page->unpublish();
|
||||
@@ -170,7 +182,11 @@ trait PageActions
|
||||
return $page;
|
||||
}
|
||||
|
||||
protected function changeStatusToListed(int $position = null): self
|
||||
/**
|
||||
* @param int $position
|
||||
* @return self
|
||||
*/
|
||||
protected function changeStatusToListed(int $position = null)
|
||||
{
|
||||
// create a sorting number for the page
|
||||
$num = $this->createNum($position);
|
||||
@@ -191,7 +207,10 @@ trait PageActions
|
||||
return $page;
|
||||
}
|
||||
|
||||
protected function changeStatusToUnlisted(): self
|
||||
/**
|
||||
* @return self
|
||||
*/
|
||||
protected function changeStatusToUnlisted()
|
||||
{
|
||||
if ($this->status() === 'unlisted') {
|
||||
return $this;
|
||||
@@ -212,7 +231,7 @@ trait PageActions
|
||||
* @param string $template
|
||||
* @return self
|
||||
*/
|
||||
public function changeTemplate(string $template): self
|
||||
public function changeTemplate(string $template)
|
||||
{
|
||||
if ($template === $this->template()->name()) {
|
||||
return $this;
|
||||
@@ -259,7 +278,7 @@ trait PageActions
|
||||
* @param string|null $languageCode
|
||||
* @return self
|
||||
*/
|
||||
public function changeTitle(string $title, string $languageCode = null): self
|
||||
public function changeTitle(string $title, string $languageCode = null)
|
||||
{
|
||||
return $this->commit('changeTitle', [$this, $title, $languageCode], function ($page, $title, $languageCode) {
|
||||
return $page->save(['title' => $title], $languageCode);
|
||||
@@ -291,13 +310,76 @@ trait PageActions
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the page to a new parent
|
||||
*
|
||||
* @param array $options
|
||||
* @return Kirby\Cms\Page
|
||||
*/
|
||||
public function copy(array $options = [])
|
||||
{
|
||||
$slug = $options['slug'] ?? $this->slug();
|
||||
$isDraft = $options['isDraft'] ?? $this->isDraft();
|
||||
$parent = $options['parent'] ?? null;
|
||||
$parentModel = $options['parent'] ?? $this->site();
|
||||
$num = $options['num'] ?? null;
|
||||
$children = $options['children'] ?? false;
|
||||
$files = $options['files'] ?? false;
|
||||
|
||||
// clean up the slug
|
||||
$slug = Str::slug($slug);
|
||||
|
||||
if ($parentModel->findPageOrDraft($slug)) {
|
||||
throw new DuplicateException([
|
||||
'key' => 'page.duplicate',
|
||||
'data' => [
|
||||
'slug' => $slug
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
$tmp = new static([
|
||||
'isDraft' => $isDraft,
|
||||
'num' => $num,
|
||||
'parent' => $parent,
|
||||
'slug' => $slug,
|
||||
]);
|
||||
|
||||
$ignore = [];
|
||||
|
||||
// don't copy files
|
||||
if ($files === false) {
|
||||
foreach ($this->files() as $file) {
|
||||
$ignore[] = $file->root();
|
||||
|
||||
// append all content files
|
||||
array_push($ignore, ...$file->contentFiles());
|
||||
}
|
||||
}
|
||||
|
||||
Dir::copy($this->root(), $tmp->root(), $children, $ignore);
|
||||
|
||||
$copy = $parentModel->clone()->findPageOrDraft($slug);
|
||||
|
||||
// remove all translated slugs
|
||||
if ($this->kirby()->multilang() === true) {
|
||||
foreach ($this->kirby()->languages() as $language) {
|
||||
if ($language->isDefault() === false) {
|
||||
$copy = $copy->save(['slug' => null], $language->code());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and stores a new page
|
||||
*
|
||||
* @param array $props
|
||||
* @return self
|
||||
*/
|
||||
public static function create(array $props): self
|
||||
public static function create(array $props)
|
||||
{
|
||||
// clean up the slug
|
||||
$props['slug'] = Str::slug($props['slug'] ?? $props['content']['title'] ?? null);
|
||||
@@ -352,7 +434,7 @@ trait PageActions
|
||||
* @param array $props
|
||||
* @return self
|
||||
*/
|
||||
public function createChild(array $props): self
|
||||
public function createChild(array $props)
|
||||
{
|
||||
$props = array_merge($props, [
|
||||
'url' => null,
|
||||
@@ -381,10 +463,7 @@ trait PageActions
|
||||
case 'date':
|
||||
case 'datetime':
|
||||
$format = $mode === 'date' ? 'Ymd' : 'YmdHi';
|
||||
$date = $this->content()->get('date')->value();
|
||||
$time = empty($date) === true ? time() : strtotime($date);
|
||||
|
||||
return date($format, $time);
|
||||
return $this->date()->toDate($format, 'now');
|
||||
break;
|
||||
case 'default':
|
||||
|
||||
@@ -473,6 +552,31 @@ trait PageActions
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Duplicates the page with the given
|
||||
* slug and optionally copies all files
|
||||
*
|
||||
* @param string $slug
|
||||
* @param array $options
|
||||
* @return Kirby\Cms\Page
|
||||
*/
|
||||
public function duplicate(string $slug = null, array $options = [])
|
||||
{
|
||||
|
||||
// create the slug for the duplicate
|
||||
$slug = Str::slug($slug ?? $this->slug() . '-copy');
|
||||
|
||||
return $this->commit('duplicate', [$this, $slug, $options], function ($page, $slug, $options) {
|
||||
return $this->copy([
|
||||
'parent' => $this->parent(),
|
||||
'slug' => $slug,
|
||||
'isDraft' => true,
|
||||
'files' => $options['files'] ?? false,
|
||||
'children' => $options['children'] ?? false,
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
public function publish()
|
||||
{
|
||||
if ($this->isDraft() === false) {
|
||||
@@ -508,8 +612,9 @@ trait PageActions
|
||||
|
||||
/**
|
||||
* Clean internal caches
|
||||
* @return self
|
||||
*/
|
||||
public function purge(): self
|
||||
public function purge()
|
||||
{
|
||||
$this->children = null;
|
||||
$this->blueprint = null;
|
||||
|
@@ -2,6 +2,15 @@
|
||||
|
||||
namespace Kirby\Cms;
|
||||
|
||||
/**
|
||||
* PageBlueprint
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class PageBlueprint extends Blueprint
|
||||
{
|
||||
|
||||
@@ -26,6 +35,7 @@ class PageBlueprint extends Blueprint
|
||||
'changeTitle' => null,
|
||||
'create' => null,
|
||||
'delete' => null,
|
||||
'duplicate' => null,
|
||||
'read' => null,
|
||||
'preview' => null,
|
||||
'sort' => null,
|
||||
|
@@ -2,6 +2,15 @@
|
||||
|
||||
namespace Kirby\Cms;
|
||||
|
||||
/**
|
||||
* PagePermissions
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class PagePermissions extends ModelPermissions
|
||||
{
|
||||
protected $category = 'pages';
|
||||
|
@@ -5,12 +5,17 @@ namespace Kirby\Cms;
|
||||
use Kirby\Exception\DuplicateException;
|
||||
use Kirby\Exception\InvalidArgumentException;
|
||||
use Kirby\Exception\LogicException;
|
||||
use Kirby\Exception\NotFoundException;
|
||||
use Kirby\Exception\PermissionException;
|
||||
use Kirby\Toolkit\Str;
|
||||
|
||||
/**
|
||||
* Validators for all page actions
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class PageRules
|
||||
{
|
||||
@@ -257,6 +262,20 @@ class PageRules
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function duplicate(Page $page, string $slug, array $options = []): bool
|
||||
{
|
||||
if ($page->permissions()->duplicate() !== true) {
|
||||
throw new PermissionException([
|
||||
'key' => 'page.duplicate.permission',
|
||||
'data' => [
|
||||
'slug' => $page->slug()
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function update(Page $page, array $content = []): bool
|
||||
{
|
||||
if ($page->permissions()->update() !== true) {
|
||||
|
@@ -2,6 +2,15 @@
|
||||
|
||||
namespace Kirby\Cms;
|
||||
|
||||
/**
|
||||
* PageSiblings
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
trait PageSiblings
|
||||
{
|
||||
|
||||
@@ -25,15 +34,6 @@ trait PageSiblings
|
||||
return $this->nextListed() !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated 3.0.0 Use `Page::hasNextListed` instead
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasNextVisible(): bool
|
||||
{
|
||||
return $this->hasNextListed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if there's a next unlisted
|
||||
* page in the siblings collection
|
||||
@@ -45,6 +45,15 @@ trait PageSiblings
|
||||
return $this->nextUnlisted() !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated 3.0.0 Use `Page::hasNextListed` instead
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasNextVisible(): bool
|
||||
{
|
||||
return $this->hasNextListed();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated 3.0.0 Use `Page::hasPrevUnlisted` instead
|
||||
* @return boolean
|
||||
@@ -97,7 +106,7 @@ trait PageSiblings
|
||||
/**
|
||||
* Returns the next listed page if it exists
|
||||
*
|
||||
* @return self|null
|
||||
* @return Kirby\Cms\Page|null
|
||||
*/
|
||||
public function nextListed()
|
||||
{
|
||||
@@ -107,7 +116,7 @@ trait PageSiblings
|
||||
/**
|
||||
* Returns the next unlisted page if it exists
|
||||
*
|
||||
* @return self|null
|
||||
* @return Kirby\Cms\Page|null
|
||||
*/
|
||||
public function nextUnlisted()
|
||||
{
|
||||
@@ -135,7 +144,7 @@ trait PageSiblings
|
||||
/**
|
||||
* Returns the previous listed page
|
||||
*
|
||||
* @return self|null
|
||||
* @return Kirby\Cms\Page|null
|
||||
*/
|
||||
public function prevListed()
|
||||
{
|
||||
@@ -145,7 +154,7 @@ trait PageSiblings
|
||||
/**
|
||||
* Returns the previous unlisted page
|
||||
*
|
||||
* @return self|null
|
||||
* @return Kirby\Cms\Page|null
|
||||
*/
|
||||
public function prevUnlisted()
|
||||
{
|
||||
@@ -164,7 +173,7 @@ trait PageSiblings
|
||||
/**
|
||||
* Private siblings collector
|
||||
*
|
||||
* @return Collection
|
||||
* @return Kirby\Cms\Collection
|
||||
*/
|
||||
protected function siblingsCollection()
|
||||
{
|
||||
@@ -179,7 +188,7 @@ trait PageSiblings
|
||||
* Returns siblings with the same template
|
||||
*
|
||||
* @param bool $self
|
||||
* @return self
|
||||
* @return Kirby\Cms\Pages
|
||||
*/
|
||||
public function templateSiblings(bool $self = true)
|
||||
{
|
||||
|
@@ -2,8 +2,6 @@
|
||||
|
||||
namespace Kirby\Cms;
|
||||
|
||||
use Kirby\Toolkit\F;
|
||||
|
||||
/**
|
||||
* The `$pages` object refers to a
|
||||
* collection of pages. The pages in this
|
||||
@@ -16,8 +14,9 @@ use Kirby\Toolkit\F;
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link http://getkirby.com
|
||||
* @copyright Bastian Allgeier
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class Pages extends Collection
|
||||
{
|
||||
@@ -25,7 +24,7 @@ class Pages extends Collection
|
||||
/**
|
||||
* Cache for the index
|
||||
*
|
||||
* @var null|Pages
|
||||
* @var Kirby\Cms\Pages|null
|
||||
*/
|
||||
protected $index = null;
|
||||
|
||||
@@ -42,7 +41,7 @@ class Pages extends Collection
|
||||
* current collection
|
||||
*
|
||||
* @param mixed $item
|
||||
* @return Pages
|
||||
* @return self
|
||||
*/
|
||||
public function add($object)
|
||||
{
|
||||
@@ -65,9 +64,9 @@ class Pages extends Collection
|
||||
/**
|
||||
* Returns all audio files of all children
|
||||
*
|
||||
* @return Files
|
||||
* @return Kirby\Cms\Files
|
||||
*/
|
||||
public function audio(): Files
|
||||
public function audio()
|
||||
{
|
||||
return $this->files()->filterBy("type", "audio");
|
||||
}
|
||||
@@ -75,13 +74,13 @@ class Pages extends Collection
|
||||
/**
|
||||
* Returns all children for each page in the array
|
||||
*
|
||||
* @return Pages
|
||||
* @return Kirby\Cms\Pages
|
||||
*/
|
||||
public function children(): Pages
|
||||
public function children()
|
||||
{
|
||||
$children = new Pages([], $this->parent);
|
||||
|
||||
foreach ($this->data as $pageKey => $page) {
|
||||
foreach ($this->data as $page) {
|
||||
foreach ($page->children() as $childKey => $child) {
|
||||
$children->data[$childKey] = $child;
|
||||
}
|
||||
@@ -93,9 +92,9 @@ class Pages extends Collection
|
||||
/**
|
||||
* Returns all code files of all children
|
||||
*
|
||||
* @return Files
|
||||
* @return Kirby\Cms\Files
|
||||
*/
|
||||
public function code(): Files
|
||||
public function code()
|
||||
{
|
||||
return $this->files()->filterBy("type", "code");
|
||||
}
|
||||
@@ -103,9 +102,9 @@ class Pages extends Collection
|
||||
/**
|
||||
* Returns all documents of all children
|
||||
*
|
||||
* @return Files
|
||||
* @return Kirby\Cms\Files
|
||||
*/
|
||||
public function documents(): Files
|
||||
public function documents()
|
||||
{
|
||||
return $this->files()->filterBy("type", "document");
|
||||
}
|
||||
@@ -113,13 +112,13 @@ class Pages extends Collection
|
||||
/**
|
||||
* Fetch all drafts for all pages in the collection
|
||||
*
|
||||
* @return Pages
|
||||
* @return Kirby\Cms\Pages
|
||||
*/
|
||||
public function drafts()
|
||||
{
|
||||
$drafts = new Pages([], $this->parent);
|
||||
|
||||
foreach ($this->data as $pageKey => $page) {
|
||||
foreach ($this->data as $page) {
|
||||
foreach ($page->drafts() as $draftKey => $draft) {
|
||||
$drafts->data[$draftKey] = $draft;
|
||||
}
|
||||
@@ -132,10 +131,10 @@ class Pages extends Collection
|
||||
* Creates a pages collection from an array of props
|
||||
*
|
||||
* @param array $pages
|
||||
* @param Model $parent
|
||||
* @param Kirby\Cms\Model $parent
|
||||
* @param array $inject
|
||||
* @param bool $draft
|
||||
* @return Pages
|
||||
* @return self
|
||||
*/
|
||||
public static function factory(array $pages, Model $model = null, bool $draft = false)
|
||||
{
|
||||
@@ -168,13 +167,13 @@ class Pages extends Collection
|
||||
/**
|
||||
* Returns all files of all children
|
||||
*
|
||||
* @return Files
|
||||
* @return Kirby\Cms\Files
|
||||
*/
|
||||
public function files(): Files
|
||||
public function files()
|
||||
{
|
||||
$files = new Files([], $this->parent);
|
||||
|
||||
foreach ($this->data as $pageKey => $page) {
|
||||
foreach ($this->data as $page) {
|
||||
foreach ($page->files() as $fileKey => $file) {
|
||||
$files->data[$fileKey] = $file;
|
||||
}
|
||||
@@ -188,10 +187,10 @@ class Pages extends Collection
|
||||
* This works recursively for children and
|
||||
* children of children, etc.
|
||||
*
|
||||
* @param string $id
|
||||
* @param string|null $id
|
||||
* @return mixed
|
||||
*/
|
||||
public function findById($id)
|
||||
public function findById(string $id = null)
|
||||
{
|
||||
// remove trailing or leading slashes
|
||||
$id = trim($id, '/');
|
||||
@@ -228,10 +227,11 @@ class Pages extends Collection
|
||||
* Finds a child or child of a child recursively.
|
||||
*
|
||||
* @param string $id
|
||||
* @param string $startAt
|
||||
* @param string|null $startAt
|
||||
* @param bool $multiLang
|
||||
* @return mixed
|
||||
*/
|
||||
public function findByIdRecursive($id, $startAt = null, bool $multiLang = false)
|
||||
public function findByIdRecursive(string $id, string $startAt = null, bool $multiLang = false)
|
||||
{
|
||||
$path = explode('/', $id);
|
||||
$collection = $this;
|
||||
@@ -259,10 +259,10 @@ class Pages extends Collection
|
||||
/**
|
||||
* Uses the specialized find by id method
|
||||
*
|
||||
* @param string $key
|
||||
* @param string|null $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function findByKey($key)
|
||||
public function findByKey(string $key = null)
|
||||
{
|
||||
return $this->findById($key);
|
||||
}
|
||||
@@ -271,7 +271,7 @@ class Pages extends Collection
|
||||
* Alias for Pages::findById
|
||||
*
|
||||
* @param string $id
|
||||
* @return Page|null
|
||||
* @return Kirby\Cms\Page|null
|
||||
*/
|
||||
public function findByUri(string $id)
|
||||
{
|
||||
@@ -281,7 +281,7 @@ class Pages extends Collection
|
||||
/**
|
||||
* Finds the currently open page
|
||||
*
|
||||
* @return Page|null
|
||||
* @return Kirby\Cms\Page|null
|
||||
*/
|
||||
public function findOpen()
|
||||
{
|
||||
@@ -293,7 +293,7 @@ class Pages extends Collection
|
||||
* extension pages
|
||||
*
|
||||
* @param string $key
|
||||
* @return Page|null
|
||||
* @return Kirby\Cms\Page|null
|
||||
*/
|
||||
public function get($key, $default = null)
|
||||
{
|
||||
@@ -311,9 +311,9 @@ class Pages extends Collection
|
||||
/**
|
||||
* Returns all images of all children
|
||||
*
|
||||
* @return Files
|
||||
* @return Kirby\Cms\Files
|
||||
*/
|
||||
public function images(): Files
|
||||
public function images()
|
||||
{
|
||||
return $this->files()->filterBy("type", "image");
|
||||
}
|
||||
@@ -323,9 +323,9 @@ class Pages extends Collection
|
||||
* pages and subpages, etc.
|
||||
*
|
||||
* @param bool $drafts
|
||||
* @return Pages
|
||||
* @return Kirby\Cms\Pages
|
||||
*/
|
||||
public function index(bool $drafts = false): Pages
|
||||
public function index(bool $drafts = false)
|
||||
{
|
||||
if (is_a($this->index, 'Kirby\Cms\Pages') === true) {
|
||||
return $this->index;
|
||||
@@ -349,7 +349,7 @@ class Pages extends Collection
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function invisible(): self
|
||||
public function invisible()
|
||||
{
|
||||
return $this->filterBy('isUnlisted', '==', true);
|
||||
}
|
||||
@@ -357,9 +357,9 @@ class Pages extends Collection
|
||||
/**
|
||||
* Returns all listed pages in the collection
|
||||
*
|
||||
* @return self
|
||||
* @return Kirby\Cms\Pages
|
||||
*/
|
||||
public function listed(): self
|
||||
public function listed()
|
||||
{
|
||||
return $this->filterBy('isListed', '==', true);
|
||||
}
|
||||
@@ -367,9 +367,9 @@ class Pages extends Collection
|
||||
/**
|
||||
* Returns all unlisted pages in the collection
|
||||
*
|
||||
* @return self
|
||||
* @return Kirby\Cms\Pages
|
||||
*/
|
||||
public function unlisted(): self
|
||||
public function unlisted()
|
||||
{
|
||||
return $this->filterBy('isUnlisted', '==', true);
|
||||
}
|
||||
@@ -379,7 +379,7 @@ class Pages extends Collection
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function merge(...$args): self
|
||||
public function merge(...$args)
|
||||
{
|
||||
// merge multiple arguments at once
|
||||
if (count($args) > 1) {
|
||||
@@ -441,9 +441,9 @@ class Pages extends Collection
|
||||
/*
|
||||
* Returns all listed and unlisted pages in the collection
|
||||
*
|
||||
* @return self
|
||||
* @return Kirby\Cms\Pages
|
||||
*/
|
||||
public function published(): self
|
||||
public function published()
|
||||
{
|
||||
return $this->filterBy('isDraft', '==', false);
|
||||
}
|
||||
@@ -451,10 +451,10 @@ class Pages extends Collection
|
||||
/**
|
||||
* Filter all pages by the given template
|
||||
*
|
||||
* @param null|string|array $template
|
||||
* @return self
|
||||
* @param string|array $templates
|
||||
* @return Kirby\Cms\Pages
|
||||
*/
|
||||
public function template($templates): self
|
||||
public function template($templates)
|
||||
{
|
||||
if (empty($templates) === true) {
|
||||
return $this;
|
||||
@@ -472,9 +472,9 @@ class Pages extends Collection
|
||||
/**
|
||||
* Returns all video files of all children
|
||||
*
|
||||
* @return Files
|
||||
* @return Kirby\Cms\Files
|
||||
*/
|
||||
public function videos(): Files
|
||||
public function videos()
|
||||
{
|
||||
return $this->files()->filterBy("type", "video");
|
||||
}
|
||||
@@ -482,9 +482,9 @@ class Pages extends Collection
|
||||
/**
|
||||
* Deprecated alias for Pages::listed()
|
||||
*
|
||||
* @return self
|
||||
* @return Kirby\Cms\Pages
|
||||
*/
|
||||
public function visible(): self
|
||||
public function visible()
|
||||
{
|
||||
return $this->filterBy('isListed', '==', true);
|
||||
}
|
||||
|
@@ -16,8 +16,9 @@ use Kirby\Toolkit\Pagination as BasePagination;
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link http://getkirby.com
|
||||
* @copyright Bastian Allgeier
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class Pagination extends BasePagination
|
||||
{
|
||||
@@ -117,9 +118,9 @@ class Pagination extends BasePagination
|
||||
* Returns the Url for the next page.
|
||||
* Returns null if there's no next page.
|
||||
*
|
||||
* @return string
|
||||
* @return string|null
|
||||
*/
|
||||
public function nextPageUrl()
|
||||
public function nextPageUrl(): ?string
|
||||
{
|
||||
if ($page = $this->nextPage()) {
|
||||
return $this->pageUrl($page);
|
||||
@@ -129,13 +130,14 @@ class Pagination extends BasePagination
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Url of the current page.
|
||||
* If the $page variable is set, the Url
|
||||
* Returns the URL of the current page.
|
||||
* If the `$page` variable is set, the URL
|
||||
* for that page will be returned.
|
||||
*
|
||||
* @param int|null $page
|
||||
* @return string|null
|
||||
*/
|
||||
public function pageUrl(int $page = null)
|
||||
public function pageUrl(int $page = null): ?string
|
||||
{
|
||||
if ($page === null) {
|
||||
return $this->pageUrl($this->page());
|
||||
@@ -163,9 +165,9 @@ class Pagination extends BasePagination
|
||||
* Returns the Url for the previous page.
|
||||
* Returns null if there's no previous page.
|
||||
*
|
||||
* @return string
|
||||
* @return string|null
|
||||
*/
|
||||
public function prevPageUrl()
|
||||
public function prevPageUrl(): ?string
|
||||
{
|
||||
if ($page = $this->prevPage()) {
|
||||
return $this->pageUrl($page);
|
||||
|
@@ -15,6 +15,12 @@ use Throwable;
|
||||
* a working panel view with all the right URLs
|
||||
* and other panel options. The view template is
|
||||
* located in `kirby/views/panel.php`
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class Panel
|
||||
{
|
||||
@@ -23,7 +29,7 @@ class Panel
|
||||
* Links all dist files in the media folder
|
||||
* and returns the link to the requested asset
|
||||
*
|
||||
* @param App $kirby
|
||||
* @param Kirby\Cms\App $kirby
|
||||
* @return bool
|
||||
*/
|
||||
public static function link(App $kirby): bool
|
||||
@@ -45,7 +51,7 @@ class Panel
|
||||
Dir::make($mediaRoot, true);
|
||||
|
||||
// create a symlink to the dist folder
|
||||
if (Dir::copy($kirby->root('panel') . '/dist', $versionRoot) !== true) {
|
||||
if (Dir::copy($panelRoot, $versionRoot) !== true) {
|
||||
throw new Exception('Panel assets could not be linked');
|
||||
}
|
||||
|
||||
@@ -55,10 +61,10 @@ class Panel
|
||||
/**
|
||||
* Renders the main panel view
|
||||
*
|
||||
* @param App $kirby
|
||||
* @return Response
|
||||
* @param Kirby\Cms\App $kirby
|
||||
* @return Kirby\Cms\Response
|
||||
*/
|
||||
public static function render(App $kirby): Response
|
||||
public static function render(App $kirby)
|
||||
{
|
||||
try {
|
||||
if (static::link($kirby) === true) {
|
||||
@@ -72,15 +78,15 @@ class Panel
|
||||
// get the uri object for the panel url
|
||||
$uri = new Uri($url = $kirby->url('panel'));
|
||||
|
||||
$pluginCss = new PanelPlugins('css');
|
||||
$pluginJs = new PanelPlugins('js');
|
||||
// fetch all plugins
|
||||
$plugins = new PanelPlugins();
|
||||
|
||||
$view = new View($kirby->root('kirby') . '/views/panel.php', [
|
||||
'kirby' => $kirby,
|
||||
'config' => $kirby->option('panel'),
|
||||
'assetUrl' => $kirby->url('media') . '/panel/' . $kirby->versionHash(),
|
||||
'pluginCss' => $pluginCss->url(),
|
||||
'pluginJs' => $pluginJs->url(),
|
||||
'pluginCss' => $plugins->url('css'),
|
||||
'pluginJs' => $plugins->url('js'),
|
||||
'icons' => F::read($kirby->root('panel') . '/dist/img/icons.svg'),
|
||||
'panelUrl' => $uri->path()->toString(true) . '/',
|
||||
'options' => [
|
||||
|
@@ -9,6 +9,12 @@ use Kirby\Toolkit\F;
|
||||
* The PanelPlugins class takes care of collecting
|
||||
* js and css plugin files for the panel and caches
|
||||
* them in the media folder
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class PanelPlugins
|
||||
{
|
||||
@@ -20,30 +26,6 @@ class PanelPlugins
|
||||
*/
|
||||
public $files;
|
||||
|
||||
/**
|
||||
* Cache of the unique plugin hash for the url and root
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $hash;
|
||||
|
||||
/**
|
||||
* css or js
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $type;
|
||||
|
||||
/**
|
||||
* Creates a new panel plugin instance by type (css or js)
|
||||
*
|
||||
* @param string $type
|
||||
*/
|
||||
public function __construct(string $type)
|
||||
{
|
||||
$this->type = $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects and returns the plugin files for all plugins
|
||||
*
|
||||
@@ -58,84 +40,13 @@ class PanelPlugins
|
||||
$this->files = [];
|
||||
|
||||
foreach (App::instance()->plugins() as $plugin) {
|
||||
$file = $plugin->root() . '/index.' . $this->type;
|
||||
|
||||
if (file_exists($file) === true) {
|
||||
$this->files[] = $file;
|
||||
}
|
||||
$this->files[] = $plugin->root() . '/index.css';
|
||||
$this->files[] = $plugin->root() . '/index.js';
|
||||
}
|
||||
|
||||
return $this->files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the cache exists
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function exist(): bool
|
||||
{
|
||||
return file_exists($this->root());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path to the cache folder
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function folder(): string
|
||||
{
|
||||
return 'panel/' . App::versionHash() . '/plugins/' . $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects and removes garbage from old plugin versions
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function gc(): bool
|
||||
{
|
||||
$folder = App::instance()->root('media') . '/' . $this->folder();
|
||||
|
||||
foreach (glob($folder . '/*') as $dir) {
|
||||
$name = basename($dir);
|
||||
|
||||
if ($name !== $this->hash()) {
|
||||
Dir::remove($dir);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the unique hash for the cache file
|
||||
* The hash is generated from all plugin filenames
|
||||
* and the max modification date to make sure changes
|
||||
* will always be cached properly
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function hash(): string
|
||||
{
|
||||
if ($this->hash !== null) {
|
||||
return $this->hash;
|
||||
}
|
||||
|
||||
return $this->hash = $this->id() . '-' . $this->modified();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a unique id based on all
|
||||
* plugin file roots
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function id(): string
|
||||
{
|
||||
return hash('crc32', implode(array_values($this->files())));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last modification
|
||||
* of the collected plugin files
|
||||
@@ -154,79 +65,36 @@ class PanelPlugins
|
||||
return max($modified);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the full path to the cache file
|
||||
* This is used for the root and url methods
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function path(): string
|
||||
{
|
||||
return $this->folder() . '/' . $this->hash() . '/index.' . $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the files from all plugins and concatenate them
|
||||
*
|
||||
* @param string $type
|
||||
* @return string
|
||||
*/
|
||||
public function read(): string
|
||||
public function read(string $type): string
|
||||
{
|
||||
$dist = [];
|
||||
|
||||
foreach ($this->files() as $file) {
|
||||
$dist[] = file_get_contents($file);
|
||||
if (F::extension($file) === $type) {
|
||||
if ($content = F::read($file)) {
|
||||
$dist[] = $content;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return implode(PHP_EOL, $dist);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the cache exists and
|
||||
* otherwise (re)creates it
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function publish(): bool
|
||||
{
|
||||
if ($this->exist() === true) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->write();
|
||||
$this->gc();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Absolute path to the cache file
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function root(): string
|
||||
{
|
||||
return App::instance()->root('media') . '/' . $this->path();
|
||||
}
|
||||
|
||||
/**
|
||||
* Absolute url to the cache file
|
||||
* This is used by the panel to link the plugins
|
||||
*
|
||||
* @param string $type
|
||||
* @return string
|
||||
*/
|
||||
public function url(): string
|
||||
public function url(string $type): string
|
||||
{
|
||||
return App::instance()->url('media') . '/' . $this->path();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the cache file
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function write(): bool
|
||||
{
|
||||
return F::write($this->root(), $this->read());
|
||||
return App::instance()->url('media') . '/plugins/index.' . $type . '?' . $this->modified();
|
||||
}
|
||||
}
|
||||
|
@@ -8,6 +8,12 @@ use Kirby\Exception\InvalidArgumentException;
|
||||
* Handles permission definition in each user
|
||||
* blueprint and wraps a couple useful methods
|
||||
* around it to check for available permissions.
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class Permissions
|
||||
{
|
||||
@@ -36,6 +42,7 @@ class Permissions
|
||||
'changeTitle' => true,
|
||||
'create' => true,
|
||||
'delete' => true,
|
||||
'duplicate' => true,
|
||||
'preview' => true,
|
||||
'read' => true,
|
||||
'sort' => true,
|
||||
@@ -68,16 +75,16 @@ class Permissions
|
||||
|
||||
public function __construct($settings = [])
|
||||
{
|
||||
if (is_bool($settings) === true) {
|
||||
return $this->setAll($settings);
|
||||
}
|
||||
|
||||
if (is_array($settings) === true) {
|
||||
return $this->setCategories($settings);
|
||||
}
|
||||
|
||||
if (is_bool($settings) === true) {
|
||||
return $this->setAll($settings);
|
||||
}
|
||||
}
|
||||
|
||||
public function for(string $category = null, string $action = null)
|
||||
public function for(string $category = null, string $action = null): bool
|
||||
{
|
||||
if ($action === null) {
|
||||
if ($this->hasCategory($category) === false) {
|
||||
@@ -94,12 +101,12 @@ class Permissions
|
||||
return $this->actions[$category][$action];
|
||||
}
|
||||
|
||||
protected function hasAction(string $category, string $action)
|
||||
protected function hasAction(string $category, string $action): bool
|
||||
{
|
||||
return $this->hasCategory($category) === true && array_key_exists($action, $this->actions[$category]) === true;
|
||||
}
|
||||
|
||||
protected function hasCategory(string $category)
|
||||
protected function hasCategory(string $category): bool
|
||||
{
|
||||
return array_key_exists($category, $this->actions) === true;
|
||||
}
|
||||
|
@@ -5,12 +5,17 @@ namespace Kirby\Cms;
|
||||
use Exception;
|
||||
use Kirby\Data\Data;
|
||||
use Kirby\Exception\InvalidArgumentException;
|
||||
use Kirby\Toolkit\F;
|
||||
|
||||
/**
|
||||
* Represents a Plugin and handles parsing of
|
||||
* the composer.json. It also creates the prefix
|
||||
* and media url for the plugin.
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class Plugin extends Model
|
||||
{
|
||||
@@ -89,6 +94,10 @@ class Plugin extends Model
|
||||
return $this->root;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return self
|
||||
*/
|
||||
protected function setName(string $name)
|
||||
{
|
||||
if (preg_match('!^[a-z0-9-]+\/[a-z0-9-]+$!i', $name) == false) {
|
||||
|
@@ -10,6 +10,12 @@ use Kirby\Toolkit\F;
|
||||
* Plugin assets are automatically copied/linked
|
||||
* to the media folder, to make them publicly
|
||||
* available. This class handles the magic around that.
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class PluginAssets
|
||||
{
|
||||
@@ -19,7 +25,7 @@ class PluginAssets
|
||||
* @param string $pluginName
|
||||
* @return void
|
||||
*/
|
||||
public static function clean(string $pluginName)
|
||||
public static function clean(string $pluginName): void
|
||||
{
|
||||
if ($plugin = App::instance()->plugin($pluginName)) {
|
||||
$root = $plugin->root() . '/assets';
|
||||
@@ -48,7 +54,7 @@ class PluginAssets
|
||||
*
|
||||
* @param string $pluginName
|
||||
* @param string $filename
|
||||
* @return string
|
||||
* @return Kirby\Cms\Response|null
|
||||
*/
|
||||
public static function resolve(string $pluginName, string $filename)
|
||||
{
|
||||
|
@@ -7,11 +7,17 @@ use Kirby\Toolkit\Facade;
|
||||
|
||||
/**
|
||||
* Shortcut to the request object
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class R extends Facade
|
||||
{
|
||||
/**
|
||||
* @return Request
|
||||
* @return Kirby\Cms\Request
|
||||
*/
|
||||
public static function instance()
|
||||
{
|
||||
|
@@ -7,6 +7,12 @@ use Kirby\Toolkit\Str;
|
||||
|
||||
/**
|
||||
* Global response configuration
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class Responder
|
||||
{
|
||||
@@ -46,7 +52,7 @@ class Responder
|
||||
*/
|
||||
public function __toString(): string
|
||||
{
|
||||
return $this->send();
|
||||
return (string)$this->send();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -85,9 +91,8 @@ class Responder
|
||||
* Construct response from an array
|
||||
*
|
||||
* @param array $response
|
||||
* @return self
|
||||
*/
|
||||
public function fromArray(array $response)
|
||||
public function fromArray(array $response): void
|
||||
{
|
||||
$this->body($response['body'] ?? null);
|
||||
$this->code($response['code'] ?? null);
|
||||
@@ -137,7 +142,7 @@ class Responder
|
||||
* Shortcut to configure a json response
|
||||
*
|
||||
* @param array $json
|
||||
* @return self
|
||||
* @return string|self
|
||||
*/
|
||||
public function json(array $json = null)
|
||||
{
|
||||
@@ -169,7 +174,7 @@ class Responder
|
||||
* Creates and returns the response object from the config
|
||||
*
|
||||
* @param string|null $body
|
||||
* @return Response
|
||||
* @return Kirby\Cms\Response
|
||||
*/
|
||||
public function send(string $body = null)
|
||||
{
|
||||
|
@@ -2,15 +2,17 @@
|
||||
|
||||
namespace Kirby\Cms;
|
||||
|
||||
use Kirby\Exception\InvalidArgumentException;
|
||||
use Kirby\Exception\NotFoundException;
|
||||
use Kirby\Http\Response as BaseResponse;
|
||||
|
||||
/**
|
||||
* Custom response object with an optimized
|
||||
* redirect method to build correct Urls
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class Response extends BaseResponse
|
||||
class Response extends \Kirby\Http\Response
|
||||
{
|
||||
|
||||
/**
|
||||
|
@@ -4,13 +4,18 @@ namespace Kirby\Cms;
|
||||
|
||||
use Exception;
|
||||
use Kirby\Data\Data;
|
||||
use Kirby\Exception\NotFoundException;
|
||||
use Kirby\Toolkit\F;
|
||||
use Kirby\Toolkit\I18n;
|
||||
|
||||
/**
|
||||
* Represents a User role with attached
|
||||
* permissions. Roles are defined by user blueprints.
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class Role extends Model
|
||||
{
|
||||
@@ -25,7 +30,7 @@ class Role extends Model
|
||||
}
|
||||
|
||||
/**
|
||||
* Improved var_dump() output
|
||||
* Improved `var_dump` output
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
@@ -48,19 +53,19 @@ class Role extends Model
|
||||
}
|
||||
}
|
||||
|
||||
protected static function defaults()
|
||||
protected static function defaults(): array
|
||||
{
|
||||
return [
|
||||
'admin' => [
|
||||
'description' => 'The admin has all rights',
|
||||
'name' => 'admin',
|
||||
'title' => 'Admin',
|
||||
'description' => I18n::translate('role.admin.description'),
|
||||
'title' => I18n::translate('role.admin.title'),
|
||||
'permissions' => true,
|
||||
],
|
||||
'nobody' => [
|
||||
'description' => 'This is a fallback role without any permissions',
|
||||
'name' => 'nobody',
|
||||
'title' => 'Nobody',
|
||||
'description' => I18n::translate('role.nobody.description'),
|
||||
'title' => I18n::translate('role.nobody.title'),
|
||||
'permissions' => false,
|
||||
]
|
||||
];
|
||||
@@ -71,7 +76,12 @@ class Role extends Model
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
public static function factory(array $props, array $inject = []): self
|
||||
/**
|
||||
* @param array $props
|
||||
* @param array $inject
|
||||
* @return self
|
||||
*/
|
||||
public static function factory(array $props, array $inject = [])
|
||||
{
|
||||
return new static($props + $inject);
|
||||
}
|
||||
@@ -91,7 +101,12 @@ class Role extends Model
|
||||
return $this->name() === 'nobody';
|
||||
}
|
||||
|
||||
public static function load(string $file, array $inject = []): self
|
||||
/**
|
||||
* @param string $file
|
||||
* @param array $inject
|
||||
* @return self
|
||||
*/
|
||||
public static function load(string $file, array $inject = [])
|
||||
{
|
||||
$data = Data::read($file);
|
||||
$data['name'] = F::name($file);
|
||||
@@ -104,6 +119,10 @@ class Role extends Model
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $inject
|
||||
* @return self
|
||||
*/
|
||||
public static function nobody(array $inject = [])
|
||||
{
|
||||
try {
|
||||
@@ -113,30 +132,49 @@ class Role extends Model
|
||||
}
|
||||
}
|
||||
|
||||
public function permissions(): Permissions
|
||||
/**
|
||||
* @return Kirby\Cms\Permissions
|
||||
*/
|
||||
public function permissions()
|
||||
{
|
||||
return $this->permissions;
|
||||
}
|
||||
|
||||
protected function setDescription($description = null): self
|
||||
/**
|
||||
* @param [type] $description
|
||||
* @return self
|
||||
*/
|
||||
protected function setDescription($description = null)
|
||||
{
|
||||
$this->description = I18n::translate($description, $description);
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function setName(string $name): self
|
||||
/**
|
||||
* @param string $name
|
||||
* @return self
|
||||
*/
|
||||
protected function setName(string $name)
|
||||
{
|
||||
$this->name = $name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function setPermissions($permissions = null): self
|
||||
/**
|
||||
* @param [type] $permissions
|
||||
* @return self
|
||||
*/
|
||||
protected function setPermissions($permissions = null)
|
||||
{
|
||||
$this->permissions = new Permissions($permissions);
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function setTitle($title = null): self
|
||||
/**
|
||||
* @param [type] $title
|
||||
* @return self
|
||||
*/
|
||||
protected function setTitle($title = null)
|
||||
{
|
||||
$this->title = I18n::translate($title, $title);
|
||||
return $this;
|
||||
|
@@ -3,7 +3,6 @@
|
||||
namespace Kirby\Cms;
|
||||
|
||||
use Kirby\Toolkit\Dir;
|
||||
use Kirby\Toolkit\F;
|
||||
|
||||
/**
|
||||
* Extension of the Collection class that
|
||||
@@ -12,10 +11,22 @@ use Kirby\Toolkit\F;
|
||||
* collection with Role objects. It also has
|
||||
* a `Roles::load()` method that handles loading
|
||||
* role definitions from disk.
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class Roles extends Collection
|
||||
{
|
||||
public static function factory(array $roles, array $inject = []): self
|
||||
|
||||
/**
|
||||
* @param array $roles
|
||||
* @param array $inject
|
||||
* @return self
|
||||
*/
|
||||
public static function factory(array $roles, array $inject = [])
|
||||
{
|
||||
$collection = new static;
|
||||
|
||||
@@ -34,7 +45,12 @@ class Roles extends Collection
|
||||
return $collection->sortBy('name', 'asc');
|
||||
}
|
||||
|
||||
public static function load(string $root = null, array $inject = []): self
|
||||
/**
|
||||
* @param string $root
|
||||
* @param array $inject
|
||||
* @return self
|
||||
*/
|
||||
public static function load(string $root = null, array $inject = [])
|
||||
{
|
||||
$roles = new static;
|
||||
|
||||
|
@@ -7,11 +7,17 @@ use Kirby\Toolkit\Facade;
|
||||
|
||||
/**
|
||||
* Shortcut to the session object
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class S extends Facade
|
||||
{
|
||||
/**
|
||||
* @return Session
|
||||
* @return Kirby\Session\Session
|
||||
*/
|
||||
public static function instance()
|
||||
{
|
||||
|
@@ -9,9 +9,21 @@ use Kirby\Toolkit\Str;
|
||||
* search logic from collections, to
|
||||
* provide a more globally usable interface
|
||||
* for any searches.
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class Search
|
||||
{
|
||||
|
||||
/**
|
||||
* @param string $query
|
||||
* @param array $params
|
||||
* @return Kirby\Cms\Files
|
||||
*/
|
||||
public static function files(string $query = null, $params = [])
|
||||
{
|
||||
return App::instance()->site()->index()->files()->search($query, $params);
|
||||
@@ -111,11 +123,21 @@ class Search
|
||||
return $results->sortBy('searchScore', 'desc');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $query
|
||||
* @param array $params
|
||||
* @return Kirby\Cms\Pages
|
||||
*/
|
||||
public static function pages(string $query = null, $params = [])
|
||||
{
|
||||
return App::instance()->site()->index()->search($query, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $query
|
||||
* @param array $params
|
||||
* @return Kirby\Cms\Users
|
||||
*/
|
||||
public static function users(string $query = null, $params = [])
|
||||
{
|
||||
return App::instance()->users()->search($query, $params);
|
||||
|
@@ -5,6 +5,15 @@ namespace Kirby\Cms;
|
||||
use Kirby\Exception\InvalidArgumentException;
|
||||
use Kirby\Toolkit\Component;
|
||||
|
||||
/**
|
||||
* Section
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class Section extends Component
|
||||
{
|
||||
|
||||
@@ -36,11 +45,17 @@ class Section extends Component
|
||||
parent::__construct($type, $attrs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Kirby\Cms\App
|
||||
*/
|
||||
public function kirby()
|
||||
{
|
||||
return $this->model->kirby();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Kirby\Cms\Model
|
||||
*/
|
||||
public function model()
|
||||
{
|
||||
return $this->model;
|
||||
|
@@ -2,7 +2,6 @@
|
||||
|
||||
namespace Kirby\Cms;
|
||||
|
||||
use Kirby\Exception\Exception;
|
||||
use Kirby\Exception\InvalidArgumentException;
|
||||
use Kirby\Exception\LogicException;
|
||||
use Kirby\Toolkit\A;
|
||||
@@ -16,8 +15,9 @@ use Kirby\Toolkit\Str;
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link http://getkirby.com
|
||||
* @copyright Bastian Allgeier
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class Site extends ModelWithContent
|
||||
{
|
||||
@@ -128,7 +128,7 @@ class Site extends ModelWithContent
|
||||
}
|
||||
|
||||
/**
|
||||
* Improved var_dump output
|
||||
* Improved `var_dump` output
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
@@ -160,9 +160,9 @@ class Site extends ModelWithContent
|
||||
/**
|
||||
* Returns the blueprint object
|
||||
*
|
||||
* @return SiteBlueprint
|
||||
* @return Kirby\Cms\SiteBlueprint
|
||||
*/
|
||||
public function blueprint(): SiteBlueprint
|
||||
public function blueprint()
|
||||
{
|
||||
if (is_a($this->blueprint, 'Kirby\Cms\SiteBlueprint') === true) {
|
||||
return $this->blueprint;
|
||||
@@ -200,7 +200,7 @@ class Site extends ModelWithContent
|
||||
/**
|
||||
* Builds a breadcrumb collection
|
||||
*
|
||||
* @return Pages
|
||||
* @return Kirby\Cms\Pages
|
||||
*/
|
||||
public function breadcrumb()
|
||||
{
|
||||
@@ -243,7 +243,7 @@ class Site extends ModelWithContent
|
||||
/**
|
||||
* Returns the error page object
|
||||
*
|
||||
* @return Page
|
||||
* @return Kirby\Cms\Page|null
|
||||
*/
|
||||
public function errorPage()
|
||||
{
|
||||
@@ -282,7 +282,7 @@ class Site extends ModelWithContent
|
||||
/**
|
||||
* Returns the home page object
|
||||
*
|
||||
* @return Page
|
||||
* @return Kirby\Cms\Page|null
|
||||
*/
|
||||
public function homePage()
|
||||
{
|
||||
@@ -334,7 +334,7 @@ class Site extends ModelWithContent
|
||||
/**
|
||||
* Compares the current object with the given site object
|
||||
*
|
||||
* @param Site $site
|
||||
* @param mixed $site
|
||||
* @return bool
|
||||
*/
|
||||
public function is($site): bool
|
||||
@@ -391,7 +391,7 @@ class Site extends ModelWithContent
|
||||
* it can be found. (see `Site::homePage()`)
|
||||
*
|
||||
* @param string $path
|
||||
* @return Page|null
|
||||
* @return Kirby\Cms\Page|null
|
||||
*/
|
||||
public function page(string $path = null)
|
||||
{
|
||||
@@ -413,9 +413,9 @@ class Site extends ModelWithContent
|
||||
/**
|
||||
* Alias for `Site::children()`
|
||||
*
|
||||
* @return Pages
|
||||
* @return Kirby\Cms\Pages
|
||||
*/
|
||||
public function pages(): Pages
|
||||
public function pages()
|
||||
{
|
||||
return $this->children();
|
||||
}
|
||||
@@ -451,7 +451,7 @@ class Site extends ModelWithContent
|
||||
/**
|
||||
* Returns the permissions object for this site
|
||||
*
|
||||
* @return SitePermissions
|
||||
* @return Kirby\Cms\SitePermissions
|
||||
*/
|
||||
public function permissions()
|
||||
{
|
||||
@@ -459,29 +459,26 @@ class Site extends ModelWithContent
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a string query, starting from the model
|
||||
* Preview Url
|
||||
*
|
||||
* @internal
|
||||
* @param string|null $query
|
||||
* @param string|null $expect
|
||||
* @return mixed
|
||||
* @return string|null
|
||||
*/
|
||||
public function query(string $query = null, string $expect = null)
|
||||
public function previewUrl(): ?string
|
||||
{
|
||||
if ($query === null) {
|
||||
$preview = $this->blueprint()->preview();
|
||||
|
||||
if ($preview === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$result = Str::query($query, [
|
||||
'kirby' => $this->kirby(),
|
||||
'site' => $this,
|
||||
]);
|
||||
|
||||
if ($expect !== null && is_a($result, $expect) !== true) {
|
||||
return null;
|
||||
if ($preview === true) {
|
||||
$url = $this->url();
|
||||
} else {
|
||||
$url = $preview;
|
||||
}
|
||||
|
||||
return $result;
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -499,7 +496,7 @@ class Site extends ModelWithContent
|
||||
* which is being used in various methods
|
||||
* to check for valid actions and input.
|
||||
*
|
||||
* @return SiteRules
|
||||
* @return Kirby\Cms\SiteRules
|
||||
*/
|
||||
protected function rules()
|
||||
{
|
||||
@@ -511,7 +508,7 @@ class Site extends ModelWithContent
|
||||
*
|
||||
* @param string $query
|
||||
* @param array $params
|
||||
* @return Pages
|
||||
* @return Kirby\Cms\Pages
|
||||
*/
|
||||
public function search(string $query = null, $params = [])
|
||||
{
|
||||
@@ -524,7 +521,7 @@ class Site extends ModelWithContent
|
||||
* @param array|null $blueprint
|
||||
* @return self
|
||||
*/
|
||||
protected function setBlueprint(array $blueprint = null): self
|
||||
protected function setBlueprint(array $blueprint = null)
|
||||
{
|
||||
if ($blueprint !== null) {
|
||||
$blueprint['model'] = $this;
|
||||
@@ -543,7 +540,7 @@ class Site extends ModelWithContent
|
||||
* @param string $id
|
||||
* @return self
|
||||
*/
|
||||
protected function setErrorPageId(string $id = 'error'): self
|
||||
protected function setErrorPageId(string $id = 'error')
|
||||
{
|
||||
$this->errorPageId = $id;
|
||||
return $this;
|
||||
@@ -558,7 +555,7 @@ class Site extends ModelWithContent
|
||||
* @param string $id
|
||||
* @return self
|
||||
*/
|
||||
protected function setHomePageId(string $id = 'home'): self
|
||||
protected function setHomePageId(string $id = 'home')
|
||||
{
|
||||
$this->homePageId = $id;
|
||||
return $this;
|
||||
@@ -568,10 +565,10 @@ class Site extends ModelWithContent
|
||||
* Sets the current page object
|
||||
*
|
||||
* @internal
|
||||
* @param Page|null $page
|
||||
* @param Kirby\Cms\Page|null $page
|
||||
* @return self
|
||||
*/
|
||||
public function setPage(Page $page = null): self
|
||||
public function setPage(Page $page = null)
|
||||
{
|
||||
$this->page = $page;
|
||||
return $this;
|
||||
@@ -581,9 +578,9 @@ class Site extends ModelWithContent
|
||||
* Sets the Url
|
||||
*
|
||||
* @param string $url
|
||||
* @return void
|
||||
* @return self
|
||||
*/
|
||||
protected function setUrl($url = null): self
|
||||
protected function setUrl($url = null)
|
||||
{
|
||||
$this->url = $url;
|
||||
return $this;
|
||||
@@ -609,24 +606,6 @@ class Site extends ModelWithContent
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* String template builder
|
||||
*
|
||||
* @param string|null $template
|
||||
* @return string
|
||||
*/
|
||||
public function toString(string $template = null): string
|
||||
{
|
||||
if ($template === null) {
|
||||
return $this->url();
|
||||
}
|
||||
|
||||
return Str::template($template, [
|
||||
'site' => $this,
|
||||
'kirby' => $this->kirby()
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Url
|
||||
*
|
||||
@@ -665,11 +644,11 @@ class Site extends ModelWithContent
|
||||
* returns the current page
|
||||
*
|
||||
* @internal
|
||||
* @param string|Page $page
|
||||
* @param string|Kirby\Cms\Page $page
|
||||
* @param string|null $languageCode
|
||||
* @return Page
|
||||
* @return Kirby\Cms\Page
|
||||
*/
|
||||
public function visit($page, string $languageCode = null): Page
|
||||
public function visit($page, string $languageCode = null)
|
||||
{
|
||||
if ($languageCode !== null) {
|
||||
$this->kirby()->setCurrentTranslation($languageCode);
|
||||
|
@@ -3,11 +3,16 @@
|
||||
namespace Kirby\Cms;
|
||||
|
||||
use Closure;
|
||||
use Kirby\Data\Data;
|
||||
use Kirby\Exception\InvalidArgumentException;
|
||||
use Kirby\Toolkit\F;
|
||||
use Kirby\Toolkit\Str;
|
||||
|
||||
/**
|
||||
* SiteActions
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
trait SiteActions
|
||||
{
|
||||
|
||||
@@ -44,7 +49,7 @@ trait SiteActions
|
||||
* @param string|null $languageCode
|
||||
* @return self
|
||||
*/
|
||||
public function changeTitle(string $title, string $languageCode = null): self
|
||||
public function changeTitle(string $title, string $languageCode = null)
|
||||
{
|
||||
return $this->commit('changeTitle', [$this, $title, $languageCode], function ($site, $title, $languageCode) {
|
||||
return $site->save(['title' => $title], $languageCode);
|
||||
@@ -55,7 +60,7 @@ trait SiteActions
|
||||
* Creates a main page
|
||||
*
|
||||
* @param array $props
|
||||
* @return Page
|
||||
* @return Kirby\Cms\Page
|
||||
*/
|
||||
public function createChild(array $props)
|
||||
{
|
||||
@@ -71,8 +76,10 @@ trait SiteActions
|
||||
|
||||
/**
|
||||
* Clean internal caches
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function purge(): self
|
||||
public function purge()
|
||||
{
|
||||
$this->children = null;
|
||||
$this->blueprint = null;
|
||||
|
@@ -5,9 +5,21 @@ namespace Kirby\Cms;
|
||||
/**
|
||||
* Extension of the basic blueprint class
|
||||
* to handle the blueprint for the site.
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class SiteBlueprint extends Blueprint
|
||||
{
|
||||
/**
|
||||
* Creates a new page blueprint object
|
||||
* with the given props
|
||||
*
|
||||
* @param array $props
|
||||
*/
|
||||
public function __construct(array $props)
|
||||
{
|
||||
parent::__construct($props);
|
||||
@@ -26,4 +38,23 @@ class SiteBlueprint extends Blueprint
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the preview settings
|
||||
* The preview setting controlls the "Open"
|
||||
* button in the panel and redirects it to a
|
||||
* different URL if necessary.
|
||||
*
|
||||
* @return string|boolean
|
||||
*/
|
||||
public function preview()
|
||||
{
|
||||
$preview = $this->props['options']['preview'] ?? true;
|
||||
|
||||
if (is_string($preview) === true) {
|
||||
return $this->model->toString($preview);
|
||||
}
|
||||
|
||||
return $preview;
|
||||
}
|
||||
}
|
||||
|
@@ -2,6 +2,15 @@
|
||||
|
||||
namespace Kirby\Cms;
|
||||
|
||||
/**
|
||||
* SitePermissions
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class SitePermissions extends ModelPermissions
|
||||
{
|
||||
protected $category = 'site';
|
||||
|
@@ -2,11 +2,16 @@
|
||||
|
||||
namespace Kirby\Cms;
|
||||
|
||||
use Exception;
|
||||
use Kirby\Exception\PermissionException;
|
||||
|
||||
/**
|
||||
* Validators for all site actions
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class SiteRules
|
||||
{
|
||||
|
@@ -2,8 +2,6 @@
|
||||
|
||||
namespace Kirby\Cms;
|
||||
|
||||
use Kirby\Exception\InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* The Structure class wraps
|
||||
* array data into a nicely chainable
|
||||
@@ -14,8 +12,9 @@ use Kirby\Exception\InvalidArgumentException;
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link http://getkirby.com
|
||||
* @copyright Bastian Allgeier
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class Structure extends Collection
|
||||
{
|
||||
|
@@ -14,8 +14,9 @@ namespace Kirby\Cms;
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link http://getkirby.com
|
||||
* @copyright Bastian Allgeier
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class StructureObject extends Model
|
||||
{
|
||||
@@ -76,9 +77,9 @@ class StructureObject extends Model
|
||||
/**
|
||||
* Returns the content
|
||||
*
|
||||
* @return Content
|
||||
* @return Kirby\Cms\Content
|
||||
*/
|
||||
public function content(): Content
|
||||
public function content()
|
||||
{
|
||||
if (is_a($this->content, 'Kirby\Cms\Content') === true) {
|
||||
return $this->content;
|
||||
@@ -119,7 +120,7 @@ class StructureObject extends Model
|
||||
/**
|
||||
* Returns the parent Model object
|
||||
*
|
||||
* @return Page|Site|File|User
|
||||
* @return Kirby\Cms\Model
|
||||
*/
|
||||
public function parent()
|
||||
{
|
||||
@@ -132,7 +133,7 @@ class StructureObject extends Model
|
||||
* @param array|null $content
|
||||
* @return self
|
||||
*/
|
||||
protected function setContent(array $content = null): self
|
||||
protected function setContent(array $content = null)
|
||||
{
|
||||
$this->content = $content;
|
||||
return $this;
|
||||
@@ -147,7 +148,7 @@ class StructureObject extends Model
|
||||
* @param string $id
|
||||
* @return self
|
||||
*/
|
||||
protected function setId(string $id): self
|
||||
protected function setId(string $id)
|
||||
{
|
||||
$this->id = $id;
|
||||
return $this;
|
||||
@@ -157,10 +158,10 @@ class StructureObject extends Model
|
||||
* Sets the parent Model. This can either be a
|
||||
* Page, Site, File or User object
|
||||
*
|
||||
* @param Page|Site|File|User|null $parent
|
||||
* @param Kirby\Cms\Model|null $parent
|
||||
* @return self
|
||||
*/
|
||||
protected function setParent(Model $parent = null): self
|
||||
protected function setParent(Model $parent = null)
|
||||
{
|
||||
$this->parent = $parent;
|
||||
return $this;
|
||||
@@ -169,10 +170,10 @@ class StructureObject extends Model
|
||||
/**
|
||||
* Sets the parent Structure collection
|
||||
*
|
||||
* @param Structure $structure
|
||||
* @param Kirby\Cms\Structure $structure
|
||||
* @return self
|
||||
*/
|
||||
protected function setStructure(Structure $structure = null): self
|
||||
protected function setStructure(Structure $structure = null)
|
||||
{
|
||||
$this->structure = $structure;
|
||||
return $this;
|
||||
@@ -181,7 +182,7 @@ class StructureObject extends Model
|
||||
/**
|
||||
* Returns the parent Structure collection as siblings
|
||||
*
|
||||
* @return Structure
|
||||
* @return Kirby\Cms\Structure
|
||||
*/
|
||||
protected function siblingsCollection()
|
||||
{
|
||||
|
@@ -5,6 +5,7 @@ namespace Kirby\Cms;
|
||||
use Throwable;
|
||||
use Kirby\Data\Json;
|
||||
use Kirby\Exception\Exception;
|
||||
use Kirby\Exception\InvalidArgumentException;
|
||||
use Kirby\Exception\PermissionException;
|
||||
use Kirby\Http\Remote;
|
||||
use Kirby\Http\Uri;
|
||||
@@ -12,6 +13,7 @@ use Kirby\Http\Url;
|
||||
use Kirby\Toolkit\Dir;
|
||||
use Kirby\Toolkit\F;
|
||||
use Kirby\Toolkit\Str;
|
||||
use Kirby\Toolkit\V;
|
||||
|
||||
/**
|
||||
* The System class gathers all information
|
||||
@@ -20,6 +22,12 @@ use Kirby\Toolkit\Str;
|
||||
*
|
||||
* This is mostly used by the panel installer
|
||||
* to check if the panel can be installed at all.
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class System
|
||||
{
|
||||
@@ -30,7 +38,7 @@ class System
|
||||
protected $app;
|
||||
|
||||
/**
|
||||
* @param App $app
|
||||
* @param Kirby\Cms\App $app
|
||||
*/
|
||||
public function __construct(App $app)
|
||||
{
|
||||
@@ -41,7 +49,7 @@ class System
|
||||
}
|
||||
|
||||
/**
|
||||
* Improved var_dump output
|
||||
* Improved `var_dump` output
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
@@ -99,6 +107,29 @@ class System
|
||||
return extension_loaded('curl');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the app's human-readable
|
||||
* index URL without scheme
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function indexUrl(): string
|
||||
{
|
||||
$url = $this->app->url('index');
|
||||
|
||||
if (Url::isAbsolute($url)) {
|
||||
$uri = Url::toObject($url);
|
||||
} else {
|
||||
// index URL was configured without host, use the current host
|
||||
$uri = Uri::current([
|
||||
'path' => $url,
|
||||
'query' => null
|
||||
]);
|
||||
}
|
||||
|
||||
return $uri->setScheme(null)->setSlash(false)->toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the most important folders
|
||||
* if they don't exist yet
|
||||
@@ -194,29 +225,6 @@ class System
|
||||
return in_array(false, array_values($this->status()), true) === false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the app's index URL for
|
||||
* licensing purposes without scheme
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function licenseUrl(): string
|
||||
{
|
||||
$url = $this->app->url('index');
|
||||
|
||||
if (Url::isAbsolute($url)) {
|
||||
$uri = Url::toObject($url);
|
||||
} else {
|
||||
// index URL was configured without host, use the current host
|
||||
$uri = Uri::current([
|
||||
'path' => $url,
|
||||
'query' => null
|
||||
]);
|
||||
}
|
||||
|
||||
return $uri->setScheme(null)->setSlash(false)->toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes the app's index URL for
|
||||
* licensing purposes
|
||||
@@ -224,10 +232,10 @@ class System
|
||||
* @param string|null $url Input URL, by default the app's index URL
|
||||
* @return string Normalized URL
|
||||
*/
|
||||
protected function licenseUrlNormalized(string $url = null): string
|
||||
protected function licenseUrl(string $url = null): string
|
||||
{
|
||||
if ($url === null) {
|
||||
$url = $this->licenseUrl();
|
||||
$url = $this->indexUrl();
|
||||
}
|
||||
|
||||
// remove common "testing" subdomains as well as www.
|
||||
@@ -300,7 +308,7 @@ class System
|
||||
}
|
||||
|
||||
// verify the URL
|
||||
if ($this->licenseUrlNormalized() !== $this->licenseUrlNormalized($license['domain'])) {
|
||||
if ($this->licenseUrl() !== $this->licenseUrl($license['domain'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -346,13 +354,25 @@ class System
|
||||
* @param string $email
|
||||
* @return boolean
|
||||
*/
|
||||
public function register(string $license, string $email): bool
|
||||
public function register(string $license = null, string $email = null): bool
|
||||
{
|
||||
if (Str::startsWith($license, 'K3-PRO-') === false) {
|
||||
throw new InvalidArgumentException([
|
||||
'key' => 'license.format'
|
||||
]);
|
||||
}
|
||||
|
||||
if (V::email($email) === false) {
|
||||
throw new InvalidArgumentException([
|
||||
'key' => 'license.email'
|
||||
]);
|
||||
}
|
||||
|
||||
$response = Remote::get('https://licenses.getkirby.com/register', [
|
||||
'data' => [
|
||||
'license' => $license,
|
||||
'email' => $email,
|
||||
'domain' => $this->licenseUrl()
|
||||
'domain' => $this->indexUrl()
|
||||
]
|
||||
]);
|
||||
|
||||
@@ -373,7 +393,9 @@ class System
|
||||
Json::write($file, $json);
|
||||
|
||||
if ($this->license() === false) {
|
||||
throw new Exception('The license could not be verified');
|
||||
throw new InvalidArgumentException([
|
||||
'key' => 'license.verification'
|
||||
]);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@@ -5,12 +5,16 @@ namespace Kirby\Cms;
|
||||
use Exception;
|
||||
use Kirby\Toolkit\F;
|
||||
use Kirby\Toolkit\Tpl;
|
||||
use Kirby\Toolkit\View;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Represents a Kirby template and takes care
|
||||
* of loading the correct file.
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class Template
|
||||
{
|
||||
|
@@ -8,6 +8,12 @@ use Kirby\Data\Data;
|
||||
/**
|
||||
* Wrapper around Kirby's localization files,
|
||||
* which are store in `kirby/translations`.
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class Translation
|
||||
{
|
||||
@@ -32,7 +38,7 @@ class Translation
|
||||
}
|
||||
|
||||
/**
|
||||
* Improved var_dump output
|
||||
* Improved `var_dump` output
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
|
@@ -10,19 +10,29 @@ use Kirby\Toolkit\F;
|
||||
* Provides a factory method to convert an array
|
||||
* to a collection of Translation objects and load
|
||||
* method to load all translations from disk
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class Translations extends Collection
|
||||
{
|
||||
public function start(string $code)
|
||||
public function start(string $code): void
|
||||
{
|
||||
F::move($this->parent->contentFile('', true), $this->parent->contentFile($code, true));
|
||||
}
|
||||
|
||||
public function stop(string $code)
|
||||
public function stop(string $code): void
|
||||
{
|
||||
F::move($this->parent->contentFile($code, true), $this->parent->contentFile('', true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $translations
|
||||
* @return self
|
||||
*/
|
||||
public static function factory(array $translations)
|
||||
{
|
||||
$collection = new static;
|
||||
@@ -35,6 +45,11 @@ class Translations extends Collection
|
||||
return $collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $root
|
||||
* @param array $inject
|
||||
* @return self
|
||||
*/
|
||||
public static function load(string $root, array $inject = [])
|
||||
{
|
||||
$collection = new static;
|
||||
|
@@ -3,7 +3,6 @@
|
||||
namespace Kirby\Cms;
|
||||
|
||||
use Kirby\Http\Url as BaseUrl;
|
||||
use Kirby\Toolkit\Str;
|
||||
|
||||
/**
|
||||
* The `Url` class extends the
|
||||
@@ -16,8 +15,9 @@ use Kirby\Toolkit\Str;
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link http://getkirby.com
|
||||
* @copyright Bastian Allgeier
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class Url extends BaseUrl
|
||||
{
|
||||
|
@@ -7,11 +7,8 @@ use Kirby\Exception\InvalidArgumentException;
|
||||
use Kirby\Exception\NotFoundException;
|
||||
use Kirby\Exception\PermissionException;
|
||||
use Kirby\Session\Session;
|
||||
use Kirby\Toolkit\A;
|
||||
use Kirby\Toolkit\F;
|
||||
use Kirby\Toolkit\Str;
|
||||
use Kirby\Toolkit\V;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* The `$user` object represents a
|
||||
@@ -19,14 +16,16 @@ use Throwable;
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link http://getkirby.com
|
||||
* @copyright Bastian Allgeier
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class User extends ModelWithContent
|
||||
{
|
||||
const CLASS_ALIAS = 'user';
|
||||
|
||||
use HasFiles;
|
||||
use HasMethods;
|
||||
use HasSiblings;
|
||||
use UserActions;
|
||||
|
||||
@@ -70,6 +69,20 @@ class User extends ModelWithContent
|
||||
*/
|
||||
protected $language;
|
||||
|
||||
/**
|
||||
* All registered user methods
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $methods = [];
|
||||
|
||||
/**
|
||||
* Registry with all User models
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $models = [];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
@@ -102,6 +115,11 @@ class User extends ModelWithContent
|
||||
return $this->$method;
|
||||
}
|
||||
|
||||
// user methods
|
||||
if ($this->hasMethod($method)) {
|
||||
return $this->callMethod($method, $arguments);
|
||||
}
|
||||
|
||||
// return site content otherwise
|
||||
return $this->content()->get($method, $arguments);
|
||||
}
|
||||
@@ -118,7 +136,7 @@ class User extends ModelWithContent
|
||||
}
|
||||
|
||||
/**
|
||||
* Improved var_dump() output
|
||||
* Improved `var_dump` output
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
@@ -150,7 +168,7 @@ class User extends ModelWithContent
|
||||
/**
|
||||
* Returns the File object for the avatar or null
|
||||
*
|
||||
* @return File|null
|
||||
* @return Kirby\Cms\File|null
|
||||
*/
|
||||
public function avatar()
|
||||
{
|
||||
@@ -160,7 +178,7 @@ class User extends ModelWithContent
|
||||
/**
|
||||
* Returns the UserBlueprint object
|
||||
*
|
||||
* @return UserBlueprint
|
||||
* @return Kirby\Cms\UserBlueprint
|
||||
*/
|
||||
public function blueprint()
|
||||
{
|
||||
@@ -237,6 +255,22 @@ class User extends ModelWithContent
|
||||
return is_file($this->contentFile('default')) === true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a User object and also
|
||||
* takes User models into account.
|
||||
*
|
||||
* @internal
|
||||
* @return self
|
||||
*/
|
||||
public static function factory($props)
|
||||
{
|
||||
if (empty($props['model']) === false) {
|
||||
return static::model($props['model'], $props);
|
||||
}
|
||||
|
||||
return new static($props);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hashes user password
|
||||
*
|
||||
@@ -244,7 +278,7 @@ class User extends ModelWithContent
|
||||
* @param string|null $password
|
||||
* @return string|null
|
||||
*/
|
||||
public static function hashPassword($password)
|
||||
public static function hashPassword($password): ?string
|
||||
{
|
||||
if ($password !== null) {
|
||||
$info = password_get_info($password);
|
||||
@@ -292,7 +326,7 @@ class User extends ModelWithContent
|
||||
/**
|
||||
* Compares the current object with the given user object
|
||||
*
|
||||
* @param User|null $user
|
||||
* @param Kirby\Cms\User|null $user
|
||||
* @return bool
|
||||
*/
|
||||
public function is(User $user = null): bool
|
||||
@@ -370,19 +404,14 @@ class User extends ModelWithContent
|
||||
* Logs the user in
|
||||
*
|
||||
* @param string $password
|
||||
* @param Session|array $session Session options or session object to set the user in
|
||||
* @param Kirby\Session\Session|array $session Session options or session object to set the user in
|
||||
* @return bool
|
||||
*
|
||||
* @throws PermissionException If the password is not valid
|
||||
*/
|
||||
public function login(string $password, $session = null): bool
|
||||
{
|
||||
try {
|
||||
$this->validatePassword($password);
|
||||
} catch (Exception $e) {
|
||||
throw new PermissionException(['key' => 'access.login']);
|
||||
}
|
||||
|
||||
$this->validatePassword($password);
|
||||
$this->loginPasswordless($session);
|
||||
|
||||
return true;
|
||||
@@ -391,10 +420,10 @@ class User extends ModelWithContent
|
||||
/**
|
||||
* Logs the user in without checking the password
|
||||
*
|
||||
* @param Session|array $session Session options or session object to set the user in
|
||||
* @param SKirby\Session\Session|array $session Session options or session object to set the user in
|
||||
* @return void
|
||||
*/
|
||||
public function loginPasswordless($session = null)
|
||||
public function loginPasswordless($session = null): void
|
||||
{
|
||||
$session = $this->sessionFromOptions($session);
|
||||
|
||||
@@ -405,10 +434,10 @@ class User extends ModelWithContent
|
||||
/**
|
||||
* Logs the user out
|
||||
*
|
||||
* @param Session|array $session Session options or session object to unset the user in
|
||||
* @param Kirby\Session\Session|array $session Session options or session object to unset the user in
|
||||
* @return void
|
||||
*/
|
||||
public function logout($session = null)
|
||||
public function logout($session = null): void
|
||||
{
|
||||
$session = $this->sessionFromOptions($session);
|
||||
|
||||
@@ -445,6 +474,27 @@ class User extends ModelWithContent
|
||||
return $this->kirby()->url('media') . '/users/' . $this->id();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a user model if it has been registered
|
||||
*
|
||||
* @internal
|
||||
* @param string $name
|
||||
* @param array $props
|
||||
* @return Kirby\Cms\User
|
||||
*/
|
||||
public static function model(string $name, array $props = [])
|
||||
{
|
||||
if ($class = (static::$models[$name] ?? null)) {
|
||||
$object = new $class($props);
|
||||
|
||||
if (is_a($object, 'Kirby\Cms\User') === true) {
|
||||
return $object;
|
||||
}
|
||||
}
|
||||
|
||||
return new static($props);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last modification date of the user
|
||||
*
|
||||
@@ -465,7 +515,7 @@ class User extends ModelWithContent
|
||||
/**
|
||||
* Returns the user's name
|
||||
*
|
||||
* @return Field
|
||||
* @return Kirby\Cms\Field
|
||||
*/
|
||||
public function name()
|
||||
{
|
||||
@@ -486,7 +536,7 @@ class User extends ModelWithContent
|
||||
* @internal
|
||||
* @return self
|
||||
*/
|
||||
public static function nobody(): self
|
||||
public static function nobody()
|
||||
{
|
||||
return new static([
|
||||
'email' => 'nobody@getkirby.com',
|
||||
@@ -494,6 +544,36 @@ class User extends ModelWithContent
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Panel icon definition
|
||||
*
|
||||
* @internal
|
||||
* @param array $params
|
||||
* @return array
|
||||
*/
|
||||
public function panelIcon(array $params = null): array
|
||||
{
|
||||
$params['type'] = 'user';
|
||||
|
||||
return parent::panelIcon($params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the image file object based on provided query
|
||||
*
|
||||
* @internal
|
||||
* @param string|null $query
|
||||
* @return Kirby\Cms\File|Kirby\Cms\Asset|null
|
||||
*/
|
||||
protected function panelImageSource(string $query = null)
|
||||
{
|
||||
if ($query === null) {
|
||||
return $this->avatar();
|
||||
}
|
||||
|
||||
return parent::panelImageSource($query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the full path without leading slash
|
||||
*
|
||||
@@ -505,6 +585,29 @@ class User extends ModelWithContent
|
||||
return 'users/' . $this->id();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns prepared data for the panel user picker
|
||||
*
|
||||
* @param array|null $params
|
||||
* @return array
|
||||
*/
|
||||
public function panelPickerData(array $params = null): array
|
||||
{
|
||||
$image = $this->panelImage($params['image'] ?? []);
|
||||
$icon = $this->panelIcon($image);
|
||||
|
||||
return [
|
||||
'icon' => $icon,
|
||||
'id' => $this->id(),
|
||||
'image' => $image,
|
||||
'email' => $this->email(),
|
||||
'info' => $this->toString($params['info'] ?? false),
|
||||
'link' => $this->panelUrl(true),
|
||||
'text' => $this->toString($params['text'] ?? '{{ user.username }}'),
|
||||
'username' => $this->username(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the url to the editing view
|
||||
* in the panel
|
||||
@@ -537,46 +640,19 @@ class User extends ModelWithContent
|
||||
}
|
||||
|
||||
/**
|
||||
* @return UserPermissions
|
||||
* @return Kirby\Cms\UserPermissions
|
||||
*/
|
||||
public function permissions()
|
||||
{
|
||||
return new UserPermissions($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a string query, starting from the model
|
||||
*
|
||||
* @internal
|
||||
* @param string|null $query
|
||||
* @param string|null $expect
|
||||
* @return mixed
|
||||
*/
|
||||
public function query(string $query = null, string $expect = null)
|
||||
{
|
||||
if ($query === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$result = Str::query($query, [
|
||||
'kirby' => $kirby = $this->kirby(),
|
||||
'site' => $kirby->site(),
|
||||
'user' => $this
|
||||
]);
|
||||
|
||||
if ($expect !== null && is_a($result, $expect) !== true) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the user role
|
||||
*
|
||||
* @return string
|
||||
* @return Kirby\Cms\Role
|
||||
*/
|
||||
public function role(): Role
|
||||
public function role()
|
||||
{
|
||||
if (is_a($this->role, 'Kirby\Cms\Role') === true) {
|
||||
return $this->role;
|
||||
@@ -605,7 +681,7 @@ class User extends ModelWithContent
|
||||
* Returns the UserRules class to
|
||||
* validate any important action.
|
||||
*
|
||||
* @return UserRules
|
||||
* @return Kirby\Cms\UserRules
|
||||
*/
|
||||
protected function rules()
|
||||
{
|
||||
@@ -618,7 +694,7 @@ class User extends ModelWithContent
|
||||
* @param array|null $blueprint
|
||||
* @return self
|
||||
*/
|
||||
protected function setBlueprint(array $blueprint = null): self
|
||||
protected function setBlueprint(array $blueprint = null)
|
||||
{
|
||||
if ($blueprint !== null) {
|
||||
$blueprint['model'] = $this;
|
||||
@@ -634,7 +710,7 @@ class User extends ModelWithContent
|
||||
* @param string $email
|
||||
* @return self
|
||||
*/
|
||||
protected function setEmail(string $email = null): self
|
||||
protected function setEmail(string $email = null)
|
||||
{
|
||||
if ($email !== null) {
|
||||
$this->email = strtolower(trim($email));
|
||||
@@ -648,7 +724,7 @@ class User extends ModelWithContent
|
||||
* @param string $id
|
||||
* @return self
|
||||
*/
|
||||
protected function setId(string $id = null): self
|
||||
protected function setId(string $id = null)
|
||||
{
|
||||
$this->id = $id;
|
||||
return $this;
|
||||
@@ -660,7 +736,7 @@ class User extends ModelWithContent
|
||||
* @param string $language
|
||||
* @return self
|
||||
*/
|
||||
protected function setLanguage(string $language = null): self
|
||||
protected function setLanguage(string $language = null)
|
||||
{
|
||||
$this->language = $language !== null ? trim($language) : null;
|
||||
return $this;
|
||||
@@ -672,7 +748,7 @@ class User extends ModelWithContent
|
||||
* @param string $name
|
||||
* @return self
|
||||
*/
|
||||
protected function setName(string $name = null): self
|
||||
protected function setName(string $name = null)
|
||||
{
|
||||
$this->name = $name !== null ? trim($name) : null;
|
||||
return $this;
|
||||
@@ -684,7 +760,7 @@ class User extends ModelWithContent
|
||||
* @param string $password
|
||||
* @return self
|
||||
*/
|
||||
protected function setPassword(string $password = null): self
|
||||
protected function setPassword(string $password = null)
|
||||
{
|
||||
$this->password = $password;
|
||||
return $this;
|
||||
@@ -696,7 +772,7 @@ class User extends ModelWithContent
|
||||
* @param string $role
|
||||
* @return self
|
||||
*/
|
||||
protected function setRole(string $role = null): self
|
||||
protected function setRole(string $role = null)
|
||||
{
|
||||
$this->role = $role !== null ? strtolower(trim($role)) : null;
|
||||
return $this;
|
||||
@@ -705,10 +781,10 @@ class User extends ModelWithContent
|
||||
/**
|
||||
* Converts session options into a session object
|
||||
*
|
||||
* @param Session|array $session Session options or session object to unset the user in
|
||||
* @return Session
|
||||
* @param Kirby\Session\Session|array $session Session options or session object to unset the user in
|
||||
* @return Kirby\Session\Session
|
||||
*/
|
||||
protected function sessionFromOptions($session): Session
|
||||
protected function sessionFromOptions($session)
|
||||
{
|
||||
// use passed session options or session object if set
|
||||
if (is_array($session) === true) {
|
||||
@@ -723,7 +799,7 @@ class User extends ModelWithContent
|
||||
/**
|
||||
* Returns the parent Users collection
|
||||
*
|
||||
* @return Users
|
||||
* @return Kirby\Cms\Users
|
||||
*/
|
||||
protected function siblingsCollection()
|
||||
{
|
||||
@@ -758,14 +834,10 @@ class User extends ModelWithContent
|
||||
public function toString(string $template = null): string
|
||||
{
|
||||
if ($template === null) {
|
||||
return $this->email();
|
||||
$template = $this->email();
|
||||
}
|
||||
|
||||
return Str::template($template, [
|
||||
'user' => $this,
|
||||
'site' => $this->site(),
|
||||
'kirby' => $this->kirby()
|
||||
]);
|
||||
return parent::toString($template);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -773,7 +845,7 @@ class User extends ModelWithContent
|
||||
* which is the given name or the email
|
||||
* as a fallback
|
||||
*
|
||||
* @return string
|
||||
* @return string|null
|
||||
*/
|
||||
public function username(): ?string
|
||||
{
|
||||
|
@@ -4,16 +4,21 @@ namespace Kirby\Cms;
|
||||
|
||||
use Closure;
|
||||
use Kirby\Data\Data;
|
||||
use Kirby\Exception\DuplicateException;
|
||||
use Kirby\Exception\Exception;
|
||||
use Kirby\Exception\InvalidArgumentLogicException;
|
||||
use Kirby\Exception\LogicException;
|
||||
use Kirby\Exception\PermissionException;
|
||||
use Kirby\Toolkit\Dir;
|
||||
use Kirby\Toolkit\F;
|
||||
use Kirby\Toolkit\Str;
|
||||
use Kirby\Toolkit\V;
|
||||
|
||||
/**
|
||||
* UserActions
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
trait UserActions
|
||||
{
|
||||
|
||||
@@ -23,7 +28,7 @@ trait UserActions
|
||||
* @param string $email
|
||||
* @return self
|
||||
*/
|
||||
public function changeEmail(string $email): self
|
||||
public function changeEmail(string $email)
|
||||
{
|
||||
return $this->commit('changeEmail', [$this, $email], function ($user, $email) {
|
||||
$user = $user->clone([
|
||||
@@ -44,7 +49,7 @@ trait UserActions
|
||||
* @param string $language
|
||||
* @return self
|
||||
*/
|
||||
public function changeLanguage(string $language): self
|
||||
public function changeLanguage(string $language)
|
||||
{
|
||||
return $this->commit('changeLanguage', [$this, $language], function ($user, $language) {
|
||||
$user = $user->clone([
|
||||
@@ -65,7 +70,7 @@ trait UserActions
|
||||
* @param string $name
|
||||
* @return self
|
||||
*/
|
||||
public function changeName(string $name): self
|
||||
public function changeName(string $name)
|
||||
{
|
||||
return $this->commit('changeName', [$this, $name], function ($user, $name) {
|
||||
$user = $user->clone([
|
||||
@@ -86,7 +91,7 @@ trait UserActions
|
||||
* @param string $password
|
||||
* @return self
|
||||
*/
|
||||
public function changePassword(string $password): self
|
||||
public function changePassword(string $password)
|
||||
{
|
||||
return $this->commit('changePassword', [$this, $password], function ($user, $password) {
|
||||
$user = $user->clone([
|
||||
@@ -105,7 +110,7 @@ trait UserActions
|
||||
* @param string $role
|
||||
* @return self
|
||||
*/
|
||||
public function changeRole(string $role): self
|
||||
public function changeRole(string $role)
|
||||
{
|
||||
return $this->commit('changeRole', [$this, $role], function ($user, $role) {
|
||||
$user = $user->clone([
|
||||
@@ -156,7 +161,7 @@ trait UserActions
|
||||
* @param array $input
|
||||
* @return self
|
||||
*/
|
||||
public static function create(array $props = null): self
|
||||
public static function create(array $props = null)
|
||||
{
|
||||
$data = $props;
|
||||
|
||||
@@ -164,7 +169,9 @@ trait UserActions
|
||||
$data['password'] = static::hashPassword($props['password']);
|
||||
}
|
||||
|
||||
$user = new static($data);
|
||||
$props['role'] = $props['model'] = strtolower($props['role'] ?? 'default');
|
||||
|
||||
$user = User::factory($data);
|
||||
|
||||
// create a form for the user
|
||||
$form = Form::for($user, [
|
||||
|
@@ -5,6 +5,12 @@ namespace Kirby\Cms;
|
||||
/**
|
||||
* Extension of the basic blueprint class
|
||||
* to handle all blueprints for users.
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class UserBlueprint extends Blueprint
|
||||
{
|
||||
|
@@ -2,6 +2,15 @@
|
||||
|
||||
namespace Kirby\Cms;
|
||||
|
||||
/**
|
||||
* UserPermissions
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class UserPermissions extends ModelPermissions
|
||||
{
|
||||
protected $category = 'users';
|
||||
|
@@ -11,6 +11,12 @@ use Kirby\Toolkit\V;
|
||||
|
||||
/**
|
||||
* Validators for all user actions
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class UserRules
|
||||
{
|
||||
@@ -164,7 +170,7 @@ class UserRules
|
||||
|
||||
public static function validId(User $user, string $id): bool
|
||||
{
|
||||
if ($duplicate = $user->kirby()->users()->find($id)) {
|
||||
if ($user->kirby()->users()->find($id)) {
|
||||
throw new DuplicateException('A user with this id exists');
|
||||
}
|
||||
|
||||
|
@@ -13,11 +13,20 @@ use Kirby\Toolkit\Str;
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link http://getkirby.com
|
||||
* @copyright Bastian Allgeier
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class Users extends Collection
|
||||
{
|
||||
|
||||
/**
|
||||
* All registered users methods
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $methods = [];
|
||||
|
||||
public function create(array $data)
|
||||
{
|
||||
return User::create($data);
|
||||
@@ -29,7 +38,7 @@ class Users extends Collection
|
||||
* current collection
|
||||
*
|
||||
* @param mixed $item
|
||||
* @return Users
|
||||
* @return self
|
||||
*/
|
||||
public function add($object)
|
||||
{
|
||||
@@ -56,13 +65,13 @@ class Users extends Collection
|
||||
* @param array $inject
|
||||
* @return self
|
||||
*/
|
||||
public static function factory(array $users, array $inject = []): self
|
||||
public static function factory(array $users, array $inject = [])
|
||||
{
|
||||
$collection = new static;
|
||||
|
||||
// read all user blueprints
|
||||
foreach ($users as $props) {
|
||||
$user = new User($props + $inject);
|
||||
$user = User::factory($props + $inject);
|
||||
$collection->set($user->id(), $user);
|
||||
}
|
||||
|
||||
@@ -73,9 +82,9 @@ class Users extends Collection
|
||||
* Finds a user in the collection by id or email address
|
||||
*
|
||||
* @param string $key
|
||||
* @return User|null
|
||||
* @return Kirby\Cms\User|null
|
||||
*/
|
||||
public function findByKey($key)
|
||||
public function findByKey(string $key)
|
||||
{
|
||||
if (Str::contains($key, '@') === true) {
|
||||
return parent::findBy('email', strtolower($key));
|
||||
@@ -91,7 +100,7 @@ class Users extends Collection
|
||||
* @param array $inject
|
||||
* @return self
|
||||
*/
|
||||
public static function load(string $root, array $inject = []): self
|
||||
public static function load(string $root, array $inject = [])
|
||||
{
|
||||
$users = new static;
|
||||
|
||||
@@ -109,4 +118,15 @@ class Users extends Collection
|
||||
|
||||
return $users;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut for `$users->filterBy('role', 'admin')`
|
||||
*
|
||||
* @param string $role
|
||||
* @return self
|
||||
*/
|
||||
public function role(string $role)
|
||||
{
|
||||
return $this->filterBy('role', $role);
|
||||
}
|
||||
}
|
||||
|
@@ -6,11 +6,17 @@ use Kirby\Toolkit\Facade;
|
||||
|
||||
/**
|
||||
* Shortcut to the visitor object
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class Visitor extends Facade
|
||||
{
|
||||
/**
|
||||
* @return \Kirby\Http\Visitor
|
||||
* @return Kirby\Http\Visitor
|
||||
*/
|
||||
public static function instance()
|
||||
{
|
||||
|
@@ -8,18 +8,19 @@ use Kirby\Toolkit\F;
|
||||
/**
|
||||
* The `Data` class provides readers and
|
||||
* writers for data. The class comes with
|
||||
* three handlers for `json`, `yaml` and
|
||||
* `txt` encoded data, but can be extended
|
||||
* and customized.
|
||||
* four handlers for `json`, `php`, `txt`
|
||||
* and `yaml` encoded data, but can be
|
||||
* extended and customized.
|
||||
*
|
||||
* The read and write methods automatically
|
||||
* detect, which data handler to use in order
|
||||
* detect which data handler to use in order
|
||||
* to correctly encode and decode passed data.
|
||||
*
|
||||
* @package Kirby
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link http://getkirby.com
|
||||
* @copyright Bastian Allgeier
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://opensource.org/licenses/MIT
|
||||
*/
|
||||
class Data
|
||||
{
|
||||
@@ -50,31 +51,31 @@ class Data
|
||||
/**
|
||||
* Handler getter
|
||||
*
|
||||
* @param string $type
|
||||
* @return Handler|null
|
||||
* @param string $type
|
||||
* @return Kirby\Data\Handler
|
||||
*/
|
||||
public static function handler(string $type)
|
||||
{
|
||||
// normalize the type
|
||||
$type = strtolower($type);
|
||||
$handler = static::$handlers[$type] ?? null;
|
||||
$type = strtolower($type);
|
||||
|
||||
if ($handler === null && isset(static::$aliases[$type]) === true) {
|
||||
$handler = static::$handlers[static::$aliases[$type]] ?? null;
|
||||
// find a handler or alias
|
||||
$handler = static::$handlers[$type] ??
|
||||
static::$handlers[static::$aliases[$type] ?? null] ??
|
||||
null;
|
||||
|
||||
if (class_exists($handler)) {
|
||||
return new $handler;
|
||||
}
|
||||
|
||||
if ($handler === null) {
|
||||
throw new Exception('Missing Handler for type: "' . $type . '"');
|
||||
}
|
||||
|
||||
return new $handler;
|
||||
throw new Exception('Missing handler for type: "' . $type . '"');
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode data with the specified handler
|
||||
* Decodes data with the specified handler
|
||||
*
|
||||
* @param string $data
|
||||
* @param string $type
|
||||
* @param string $data
|
||||
* @param string $type
|
||||
* @return array
|
||||
*/
|
||||
public static function decode(string $data = null, string $type): array
|
||||
@@ -83,10 +84,10 @@ class Data
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode data with the specified handler
|
||||
* Encodes data with the specified handler
|
||||
*
|
||||
* @param array $data
|
||||
* @param string $type
|
||||
* @param array $data
|
||||
* @param string $type
|
||||
* @return string
|
||||
*/
|
||||
public static function encode(array $data = null, string $type): string
|
||||
@@ -95,9 +96,9 @@ class Data
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads data from a file
|
||||
* The data handler is automatically chosen by
|
||||
* the extension if not specified.
|
||||
* Reads data from a file;
|
||||
* the data handler is automatically chosen by
|
||||
* the extension if not specified
|
||||
*
|
||||
* @param string $file
|
||||
* @param string $type
|
||||
@@ -109,13 +110,13 @@ class Data
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes data to a file.
|
||||
* The data handler is automatically chosen by
|
||||
* the extension if not specified.
|
||||
* Writes data to a file;
|
||||
* the data handler is automatically chosen by
|
||||
* the extension if not specified
|
||||
*
|
||||
* @param string $file
|
||||
* @param array $data
|
||||
* @param string $type
|
||||
* @param string $file
|
||||
* @param array $data
|
||||
* @param string $type
|
||||
* @return boolean
|
||||
*/
|
||||
public static function write(string $file = null, array $data = [], string $type = null): bool
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user