julienmonnerie/kirby/src/Cms/Blocks.php

167 lines
4 KiB
PHP
Raw Normal View History

2022-06-17 17:51:59 +02:00
<?php
namespace Kirby\Cms;
use Exception;
use Kirby\Data\Json;
use Kirby\Data\Yaml;
use Kirby\Parsley\Parsley;
use Kirby\Parsley\Schema\Blocks as BlockSchema;
use Kirby\Toolkit\A;
use Kirby\Toolkit\Str;
use Throwable;
/**
* A collection of blocks
* @since 3.5.0
*
* @package Kirby Cms
* @author Bastian Allgeier <bastian@getkirby.com>
* @link https://getkirby.com
* @copyright Bastian Allgeier
* @license https://getkirby.com/license
*/
class Blocks extends Items
{
public const ITEM_CLASS = '\Kirby\Cms\Block';
/**
* Return HTML when the collection is
* converted to a string
*
* @return string
*/
public function __toString(): string
{
return $this->toHtml();
}
/**
* Converts the blocks to HTML and then
* uses the Str::excerpt method to create
* a non-formatted, shortened excerpt from it
*
* @param mixed ...$args
* @return string
*/
public function excerpt(...$args)
{
return Str::excerpt($this->toHtml(), ...$args);
}
/**
* Wrapper around the factory to
* catch blocks from layouts
*
* @param array $items
* @param array $params
* @return \Kirby\Cms\Blocks
*/
public static function factory(array $items = null, array $params = [])
{
$items = static::extractFromLayouts($items);
$items = BlockConverter::editorBlocks($items);
return parent::factory($items, $params);
}
/**
* Pull out blocks from layouts
*
* @param array $input
* @return array
*/
protected static function extractFromLayouts(array $input): array
{
if (empty($input) === true) {
return [];
}
if (
// no columns = no layout
array_key_exists('columns', $input[0]) === false ||
// checks if this is a block for the builder plugin
array_key_exists('_key', $input[0]) === true
) {
return $input;
}
$blocks = [];
foreach ($input as $layout) {
foreach (($layout['columns'] ?? []) as $column) {
foreach (($column['blocks'] ?? []) as $block) {
$blocks[] = $block;
}
}
}
return $blocks;
}
/**
* Checks if a given block type exists in the collection
* @since 3.6.0
*
* @param string $type
* @return bool
*/
public function hasType(string $type): bool
{
return $this->filterBy('type', $type)->count() > 0;
}
/**
* Parse and sanitize various block formats
*
* @param array|string $input
* @return array
*/
public static function parse($input): array
{
if (empty($input) === false && is_array($input) === false) {
try {
$input = Json::decode((string)$input);
} catch (Throwable $e) {
try {
// try to import the old YAML format
$yaml = Yaml::decode((string)$input);
$first = A::first($yaml);
// check for valid yaml
if (empty($yaml) === true || (isset($first['_key']) === false && isset($first['type']) === false)) {
throw new Exception('Invalid YAML');
} else {
$input = $yaml;
}
} catch (Throwable $e) {
$parser = new Parsley((string)$input, new BlockSchema());
$input = $parser->blocks();
}
}
}
if (empty($input) === true) {
return [];
}
return $input;
}
/**
* Convert all blocks to HTML
*
* @return string
*/
public function toHtml(): string
{
$html = [];
foreach ($this->data as $block) {
$html[] = $block->toHtml();
}
return implode($html);
}
}