<?php
namespace App\Blocks;
use Psr\Container\ContainerInterface;
use Twig\Environment;
class BlocksLoader
{
private $twig;
/**
* @var BlockRuntimeDescription[]
*/
private array $blocks = [];
private ContainerInterface $container;
public function __construct(ContainerInterface $container, Environment $twig)
{
$this->container = $container;
$this->twig = $twig;
}
/**
* Load all blocks from core's block directory
*/
private function loadBaseBlocks() {
$commonBlocksPath = __DIR__ . '/../../blocks';
$blockNames = self::getBlockFolderList($commonBlocksPath);
foreach ($blockNames as $blockName) {
$this->blocks[] = new BlockRuntimeDescription($commonBlocksPath, $blockName);
}
}
/**
* Load additional blocks from a custom directory and namespace
*/
private function overrideBlocks(string $namespace, string $newBasePath)
{
$existingBlockNames = array_map(function ($block) {
return $block->name;
}, $this->blocks);
$blockNames = self::getBlockFolderList($newBasePath);
foreach ($blockNames as $blockName) {
if (in_array($blockName, $existingBlockNames)) {
$this->getBlockByName($blockName)?->override($namespace, $newBasePath);
} else {
$this->blocks[] = new BlockRuntimeDescription($newBasePath, $blockName);
}
}
}
/**
* Inject all loaded blocks into ACF
*/
private function inject()
{
foreach ($this->blocks as $blockDescription) {
$blockDescription->register(function (array $rawGutenbergBlockData, bool $preview, $additionalData) use ($blockDescription) {
$this->renderCallback($blockDescription->name, $rawGutenbergBlockData, $preview, $additionalData);
});
}
}
private function getBlockClass(string $blockName): string
{
$block = $this->getBlockByName($blockName);
if (!$block) {
return GenericBlock::class;
}
if ($block->overridenClass) {
return $block->overridenClass;
}
return GenericBlock::class;
}
private function getBlockObject(string $blockName): BlockInterface
{
$class = $this->getBlockClass($blockName);
if ($this->container->has($class)) {
return $this->container->get($class);
}
return new $class;
}
public function renderCallback(string $blockName, array $rawGutenbergBlockData, $preview = false, array|false $additionalData = false)
{
try {
$blockDefinition = $this->getBlockByName($blockName);
$object = $this->getBlockObject($blockName);
$template = $this->twig->load($blockDefinition->getTemplate());
$rawGutenbergBlockData['additionalData'] = $additionalData ?: [];
$context = $object->buildTemplateContext($rawGutenbergBlockData);
echo $template->render($context);
} catch (\Exception|\Error $e) {
if ($preview) {
echo "<div><strong>Error al renderizar el bloque: {$e->getMessage()}</strong>";
return;
}
throw $e;
}
}
public function setBlockCategories($categories, $post)
{
return array_merge(
$categories,
array(
array(
'slug' => 'ydevs',
'title' => 'Ydevs Blocks',
'icon' => 'wordpress',
),
)
);
}
public function init(string $websiteBlocksPath, string $websiteNamespace = 'Blocks')
{
$this->loadBaseBlocks();
$this->overrideBlocks($websiteNamespace, $websiteBlocksPath);
$this->inject();
}
// -- old shite
public static function getBlockFolderList(string $basePath)
{
$blocks = [];
foreach (glob($basePath . DIRECTORY_SEPARATOR . "*", GLOB_ONLYDIR) as $folder) {
$blocks[] = basename($folder);
}
return $blocks;
}
private function getBlockByName(string $blockName): ?BlockRuntimeDescription
{
foreach ($this->blocks as $block) {
if ($block->name === $blockName) {
return $block;
}
}
return null;
}
}