Upgrade to 3.0.2

This commit is contained in:
Bastian Allgeier
2019-02-19 16:39:58 +01:00
parent f76ee1bb14
commit 8e3d86a590
44 changed files with 638 additions and 264 deletions

View File

@@ -1,24 +0,0 @@
# Kirby
[![Build Status](https://travis-ci.com/getkirby/kirby.svg?branch=master)](https://travis-ci.com/getkirby/kirby)
This is Kirby's core application folder. Get started with one of the following repositories instead:
- [Starterkit](https://github.com/getkirby/starterkit)
- [Plainkit](https://github.com/getkirby/plainkit)
## Bug reports
Please post all bug reports in our issue tracker:
https://github.com/getkirby/kirby/issues
## Feature suggestions
If you want to suggest features or enhancements for Kirby, please use our Ideas repository:
https://github.com/getkirby/ideas/issues
## License
Kirby is not free software. In order to run Kirby on a public server you must purchase a valid license.
- https://getkirby.com/buy
- https://getkirby.com/license

View File

@@ -1,7 +1,7 @@
{ {
"name": "getkirby/cms", "name": "getkirby/cms",
"description": "The Kirby 3 core", "description": "The Kirby 3 core",
"version": "3.0.1", "version": "3.0.2",
"license": "proprietary", "license": "proprietary",
"keywords": ["kirby", "cms", "core"], "keywords": ["kirby", "cms", "core"],
"homepage": "https://getkirby.com", "homepage": "https://getkirby.com",
@@ -23,7 +23,7 @@
"php": ">=7.1.0", "php": ">=7.1.0",
"ext-mbstring": "*", "ext-mbstring": "*",
"ext-ctype": "*", "ext-ctype": "*",
"getkirby/composer-installer": "*", "getkirby/composer-installer": "^1.0",
"mustangostang/spyc": "0.6.2", "mustangostang/spyc": "0.6.2",
"michelf/php-smartypants": "1.8.1", "michelf/php-smartypants": "1.8.1",
"claviska/simpleimage": "3.3.3", "claviska/simpleimage": "3.3.3",

22
kirby/composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "795a9baff274c8a85cd3670e696e6331", "content-hash": "b4bfa5287bd05b9d23be8ff5411080ff",
"packages": [ "packages": [
{ {
"name": "claviska/simpleimage", "name": "claviska/simpleimage",
@@ -108,24 +108,24 @@
}, },
{ {
"name": "getkirby/composer-installer", "name": "getkirby/composer-installer",
"version": "1.0.1", "version": "1.1.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/k-next/composer-installer.git", "url": "https://github.com/getkirby/composer-installer.git",
"reference": "dc0e38c4f0fc04875c1a523d82364a44f436cbf4" "reference": "162497e4d9465fae95cb44b6135506eac54c9a05"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/k-next/composer-installer/zipball/dc0e38c4f0fc04875c1a523d82364a44f436cbf4", "url": "https://api.github.com/repos/getkirby/composer-installer/zipball/162497e4d9465fae95cb44b6135506eac54c9a05",
"reference": "dc0e38c4f0fc04875c1a523d82364a44f436cbf4", "reference": "162497e4d9465fae95cb44b6135506eac54c9a05",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"composer-plugin-api": "^1.0" "composer-plugin-api": "^1.0"
}, },
"require-dev": { "require-dev": {
"composer/composer": "^1.3", "composer/composer": "^1.8",
"phpunit/phpunit": "^6.0" "phpunit/phpunit": "^7.0"
}, },
"type": "composer-plugin", "type": "composer-plugin",
"extra": { "extra": {
@@ -133,16 +133,16 @@
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"Kirby\\ComposerInstaller\\": "src/" "Kirby\\": "src/"
} }
}, },
"notification-url": "https://packagist.org/downloads/", "notification-url": "https://packagist.org/downloads/",
"license": [ "license": [
"MIT" "MIT"
], ],
"description": "Kirby's custom Composer installer for the Kirby CMS", "description": "Kirby's custom Composer installer for the Kirby CMS and for Kirby plugins",
"homepage": "https://getkirby.com", "homepage": "https://getkirby.com",
"time": "2018-12-19T10:01:45+00:00" "time": "2019-02-06T09:15:26+00:00"
}, },
{ {
"name": "league/color-extractor", "name": "league/color-extractor",

View File

@@ -3,6 +3,7 @@
$aliases = [ $aliases = [
// cms classes // cms classes
'asset' => 'Kirby\Cms\Asset',
'collection' => 'Kirby\Cms\Collection', 'collection' => 'Kirby\Cms\Collection',
'dir' => 'Kirby\Cms\Dir', 'dir' => 'Kirby\Cms\Dir',
'field' => 'Kirby\Cms\Field', 'field' => 'Kirby\Cms\Field',

View File

@@ -32,7 +32,11 @@ return [
return $system->toArray(); return $system->toArray();
}, },
'breadcrumbTitle' => function () { 'breadcrumbTitle' => function () {
return $this->site()->blueprint()->title(); try {
return $this->site()->blueprint()->title();
} catch (Throwable $e) {
return $this->site()->title()->value();
}
}, },
'title' => function () { 'title' => function () {
return $this->site()->title()->value(); return $this->site()->title()->value();

View File

@@ -14,7 +14,7 @@ use Kirby\Toolkit\F;
use Kirby\Toolkit\Tpl as Snippet; use Kirby\Toolkit\Tpl as Snippet;
return [ return [
'file::version' => function (App $kirby, Model $file, array $options = []) { 'file::version' => function (App $kirby, $file, array $options = []) {
if ($file->isResizable() === false) { if ($file->isResizable() === false) {
return $file; return $file;
} }
@@ -24,8 +24,7 @@ return [
$attributes = $darkroom->preprocess($file->root(), $options); $attributes = $darkroom->preprocess($file->root(), $options);
// create url and root // create url and root
$parent = $file->parent(); $mediaRoot = dirname($file->mediaRoot());
$mediaRoot = $parent->mediaRoot() . '/' . $file->mediaHash();
$dst = $mediaRoot . '/{{ name }}{{ attributes }}.{{ extension }}'; $dst = $mediaRoot . '/{{ name }}{{ attributes }}.{{ extension }}';
$thumbRoot = (new Filename($file->root(), $dst, $attributes))->toString(); $thumbRoot = (new Filename($file->root(), $dst, $attributes))->toString();
$thumbName = basename($thumbRoot); $thumbName = basename($thumbRoot);
@@ -45,10 +44,10 @@ return [
'modifications' => $options, 'modifications' => $options,
'original' => $file, 'original' => $file,
'root' => $thumbRoot, 'root' => $thumbRoot,
'url' => $parent->mediaUrl() . '/' . $file->mediaHash() . '/' . $thumbName, 'url' => dirname($file->mediaUrl()) . '/' . $thumbName,
]); ]);
}, },
'file::url' => function (App $kirby, Model $file) { 'file::url' => function (App $kirby, $file) {
return $file->mediaUrl(); return $file->mediaUrl();
}, },
'markdown' => function (App $kirby, string $text = null, array $options = []): string { 'markdown' => function (App $kirby, string $text = null, array $options = []): string {

View File

@@ -3,6 +3,12 @@
return [ return [
'extends' => 'tags', 'extends' => 'tags',
'props' => [ 'props' => [
/**
* Unset inherited props
*/
'accept' => null,
/** /**
* Custom icon to replace the arrow down. * Custom icon to replace the arrow down.
*/ */

View File

@@ -36,10 +36,7 @@ return [
return null; return null;
} }
$value = str_replace(',', '.', $value); return (float)Str::float($value);
$value = floatval($value);
return $value;
} }
], ],
'validations' => [ 'validations' => [

View File

@@ -1,6 +1,7 @@
<?php <?php
use Kirby\Cms\App; use Kirby\Cms\App;
use Kirby\Cms\Asset;
use Kirby\Cms\Html; use Kirby\Cms\Html;
use Kirby\Cms\Response; use Kirby\Cms\Response;
use Kirby\Cms\Url; use Kirby\Cms\Url;
@@ -11,6 +12,17 @@ use Kirby\Toolkit\F;
use Kirby\Toolkit\I18n; use Kirby\Toolkit\I18n;
use Kirby\Toolkit\View; use Kirby\Toolkit\View;
/**
* Helper to create an asset object
*
* @param string $path
* @return Asset
*/
function asset(string $path)
{
return new Asset($path);
}
/** /**
* Generates a list of HTML attributes * Generates a list of HTML attributes
* *
@@ -425,6 +437,9 @@ function kirbytext(string $text = null, array $data = []): string
*/ */
function load(array $classmap, string $base = null) function load(array $classmap, string $base = null)
{ {
// convert all classnames to lowercase
$classmap = array_change_key_case($classmap);
spl_autoload_register(function ($class) use ($classmap, $base) { spl_autoload_register(function ($class) use ($classmap, $base) {
$class = strtolower($class); $class = strtolower($class);
@@ -640,15 +655,25 @@ function snippet(string $name, $data = [], bool $return = false)
*/ */
function svg(string $file) function svg(string $file)
{ {
$root = App::instance()->root(); $extension = F::extension($file);
$file = $root . '/' . $file;
if (file_exists($file) === false) { // check for valid svg files
if ($extension !== 'svg') {
return false; return false;
} }
// try to convert relative paths to absolute
if (file_exists($file) === false) {
$root = App::instance()->root();
$file = realpath($root . '/' . $file);
if (file_exists($file) === false) {
return false;
}
}
ob_start(); ob_start();
include F::realpath($file, $root); include $file;
$svg = ob_get_contents(); $svg = ob_get_contents();
ob_end_clean(); ob_end_clean();

View File

@@ -56,9 +56,6 @@ return [
'controllers' => function (array $roots) { 'controllers' => function (array $roots) {
return $roots['site'] . '/controllers'; return $roots['site'] . '/controllers';
}, },
'emails' => function (array $roots) {
return $roots['site'] . '/emails';
},
'languages' => function (array $roots) { 'languages' => function (array $roots) {
return $roots['site'] . '/languages'; return $roots['site'] . '/languages';
}, },

View File

@@ -94,6 +94,13 @@ return function ($kirby) {
'action' => function ($id, $hash, $filename) use ($kirby) { 'action' => function ($id, $hash, $filename) use ($kirby) {
return Media::link($kirby->user($id), $hash, $filename); return Media::link($kirby->user($id), $hash, $filename);
} }
],
[
'pattern' => 'media/assets/(:all)/(:any)/(:any)',
'env' => 'media',
'action' => function ($path, $hash, $filename) use ($kirby) {
return Media::thumb($path, $hash, $filename);
}
] ]
]; ];

View File

@@ -67,6 +67,12 @@ return [
return $status; return $status;
}, },
/**
* Filters the list by templates and sets template options when adding new pages to the section.
*/
'templates' => function ($templates = null) {
return A::wrap($templates ?? $this->template);
},
/** /**
* Setup for the main text in the list or cards. By default this will display the page title. * Setup for the main text in the list or cards. By default this will display the page title.
*/ */
@@ -78,9 +84,6 @@ return [
'dragTextType' => function () { 'dragTextType' => function () {
return option('panel.kirbytext', true) ? 'kirbytext' : 'markdown'; return option('panel.kirbytext', true) ? 'kirbytext' : 'markdown';
}, },
'templates' => function () {
return A::wrap($this->templates ?? $this->template);
},
'parent' => function () { 'parent' => function () {
return $this->parentModel(); return $this->parentModel();
}, },

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -422,6 +422,10 @@ class App
$id = dirname($path); $id = dirname($path);
$filename = basename($path); $filename = basename($path);
if (is_a($parent, File::class) === true) {
$parent = $parent->parent();
}
if ($id === '.') { if ($id === '.') {
if ($file = $parent->file($filename)) { if ($file = $parent->file($filename)) {
return $file; return $file;

View File

@@ -4,8 +4,115 @@ namespace Kirby\Cms;
use Kirby\Toolkit\Properties; use Kirby\Toolkit\Properties;
/**
* Anything in your public path can be converted
* to an Asset object to use the same handy file
* methods and thumbnail generation as for any other
* Kirby files. Pass a relative path to the Asset
* object to create the asset.
*/
class Asset class Asset
{ {
use FileFoundation; use FileFoundation;
use FileModifications;
use Properties; use Properties;
/**
* @var string
*/
protected $path;
/**
* Creates a new Asset object
* for the given path.
*/
public function __construct(string $path)
{
$this->setPath(dirname($path));
$this->setRoot($this->kirby()->root('index') . '/' . $path);
$this->setUrl($this->kirby()->url('index') . '/' . $path);
}
/**
* Returns the alternative text for the asset
*
* @return null
*/
public function alt()
{
return null;
}
/**
* Returns a unique id for the asset
*
* @return string
*/
public function id(): string
{
return $this->root();
}
/**
* Create a unique media hash
*
* @return string
*/
public function mediaHash(): string
{
return crc32($this->filename()) . '-' . $this->modified();
}
/**
* Returns the relative path starting at the media folder
*
* @return string
*/
public function mediaPath(): string
{
return 'assets/' . $this->path() . '/' . $this->mediaHash() . '/' . $this->filename();
}
/**
* Returns the absolute path to the file in the public media folder
*
* @return string
*/
public function mediaRoot(): string
{
return $this->kirby()->root('media') . '/' . $this->mediaPath();
}
/**
* Returns the absolute Url to the file in the public media folder
*
* @return string
*/
public function mediaUrl(): string
{
return $this->kirby()->url('media') . '/' . $this->mediaPath();
}
/**
* Returns the path of the file from the web root,
* excluding the filename
*
* @return string
*/
public function path(): string
{
return $this->path;
}
/**
* Setter for the path
*
* @param string $path
* @return self
*/
protected function setPath(string $path)
{
$this->path = $path === '.' ? '' : $path;
return $this;
}
} }

View File

@@ -69,8 +69,8 @@ class Auth
throw new InvalidArgumentException('Invalid authorization header'); throw new InvalidArgumentException('Invalid authorization header');
} }
// only allow basic auth when https is enabled // only allow basic auth when https is enabled or insecure requests permitted
if ($request->ssl() === false) { if ($request->ssl() === false && $this->kirby->option('api.allowInsecure', false) !== true) {
throw new PermissionException('Basic authentication is only allowed over HTTPS'); throw new PermissionException('Basic authentication is only allowed over HTTPS');
} }

View File

@@ -376,6 +376,10 @@ class Blueprint
protected function normalizeColumns(string $tabName, array $columns): array protected function normalizeColumns(string $tabName, array $columns): array
{ {
foreach ($columns as $columnKey => $columnProps) { foreach ($columns as $columnKey => $columnProps) {
if (is_array($columnProps) === false) {
continue;
}
$columnProps = $this->convertFieldsToSections($tabName . '-col-' . $columnKey, $columnProps); $columnProps = $this->convertFieldsToSections($tabName . '-col-' . $columnKey, $columnProps);
// inject getting started info, if the sections are empty // inject getting started info, if the sections are empty

View File

@@ -73,7 +73,7 @@ class Collection extends BaseCollection
*/ */
public function __set(string $id, $object) public function __set(string $id, $object)
{ {
$this->data[$object->id()] = $object; $this->data[$id] = $object;
} }
/** /**
@@ -81,14 +81,16 @@ class Collection extends BaseCollection
* an entire second collection to the * an entire second collection to the
* current collection * current collection
* *
* @param mixed $item * @param mixed $object
*/ */
public function add($object) public function add($object)
{ {
if (is_a($object, static::class) === true) { if (is_a($object, static::class) === true) {
$this->data = array_merge($this->data, $object->data); $this->data = array_merge($this->data, $object->data);
} else { } elseif (method_exists($object, 'id') === true) {
$this->__set($object->id(), $object); $this->__set($object->id(), $object);
} else {
$this->append($object);
} }
return $this; return $this;

View File

@@ -165,6 +165,15 @@ class Field
return $this->key; return $this->key;
} }
/**
* @see Field::parent()
* @return Page|File|Site|User
*/
public function model()
{
return $this->parent;
}
/** /**
* Provides a fallback if the field value is empty * Provides a fallback if the field value is empty
* *

View File

@@ -29,6 +29,7 @@ class File extends ModelWithContent
use FileActions; use FileActions;
use FileFoundation; use FileFoundation;
use FileModifications;
use HasMethods; use HasMethods;
use HasSiblings; use HasSiblings;
@@ -179,27 +180,6 @@ class File extends ModelWithContent
return $this->blueprint = FileBlueprint::factory('files/' . $this->template(), 'files/default', $this); return $this->blueprint = FileBlueprint::factory('files/' . $this->template(), 'files/default', $this);
} }
/**
* Blurs the image by the given amount of pixels
*
* @param boolean $pixels
* @return self
*/
public function blur($pixels = true)
{
return $this->thumb(['blur' => $pixels]);
}
/**
* Converts the image to black and white
*
* @return self
*/
public function bw()
{
return $this->thumb(['grayscale' => true]);
}
/** /**
* Store the template in addition to the * Store the template in addition to the
* other content. * other content.
@@ -236,38 +216,6 @@ class File extends ModelWithContent
return $this->filename(); return $this->filename();
} }
/**
* Crops the image by the given width and height
*
* @param integer $width
* @param integer $height
* @param string|array $options
* @return self
*/
public function crop(int $width, int $height = null, $options = null)
{
$quality = null;
$crop = 'center';
if (is_int($options) === true) {
$quality = $options;
} elseif (is_string($options)) {
$crop = $options;
} elseif (is_a($options, 'Kirby\Cms\Field') === true) {
$crop = $options->value();
} elseif (is_array($options)) {
$quality = $options['quality'] ?? $quality;
$crop = $options['crop'] ?? $crop;
}
return $this->thumb([
'width' => $width,
'height' => $height,
'quality' => $quality,
'crop' => $crop
]);
}
/** /**
* Provides a kirbytag or markdown * Provides a kirbytag or markdown
* tag for the file, which will be * tag for the file, which will be
@@ -295,16 +243,6 @@ class File extends ModelWithContent
} }
} }
/**
* Checks if the file exists on disk
*
* @return boolean
*/
public function exists(): bool
{
return is_file($this->root()) === true;
}
/** /**
* Returns the filename with extension * Returns the filename with extension
* *
@@ -325,21 +263,6 @@ class File extends ModelWithContent
return $this->siblingsCollection(); return $this->siblingsCollection();
} }
/**
* Converts the file to html
*
* @param array $attr
* @return string
*/
public function html(array $attr = []): string
{
if ($this->type() === 'image') {
return Html::img($this->url(), array_merge(['alt' => $this->alt()], $attr));
} else {
return Html::a($this->url(), $attr);
}
}
/** /**
* Returns the id * Returns the id
* *
@@ -425,18 +348,6 @@ class File extends ModelWithContent
return $this->parent(); return $this->parent();
} }
/**
* Get the file's last modification time.
*
* @param string $format
* @param string|null $handler date or strftime
* @return mixed
*/
public function modified(string $format = null, string $handler = null)
{
return F::modified($this->root(), $format, $handler ?? $this->kirby()->option('date.handler', 'date'));
}
/** /**
* Returns the parent Page object * Returns the parent Page object
* *
@@ -607,17 +518,6 @@ class File extends ModelWithContent
return new FilePermissions($this); return new FilePermissions($this);
} }
/**
* Sets the JPEG compression quality
*
* @param integer $quality
* @return self
*/
public function quality(int $quality)
{
return $this->thumb(['quality' => $quality]);
}
/** /**
* Creates a string query, starting from the model * Creates a string query, starting from the model
* *
@@ -644,24 +544,6 @@ class File extends ModelWithContent
return $result; return $result;
} }
/**
* Resizes the file with the given width and height
* while keeping the aspect ratio.
*
* @param integer $width
* @param integer $height
* @param integer $quality
* @return self
*/
public function resize(int $width = null, int $height = null, int $quality = null)
{
return $this->thumb([
'width' => $width,
'height' => $height,
'quality' => $quality
]);
}
/** /**
* Returns the absolute root to the file * Returns the absolute root to the file
* *
@@ -799,33 +681,6 @@ class File extends ModelWithContent
return $this->siblings($self)->filterBy('template', $this->template()); return $this->siblings($self)->filterBy('template', $this->template());
} }
/**
* Creates a modified version of images
* 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
* could potentially also be a CDN or any other
* place.
*
* @param array|null $options
* @return FileVersion|File
*/
public function thumb(array $options = null)
{
if (empty($options) === true) {
return $this;
}
$result = $this->kirby()->component('file::version')($this->kirby(), $this, $options);
if (is_a($result, FileVersion::class) === false && is_a($result, File::class) === false) {
throw new InvalidArgumentException('The file::version component must return a File or FileVersion object');
}
return $result;
}
/** /**
* Extended info for the array export * Extended info for the array export
* by injecting the information from * by injecting the information from

View File

@@ -157,6 +157,18 @@ trait FileFoundation
return App::instance(); return App::instance();
} }
/**
* Get the file's last modification time.
*
* @param string $format
* @param string|null $handler date or strftime
* @return mixed
*/
public function modified(string $format = null, string $handler = null)
{
return F::modified($this->root(), $format, $handler ?? $this->kirby()->option('date.handler', 'date'));
}
/** /**
* Returns the absolute path to the file root * Returns the absolute path to the file root
* *

View File

@@ -0,0 +1,119 @@
<?php
namespace Kirby\Cms;
/**
* Resizing, blurring etc
*/
trait FileModifications
{
/**
* Blurs the image by the given amount of pixels
*
* @param boolean $pixels
* @return self
*/
public function blur($pixels = true)
{
return $this->thumb(['blur' => $pixels]);
}
/**
* Converts the image to black and white
*
* @return self
*/
public function bw()
{
return $this->thumb(['grayscale' => true]);
}
/**
* Crops the image by the given width and height
*
* @param integer $width
* @param integer $height
* @param string|array $options
* @return self
*/
public function crop(int $width, int $height = null, $options = null)
{
$quality = null;
$crop = 'center';
if (is_int($options) === true) {
$quality = $options;
} elseif (is_string($options)) {
$crop = $options;
} elseif (is_a($options, 'Kirby\Cms\Field') === true) {
$crop = $options->value();
} elseif (is_array($options)) {
$quality = $options['quality'] ?? $quality;
$crop = $options['crop'] ?? $crop;
}
return $this->thumb([
'width' => $width,
'height' => $height,
'quality' => $quality,
'crop' => $crop
]);
}
/**
* Sets the JPEG compression quality
*
* @param integer $quality
* @return self
*/
public function quality(int $quality)
{
return $this->thumb(['quality' => $quality]);
}
/**
* Resizes the file with the given width and height
* while keeping the aspect ratio.
*
* @param integer $width
* @param integer $height
* @param integer $quality
* @return self
*/
public function resize(int $width = null, int $height = null, int $quality = null)
{
return $this->thumb([
'width' => $width,
'height' => $height,
'quality' => $quality
]);
}
/**
* Creates a modified version of images
* 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
* could potentially also be a CDN or any other
* place.
*
* @param array|null $options
* @return FileVersion|File
*/
public function thumb(array $options = null)
{
if (empty($options) === true) {
return $this;
}
$result = $this->kirby()->component('file::version')($this->kirby(), $this, $options);
if (is_a($result, FileVersion::class) === false && is_a($result, File::class) === false) {
throw new InvalidArgumentException('The file::version component must return a File or FileVersion object');
}
return $result;
}
}

View File

@@ -25,7 +25,7 @@ class FileRules
} }
$parent = $file->parent(); $parent = $file->parent();
$duplicate = $parent->files()->not($file)->findBy('name', $name); $duplicate = $parent->files()->not($file)->findBy('filename', $name . '.' . $file->extension());
if ($duplicate) { if ($duplicate) {
throw new DuplicateException([ throw new DuplicateException([

View File

@@ -2,8 +2,13 @@
namespace Kirby\Cms; namespace Kirby\Cms;
class FileVersion extends Asset use Kirby\Toolkit\Properties;
class FileVersion
{ {
use FileFoundation;
use Properties;
protected $modifications; protected $modifications;
protected $original; protected $original;
@@ -23,8 +28,10 @@ class FileVersion extends Asset
return $this->asset()->$method(...$arguments); return $this->asset()->$method(...$arguments);
} }
// content fields if (is_a($this->original(), File::class) === true) {
return $this->original()->content()->get($method, $arguments); // content fields
return $this->original()->content()->get($method, $arguments);
}
} }
public function id(): string public function id(): string
@@ -42,7 +49,7 @@ class FileVersion extends Asset
return $this->modifications ?? []; return $this->modifications ?? [];
} }
public function original(): File public function original()
{ {
return $this->original; return $this->original;
} }
@@ -58,7 +65,7 @@ class FileVersion extends Asset
$this->modifications = $modifications; $this->modifications = $modifications;
} }
protected function setOriginal(File $original) protected function setOriginal($original)
{ {
$this->original = $original; $this->original = $original;
} }

View File

@@ -41,9 +41,17 @@ class Form extends BaseForm
{ {
// get the original model data // get the original model data
$original = $model->content()->toArray(); $original = $model->content()->toArray();
$values = $props['values'] ?? [];
// convert closures to values
foreach ($values as $key => $value) {
if (is_a($value, 'Closure') === true) {
$values[$key] = $value($original[$key] ?? null);
}
}
// set a few defaults // set a few defaults
$props['values'] = array_merge($original, $props['values'] ?? []); $props['values'] = array_merge($original, $values);
$props['fields'] = $props['fields'] ?? []; $props['fields'] = $props['fields'] ?? [];
$props['model'] = $model; $props['model'] = $model;

View File

@@ -25,22 +25,34 @@ class Media
* @param string $filename * @param string $filename
* @return Response|false * @return Response|false
*/ */
public static function thumb(Model $model, string $hash, string $filename) 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 { try {
$kirby = $model->kirby();
$url = $model->mediaUrl() . '/' . $hash . '/' . $filename;
$root = $model->mediaRoot() . '/' . $hash;
$thumb = $root . '/' . $filename; $thumb = $root . '/' . $filename;
$job = $root . '/.jobs/' . $filename . '.json'; $job = $root . '/.jobs/' . $filename . '.json';
$options = Data::read($job); $options = Data::read($job);
$file = $model->file($options['filename']);
if (!$file || empty($options) === true) { if (empty($options) === true) {
return false; return false;
} }
$kirby->thumb($file->root(), $thumb, $options); 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); F::remove($job);

View File

@@ -608,10 +608,19 @@ class Page extends ModelWithContent
/** /**
* Checks if the page is a descendant of the given page * Checks if the page is a descendant of the given page
* *
* @param string|Page $parent
* @return boolean * @return boolean
*/ */
public function isDescendantOf(Page $parent): bool public function isDescendantOf($parent): bool
{ {
if (is_string($parent) === true) {
$parent = $this->site()->find($parent);
}
if (!$parent) {
return false;
}
return $this->parents()->has($parent->id()) === true; return $this->parents()->has($parent->id()) === true;
} }
@@ -828,7 +837,7 @@ class Page extends ModelWithContent
* @param string|null $handler * @param string|null $handler
* @return int|string * @return int|string
*/ */
public function modified(string $format = 'U', string $handler = null) public function modified(string $format = null, string $handler = null)
{ {
return F::modified($this->contentFile(), $format, $handler ?? $this->kirby()->option('date.handler', 'date')); return F::modified($this->contentFile(), $format, $handler ?? $this->kirby()->option('date.handler', 'date'));
} }

View File

@@ -380,7 +380,7 @@ trait PageActions
return 0; return 0;
case 'date': case 'date':
case 'datetime': case 'datetime':
$format = 'date' ? 'Ymd' : 'YmdHi'; $format = $mode === 'date' ? 'Ymd' : 'YmdHi';
$date = $this->content()->get('date')->value(); $date = $this->content()->get('date')->value();
$time = empty($date) === true ? time() : strtotime($date); $time = empty($date) === true ? time() : strtotime($date);

View File

@@ -50,6 +50,9 @@ class Txt extends Handler
// avoid problems with arrays // avoid problems with arrays
if (is_array($value) === true) { if (is_array($value) === true) {
$value = Yaml::encode($value); $value = Yaml::encode($value);
// avoid problems with localized floats
} elseif (is_float($value) === true) {
$value = Str::float($value);
} }
// escape accidental dividers within a field // escape accidental dividers within a field

View File

@@ -25,8 +25,19 @@ class Yaml extends Handler
*/ */
public static function encode(array $data): string public static function encode(array $data): string
{ {
// fetch the current locale setting for numbers
$locale = setlocale(LC_NUMERIC, 0);
// change to english numerics to avoid issues with floats
setlocale(LC_NUMERIC, 'en_US');
// $data, $indent, $wordwrap, $no_opening_dashes // $data, $indent, $wordwrap, $no_opening_dashes
return Spyc::YAMLDump($data, false, false, true); $yaml = Spyc::YAMLDump($data, false, false, true);
// restore the previous locale settings
setlocale(LC_NUMERIC, $locale);
return $yaml;
} }
/** /**

View File

@@ -147,7 +147,7 @@ class Form
} elseif (is_array($value) === true) { } elseif (is_array($value) === true) {
$strings[$key] = Yaml::encode($value); $strings[$key] = Yaml::encode($value);
} else { } else {
$strings[$key] = (string)$value; $strings[$key] = $value;
} }
} }

View File

@@ -118,7 +118,9 @@ class Html
if (isset($value['value']) && isset($value['escape'])) { if (isset($value['value']) && isset($value['escape'])) {
$value = $value['escape'] === true ? htmlspecialchars($value['value'], ENT_QUOTES, 'UTF-8') : $value['value']; $value = $value['escape'] === true ? htmlspecialchars($value['value'], ENT_QUOTES, 'UTF-8') : $value['value'];
} else { } else {
$value = implode(' ', $value); $value = implode(' ', array_filter($value, function ($value) {
return !empty($value) || is_numeric($value);
}));
} }
} else { } else {
$value = htmlspecialchars($value, ENT_QUOTES, 'UTF-8'); $value = htmlspecialchars($value, ENT_QUOTES, 'UTF-8');

View File

@@ -336,6 +336,20 @@ class Str
return static::substr($string, 0, strrpos(static::substr($string, 0, $chars), ' ')) . ' ' . $rep; return static::substr($string, 0, strrpos(static::substr($string, 0, $chars), ' ')) . ' ' . $rep;
} }
/**
* Convert the value to a float with a decimal
* point, no matter what the locale setting is
*
* @param string|int|float $value
* @return string
*/
public static function float($value): string
{
$value = str_replace(',', '.', $value);
$decimal = strlen(substr(strrchr($value, "."), 1));
return number_format((float)$value, $decimal);
}
/** /**
* Returns the rest of the string starting from the given character * Returns the rest of the string starting from the given character
* *

View File

@@ -5,7 +5,7 @@
"cancel": "Peruuta", "cancel": "Peruuta",
"change": "Muuta", "change": "Muuta",
"close": "Sulje", "close": "Sulje",
"confirm": "Tallenna", "confirm": "Ok",
"copy": "Kopioi", "copy": "Kopioi",
"create": "Luo", "create": "Luo",
@@ -29,7 +29,7 @@
"email": "S\u00e4hk\u00f6posti", "email": "S\u00e4hk\u00f6posti",
"email.placeholder": "nimi@osoite.fi", "email.placeholder": "nimi@osoite.fi",
"error.access.login": "Invalid login", "error.access.login": "Kirjautumistiedot eivät kelpaa",
"error.access.panel": "Sinulla ei ole oikeutta käyttää paneelia", "error.access.panel": "Sinulla ei ole oikeutta käyttää paneelia",
"error.avatar.create.fail": "Profiilikuvaa ei voitu lähettää", "error.avatar.create.fail": "Profiilikuvaa ei voitu lähettää",
@@ -41,7 +41,7 @@
"error.blueprint.notFound": "Kaavaa \"{name}\" ei voitu ladata", "error.blueprint.notFound": "Kaavaa \"{name}\" ei voitu ladata",
"error.email.preset.notFound": "The email preset \"{name}\" cannot be found", "error.email.preset.notFound": "Nimellä \"{name}\" ja kyseisellä verkkotunnuksella ei löydy sähköpostiosoitetta",
"error.field.converter.invalid": "Muunnin \"{converter}\" ei kelpaa", "error.field.converter.invalid": "Muunnin \"{converter}\" ei kelpaa",
@@ -158,17 +158,17 @@
"error.user.update.permission": "error.user.update.permission":
"Sinulla ei ole oikeutta päivittää käyttäjää \"{name}\"", "Sinulla ei ole oikeutta päivittää käyttäjää \"{name}\"",
"error.validation.accepted": "Please confirm", "error.validation.accepted": "Ole hyvä ja vahvista",
"error.validation.alpha": "Anna vain merkkejä väliltä a-z", "error.validation.alpha": "Anna vain merkkejä väliltä a-z",
"error.validation.alphanum": "error.validation.alphanum":
"Anna vain merkkejä väliltä a-z tai/ja numeroita väliltä 0-9", "Anna vain merkkejä väliltä a-z tai/ja numeroita väliltä 0-9",
"error.validation.between": "error.validation.between":
"Anna arvo väliltä \"{min}\" ja \"{max}\"", "Anna arvo väliltä \"{min}\" ja \"{max}\"",
"error.validation.boolean": "Please confirm or deny", "error.validation.boolean": "Vahvista tai peruuta",
"error.validation.contains": "error.validation.contains":
"Anna arvo joka sisältää \"{needle}\"", "Anna arvo joka sisältää \"{needle}\"",
"error.validation.date": "Anna kelpaava päivämäärä", "error.validation.date": "Anna kelpaava päivämäärä",
"error.validation.denied": "Please deny", "error.validation.denied": "Ole hyvä ja peruuta",
"error.validation.different": "Arvo ei voi olla \"{other}\"", "error.validation.different": "Arvo ei voi olla \"{other}\"",
"error.validation.email": "Anna kelpaava sähköpostiosoite", "error.validation.email": "Anna kelpaava sähköpostiosoite",
"error.validation.endswith": "Arvon loppuosa täytyy olla \"{end}\"", "error.validation.endswith": "Arvon loppuosa täytyy olla \"{end}\"",
@@ -203,7 +203,7 @@
"field.files.empty": "Tiedostoja ei ole vielä valittu", "field.files.empty": "Tiedostoja ei ole vielä valittu",
"field.pages.empty": " Sivuja ei ole vielä valittu", "field.pages.empty": " Sivuja ei ole vielä valittu",
"field.structure.delete.confirm": "Haluatko varmasti poistaa tämän rivin?", "field.structure.delete.confirm": "Haluatko varmasti poistaa tämän rivin?",
"field.structure.empty": "Kirjoituksia ei ole vielä lisätty", "field.structure.empty": "Rivejä ei ole vielä lisätty",
"field.users.empty": "Käyttäjiä ei ole vielä valittu", "field.users.empty": "Käyttäjiä ei ole vielä valittu",
"file.delete.confirm": "file.delete.confirm":
@@ -371,7 +371,7 @@
"translation.author": "Kirby-tiimi", "translation.author": "Kirby-tiimi",
"translation.direction": "ltr", "translation.direction": "ltr",
"translation.name": "Englanti", "translation.name": "Suomi",
"upload": "Lähetä", "upload": "Lähetä",
"upload.errors": "Virhe", "upload.errors": "Virhe",

View File

@@ -218,21 +218,21 @@
"installation": "Installazione", "installation": "Installazione",
"installation.completed": "Il pannello è stato installato", "installation.completed": "Il pannello è stato installato",
"installation.disabled": "The panel installer is disabled on public servers by default. Please run the installer on a local machine or enable it with the <code>panel.install</code> option.", "installation.disabled": "L'installazione del pannello è disabilitata di default sui server pubblici. Esegui l'installazione in locale oppure abilitala usando l'opzione <code>panel.install</code>.",
"installation.issues.accounts": "installation.issues.accounts":
"\/site\/accounts non dispone dei permessi di scrittura", "<code>/site/accounts</code> non esiste o non dispone dei permessi di scrittura",
"installation.issues.content": "installation.issues.content":
"La cartella \/content e tutti i file e le cartelle in essa contenuti devono disporre dei permessi di scrittura.", "La cartella <code>/content</code> non esiste o non dispone dei permessi di scrittura",
"installation.issues.curl": "È necessaria l'estensione <code>CURL</code>", "installation.issues.curl": "È necessaria l'estensione <code>CURL</code>",
"installation.issues.headline": "Il pannello non può esser installato", "installation.issues.headline": "Il pannello non può esser installato",
"installation.issues.mbstring": "installation.issues.mbstring":
"È necessaria l'estensione <code>MB String</code>", "È necessaria l'estensione <code>MB String</code>",
"installation.issues.media": "installation.issues.media":
"La cartella <code>/media</code> non esiste o non è scrivibile", "La cartella <code>/media</code> non esiste o non dispone dei permessi di scrittura",
"installation.issues.php": "Assicurati di utilizzare <code>PHP 7.1+</code>", "installation.issues.php": "Assicurati di utilizzare <code>PHP 7.1+</code>",
"installation.issues.server": "installation.issues.server":
"Kirby necessita di <code>Apache</code>, <code>Nginx</code> o <code>Caddy</code>", "Kirby necessita di <code>Apache</code>, <code>Nginx</code> o <code>Caddy</code>",
"installation.issues.sessions": "The <code>/site/sessions</code> folder does not exist or is not writable", "installation.issues.sessions": "La cartella <code>/site/sessions</code>non esiste o non dispone dei permessi di scrittura",
"language": "Lingua", "language": "Lingua",
"language.code": "Codice", "language.code": "Codice",

View File

@@ -207,7 +207,7 @@
"field.users.empty": "Nog geen gebruikers geselecteerd", "field.users.empty": "Nog geen gebruikers geselecteerd",
"file.delete.confirm": "file.delete.confirm":
"Wil je dit bestand verwijderen?", "Wil je dit bestand <br><strong>{filename}</strong> verwijderen?",
"files": "Bestanden", "files": "Bestanden",
"files.empty": "Nog geen bestanden", "files.empty": "Nog geen bestanden",
@@ -218,11 +218,11 @@
"installation": "Installatie", "installation": "Installatie",
"installation.completed": "Het Panel is geïnstalleerd", "installation.completed": "Het Panel is geïnstalleerd",
"installation.disabled": "The panel installer is disabled on public servers by default. Please run the installer on a local machine or enable it with the <code>panel.install</code> option.", "installation.disabled": "Je kan geen Panel installatie uitvoeren op een openbare server. Voer het installatieprogramma uit op een lokale computer of schakel het in met de <code>panel.install</code> optie.",
"installation.issues.accounts": "installation.issues.accounts":
"De map <code>/site/accounts</code> heeft geen schrijfrechten", "De map <code>/site/accounts</code> heeft geen schrijfrechten",
"installation.issues.content": "installation.issues.content":
"De contentmap en alle bestanden hierin moeten schrijfrechten hebben.", "De map <code>/content</code> bestaat niet of heeft geen schrijfrechten",
"installation.issues.curl": "De <code>CURL</code>-extensie is vereist", "installation.issues.curl": "De <code>CURL</code>-extensie is vereist",
"installation.issues.headline": "Het Panel kan niet worden geïnstalleerd", "installation.issues.headline": "Het Panel kan niet worden geïnstalleerd",
"installation.issues.mbstring": "installation.issues.mbstring":
@@ -241,7 +241,7 @@
"<p>Weet je zeker dat je <strong>{name}</strong>wilt aanpassen naar de standaard taal? Dit kan niet ongedaan worden gemaakt</p><p>Als <strong>{name}</strong> nog niet vertaalde content heeft, is er geen content meer om op terug te vallen en zouden delen van je site leeg kunnen zijn.</p>", "<p>Weet je zeker dat je <strong>{name}</strong>wilt aanpassen naar de standaard taal? Dit kan niet ongedaan worden gemaakt</p><p>Als <strong>{name}</strong> nog niet vertaalde content heeft, is er geen content meer om op terug te vallen en zouden delen van je site leeg kunnen zijn.</p>",
"language.create": "Nieuwe taal toevoegen", "language.create": "Nieuwe taal toevoegen",
"language.delete.confirm": "language.delete.confirm":
"Weet je zeker dat je de taal {name} -inclusief alle vertalingen- wilt verwijderen? Je kunt dit niet ongedaan maken!", "Weet je zeker dat je de taal <strong>{name}</strong> inclusief alle vertalingen wilt verwijderen? Je kunt dit niet ongedaan maken!",
"language.deleted": "De taal is verwijderd", "language.deleted": "De taal is verwijderd",
"language.direction": "Leesrichting", "language.direction": "Leesrichting",
"language.direction.ltr": "Links naar rechts", "language.direction.ltr": "Links naar rechts",
@@ -256,7 +256,7 @@
"languages.secondary": "Andere talen", "languages.secondary": "Andere talen",
"languages.secondary.empty": "Er zijn nog geen andere talen beschikbaar", "languages.secondary.empty": "Er zijn nog geen andere talen beschikbaar",
"license": "Kirby-licentie", "license": "Licentie",
"license.buy": "Koop een licentie", "license.buy": "Koop een licentie",
"license.register": "Registreren", "license.register": "Registreren",
"license.register.help": "license.register.help":
@@ -371,7 +371,7 @@
"translation.author": "Het team van Kirby", "translation.author": "Het team van Kirby",
"translation.direction": "ltr", "translation.direction": "ltr",
"translation.name": "Engels", "translation.name": "Nederlands",
"upload": "Upload", "upload": "Upload",
"upload.errors": "Foutmelding", "upload.errors": "Foutmelding",

View File

@@ -97,8 +97,10 @@ return array(
'Kirby\\Cms\\UserRules' => $baseDir . '/src/Cms/UserRules.php', 'Kirby\\Cms\\UserRules' => $baseDir . '/src/Cms/UserRules.php',
'Kirby\\Cms\\Users' => $baseDir . '/src/Cms/Users.php', 'Kirby\\Cms\\Users' => $baseDir . '/src/Cms/Users.php',
'Kirby\\Cms\\Visitor' => $baseDir . '/src/Cms/Visitor.php', 'Kirby\\Cms\\Visitor' => $baseDir . '/src/Cms/Visitor.php',
'Kirby\\ComposerInstaller\\Installer' => $vendorDir . '/getkirby/composer-installer/src/Installer.php', 'Kirby\\ComposerInstaller\\CmsInstaller' => $vendorDir . '/getkirby/composer-installer/src/ComposerInstaller/CmsInstaller.php',
'Kirby\\ComposerInstaller\\Plugin' => $vendorDir . '/getkirby/composer-installer/src/Plugin.php', 'Kirby\\ComposerInstaller\\Installer' => $vendorDir . '/getkirby/composer-installer/src/ComposerInstaller/Installer.php',
'Kirby\\ComposerInstaller\\Plugin' => $vendorDir . '/getkirby/composer-installer/src/ComposerInstaller/Plugin.php',
'Kirby\\ComposerInstaller\\PluginInstaller' => $vendorDir . '/getkirby/composer-installer/src/ComposerInstaller/PluginInstaller.php',
'Kirby\\Data\\Data' => $baseDir . '/src/Data/Data.php', 'Kirby\\Data\\Data' => $baseDir . '/src/Data/Data.php',
'Kirby\\Data\\Handler' => $baseDir . '/src/Data/Handler.php', 'Kirby\\Data\\Handler' => $baseDir . '/src/Data/Handler.php',
'Kirby\\Data\\Json' => $baseDir . '/src/Data/Json.php', 'Kirby\\Data\\Json' => $baseDir . '/src/Data/Json.php',

View File

@@ -12,7 +12,6 @@ return array(
'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'), 'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'),
'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'), 'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'),
'PHPMailer\\PHPMailer\\' => array($vendorDir . '/phpmailer/phpmailer/src'), 'PHPMailer\\PHPMailer\\' => array($vendorDir . '/phpmailer/phpmailer/src'),
'Kirby\\ComposerInstaller\\' => array($vendorDir . '/getkirby/composer-installer/src'), 'Kirby\\' => array($baseDir . '/src', $vendorDir . '/getkirby/composer-installer/src'),
'Kirby\\' => array($baseDir . '/src'),
'' => array($vendorDir . '/league/color-extractor/src'), '' => array($vendorDir . '/league/color-extractor/src'),
); );

View File

@@ -38,7 +38,6 @@ class ComposerStaticInit12091bebabd81c9aba88b2aeec22c8d7
), ),
'K' => 'K' =>
array ( array (
'Kirby\\ComposerInstaller\\' => 24,
'Kirby\\' => 6, 'Kirby\\' => 6,
), ),
); );
@@ -68,13 +67,10 @@ class ComposerStaticInit12091bebabd81c9aba88b2aeec22c8d7
array ( array (
0 => __DIR__ . '/..' . '/phpmailer/phpmailer/src', 0 => __DIR__ . '/..' . '/phpmailer/phpmailer/src',
), ),
'Kirby\\ComposerInstaller\\' =>
array (
0 => __DIR__ . '/..' . '/getkirby/composer-installer/src',
),
'Kirby\\' => 'Kirby\\' =>
array ( array (
0 => __DIR__ . '/../..' . '/src', 0 => __DIR__ . '/../..' . '/src',
1 => __DIR__ . '/..' . '/getkirby/composer-installer/src',
), ),
); );
@@ -191,8 +187,10 @@ class ComposerStaticInit12091bebabd81c9aba88b2aeec22c8d7
'Kirby\\Cms\\UserRules' => __DIR__ . '/../..' . '/src/Cms/UserRules.php', 'Kirby\\Cms\\UserRules' => __DIR__ . '/../..' . '/src/Cms/UserRules.php',
'Kirby\\Cms\\Users' => __DIR__ . '/../..' . '/src/Cms/Users.php', 'Kirby\\Cms\\Users' => __DIR__ . '/../..' . '/src/Cms/Users.php',
'Kirby\\Cms\\Visitor' => __DIR__ . '/../..' . '/src/Cms/Visitor.php', 'Kirby\\Cms\\Visitor' => __DIR__ . '/../..' . '/src/Cms/Visitor.php',
'Kirby\\ComposerInstaller\\Installer' => __DIR__ . '/..' . '/getkirby/composer-installer/src/Installer.php', 'Kirby\\ComposerInstaller\\CmsInstaller' => __DIR__ . '/..' . '/getkirby/composer-installer/src/ComposerInstaller/CmsInstaller.php',
'Kirby\\ComposerInstaller\\Plugin' => __DIR__ . '/..' . '/getkirby/composer-installer/src/Plugin.php', 'Kirby\\ComposerInstaller\\Installer' => __DIR__ . '/..' . '/getkirby/composer-installer/src/ComposerInstaller/Installer.php',
'Kirby\\ComposerInstaller\\Plugin' => __DIR__ . '/..' . '/getkirby/composer-installer/src/ComposerInstaller/Plugin.php',
'Kirby\\ComposerInstaller\\PluginInstaller' => __DIR__ . '/..' . '/getkirby/composer-installer/src/ComposerInstaller/PluginInstaller.php',
'Kirby\\Data\\Data' => __DIR__ . '/../..' . '/src/Data/Data.php', 'Kirby\\Data\\Data' => __DIR__ . '/../..' . '/src/Data/Data.php',
'Kirby\\Data\\Handler' => __DIR__ . '/../..' . '/src/Data/Handler.php', 'Kirby\\Data\\Handler' => __DIR__ . '/../..' . '/src/Data/Handler.php',
'Kirby\\Data\\Json' => __DIR__ . '/../..' . '/src/Data/Json.php', 'Kirby\\Data\\Json' => __DIR__ . '/../..' . '/src/Data/Json.php',

View File

@@ -4,7 +4,6 @@ namespace Kirby\ComposerInstaller;
use InvalidArgumentException; use InvalidArgumentException;
use Composer\Config; use Composer\Config;
use Composer\Installer\LibraryInstaller;
use Composer\Package\PackageInterface; use Composer\Package\PackageInterface;
/** /**
@@ -14,7 +13,7 @@ use Composer\Package\PackageInterface;
* @copyright Bastian Allgeier * @copyright Bastian Allgeier
* @license MIT * @license MIT
*/ */
class Installer extends LibraryInstaller class CmsInstaller extends Installer
{ {
/** /**
* Decides if the installer supports the given type * Decides if the installer supports the given type

View File

@@ -0,0 +1,80 @@
<?php
namespace Kirby\ComposerInstaller;
use RuntimeException;
use Composer\Installer\LibraryInstaller;
use Composer\Package\PackageInterface;
use Composer\Repository\InstalledRepositoryInterface;
/**
* @package Kirby Composer Installer
* @author Lukas Bestle <lukas@getkirby.com>
* @link https://getkirby.com
* @copyright Bastian Allgeier
* @license MIT
*/
class Installer extends LibraryInstaller
{
/**
* Decides if the installer supports the given type
*
* @param string $packageType
* @return bool
*/
public function supports($packageType): bool
{
throw new RuntimeException('This method needs to be overridden.'); // @codeCoverageIgnore
}
/**
* Installs specific package.
*
* @param InstalledRepositoryInterface $repo repository in which to check
* @param PackageInterface $package package instance
*/
public function install(InstalledRepositoryInterface $repo, PackageInterface $package)
{
// first install the package normally...
parent::install($repo, $package);
// ...then run custom code
$this->postInstall($package);
}
/**
* Updates specific package.
*
* @param InstalledRepositoryInterface $repo repository in which to check
* @param PackageInterface $initial already installed package version
* @param PackageInterface $target updated version
*
* @throws InvalidArgumentException if $initial package is not installed
*/
public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target)
{
// first update the package normally...
parent::update($repo, $initial, $target);
// ...then run custom code
$this->postInstall($target);
}
/**
* Custom handler that will be called after each package
* installation or update
*
* @param PackageInterface $package
*/
protected function postInstall(PackageInterface $package)
{
// remove the package's `vendor` directory to avoid duplicated autoloader and vendor code
$packageVendorDir = $this->getInstallPath($package) . '/vendor';
if (is_dir($packageVendorDir)) {
$success = $this->filesystem->removeDirectory($packageVendorDir);
if (!$success) {
throw new RuntimeException('Could not completely delete ' . $path . ', aborting.'); // @codeCoverageIgnore
}
}
}
}

View File

@@ -23,7 +23,8 @@ class Plugin implements PluginInterface
*/ */
public function activate(Composer $composer, IOInterface $io) public function activate(Composer $composer, IOInterface $io)
{ {
$installer = new Installer($io, $composer); $installationManager = $composer->getInstallationManager();
$composer->getInstallationManager()->addInstaller($installer); $installationManager->addInstaller(new CmsInstaller($io, $composer));
$installationManager->addInstaller(new PluginInstaller($io, $composer));
} }
} }

View File

@@ -0,0 +1,102 @@
<?php
namespace Kirby\ComposerInstaller;
use Composer\Package\PackageInterface;
/**
* @package Kirby Composer Installer
* @author Lukas Bestle <lukas@getkirby.com>
* @link https://getkirby.com
* @copyright Bastian Allgeier
* @license MIT
*/
class PluginInstaller extends Installer
{
/**
* Decides if the installer supports the given type
*
* @param string $packageType
* @return bool
*/
public function supports($packageType): bool
{
return $packageType === 'kirby-plugin';
}
/**
* Returns the installation path of a package
*
* @param PackageInterface $package
* @return string path
*/
public function getInstallPath(PackageInterface $package): string
{
// place into `vendor` directory as usual if Pluginkit is not supported
if ($this->supportsPluginkit($package) !== true) {
return parent::getInstallPath($package);
}
// get the extra configuration of the top-level package
if ($rootPackage = $this->composer->getPackage()) {
$extra = $rootPackage->getExtra();
} else {
$extra = [];
}
// use base path from configuration, otherwise fall back to default
$basePath = $extra['kirby-plugin-path'] ?? 'site/plugins';
// determine the plugin name from its package name;
// can be overridden in the plugin's `composer.json`
$prettyName = $package->getPrettyName();
$pluginExtra = $package->getExtra();
if (!empty($pluginExtra['installer-name'])) {
$name = $pluginExtra['installer-name'];
} elseif (strpos($prettyName, '/') !== false) {
// use name after the slash
$name = explode('/', $prettyName)[1];
} else {
$name = $prettyName;
}
// build destination path from base path and plugin name
return $basePath . '/' . $name;
}
/**
* Custom handler that will be called after each package
* installation or update
*
* @param PackageInterface $package
*/
protected function postInstall(PackageInterface $package)
{
// only continue if Pluginkit is supported
if ($this->supportsPluginkit($package) !== true) {
return;
}
parent::postInstall($package);
}
/**
* Checks if the package has explicitly required this installer;
* otherwise (if the Pluginkit is not yet supported by the plugin)
* the installer will fall back to the behavior of the LibraryInstaller
*
* @param PackageInterface $package
* @return bool
*/
protected function supportsPluginkit(PackageInterface $package): bool
{
foreach ($package->getRequires() as $link) {
if ($link->getTarget() === 'getkirby/composer-installer') {
return true;
}
}
// no required package is the installer
return false;
}
}