Skip to content

Commit

Permalink
[#33] Adds cli generator and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
joshuapease committed Mar 24, 2022
1 parent 5bdc579 commit 9fb52dd
Show file tree
Hide file tree
Showing 10 changed files with 340 additions and 2 deletions.
10 changes: 9 additions & 1 deletion src/Module.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,12 @@ class Module extends \yii\base\Module
public function init()
{
Craft::setAlias('@viget/base', __DIR__);
$this->controllerNamespace = 'viget\base\controllers';

if (Craft::$app->getRequest()->getIsConsoleRequest()) {
$this->controllerNamespace = 'viget\base\console\controllers';
} else {
$this->controllerNamespace = 'viget\base\controllers';
}

parent::init();
self::$instance = $this;
Expand Down Expand Up @@ -206,6 +211,9 @@ private function _loadConfig()
'volume' => 'partsKit',
'theme' => 'light',
],
'scaffold' => [
'templatePrefix' => null, // used for test suite
],
'tailwind' => [
'configPath' => Craft::getAlias('@config/tailwind/tailwind.json'),
],
Expand Down
193 changes: 193 additions & 0 deletions src/console/controllers/GenerateController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
<?php

namespace viget\base\console\controllers;

use Craft;
use craft\console\Controller;
use craft\helpers\FileHelper;
use craft\services\Sections;

use viget\base\Module;
use yii\console\ExitCode;
use yii\helpers\Console;

class GenerateController extends Controller
{

// TODO - pass variants to make multiple files `default, dark, two-up`
// TODO - make multiple partials at once

private $templatesDir;
private $scaffoldTemplatesDir;
private $partsKitDir;
private $defaultFileExtension;

public function init()
{
$templatePrefix = self::getConfig('templatePrefix', 'scaffold');
$this->templatesDir = Craft::$app->path->getSiteTemplatesPath() . $templatePrefix;
$this->scaffoldTemplatesDir = FileHelper::normalizePath(__dir__ . '/../../templates/_scaffold');
$this->partsKitDir = self::getConfig('directory');
$this->defaultFileExtension = '.html';
parent::init();
}


/**
* Get a config item either the default or from the config file
*
* @param string $key
* @return string|array|null
*/
public static function getConfig(string $key, string $section = 'partsKit')
{
return Module::$config[$section][$key] ?? null;
}

public function actionEntrytypes(string $handle)
{
$section = Craft::$app->sections->getSectionByHandle($handle);
if(!$section) {
$this->stdout("No section found for $handle" . PHP_EOL, Console::FG_RED);
return ExitCode::UNSPECIFIED_ERROR;
}

$settings = current($section->getSiteSettings()) ?? null;

if(!$settings) {
$this->stdout("No settings found for section $handle" . PHP_EOL, Console::FG_RED);
return ExitCode::UNSPECIFIED_ERROR;
}

$templateParts = self::_splitAndSanitizeInput($settings->template);
$path = $templateParts['path'];

$templateContent = self::_compileTemplate(
$this->_loadScaffoldTemplate('template.html'),
[
'layout' => self::getConfig('layout'),
]
);

$structureIndex = self::_compileTemplate(
$this->_loadScaffoldTemplate('structure.html'),
[
'path' => $templateParts['path'],
]
);

// Create the index file for our structure
$this->_writeFile( $path . '/index', $structureIndex);

foreach($section->entryTypes as $entryType) {
$this->_writeFile($path . '/' . $entryType->handle, $templateContent);
}

return ExitCode::OK;
}

public function actionTemplate($templatePath)
{
$parts = self::_splitAndSanitizeInput($templatePath);
$path = $parts['path'];
$filename = $parts['filename'];

$templateContent = self::_compileTemplate(
$this->_loadScaffoldTemplate('template.html'),
[
'layout' => self::getConfig('layout'),
]
);

// Write template file
// TODO make _elements a config option
$this->_writeFile('_elements/' . $path . '/' . $filename, $templateContent);

return ExitCode::OK;
}

public function actionPartial($partialPath, ?string $variantsInput = null)
{
$parts = self::_splitAndSanitizeInput($partialPath);
$path = $parts["path"];
$filename = $parts['filename'];

$variants = [
'default',
];

if($variantsInput) {
$variants = array_merge($variants, explode(',', $variantsInput));
}

$partialContent = $this->_loadScaffoldTemplate('partial.html');
$partsKitContent = $this->_loadScaffoldTemplate('partial-parts-kit.html');

$partsKitContentCompiled = self::_compileTemplate($partsKitContent, [
'partialPath' => $partialPath,
]);

// Create file in _partials dir
// TODO make _partials a config option
$this->_writeFile('_partials/' . $path . '/' . $filename, $partialContent);

foreach($variants as $variant) {
$this->_writeFile($this->partsKitDir . '/' . $filename . '/' . $variant, $partsKitContentCompiled);
}

return ExitCode::OK;
}

private function _loadScaffoldTemplate(string $path)
{
return file_get_contents($this->scaffoldTemplatesDir . '/' . $path);
}

private function _writeFile(string $path, string $content)
{
$fullPath = $this->templatesDir . '/' . $path . $this->defaultFileExtension;

if (file_exists($fullPath)) {
$this->stdout("File already exists for $fullPath" . PHP_EOL, Console::FG_RED);
return;
}

FileHelper::writeToFile($fullPath, $content);
}

// TODO - unit test
private static function _removeFileExtension(string $filename): string
{
$explode = explode('.', $filename);
if(count($explode) === 1) {
return $filename;
}

return implode('.', array_slice($explode, 0, -1));
}

// TODO - unit test
private static function _splitAndSanitizeInput(string $input): array
{
$split = explode(DIRECTORY_SEPARATOR, $input);
$path = implode(DIRECTORY_SEPARATOR, array_slice($split, 0, -1));
$filename = self::_removeFileExtension(end($split));

return [
'path' => FileHelper::normalizePath($path),
'filename' => FileHelper::sanitizeFilename($filename),
];
}

// TODO - unit test
private static function _compileTemplate(string $template, array $vars): string
{
$patterns = array_map(function ($item) {
return "/%%$item%%/";
}, array_values(array_flip($vars)));

$replacements = array_values($vars);

return preg_replace($patterns, $replacements, $template);
}
}
7 changes: 7 additions & 0 deletions src/templates/_scaffold/partial-parts-kit.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{% extends 'viget-base/_layouts/parts-kit' %}

{% block main %}
{{ partial('_partials/%%partialPath%%', {
key: value,
}) }}
{% endblock %}
3 changes: 3 additions & 0 deletions src/templates/_scaffold/partial.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{% set prop = prop ?? null %}

<!-- Your partial -->
3 changes: 3 additions & 0 deletions src/templates/_scaffold/structure.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{{ partial("%%path%%/#{entry.type.handle}", {
entry: entry,
}) }}
18 changes: 18 additions & 0 deletions src/templates/_scaffold/template.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{% do craft.app.elements.eagerLoadElements(
className(entry),
[entry],
[
'assetField',
'matrixField',
]
) %}

{% from '_macros' import macro %}

{% extends '%%layout%%' %}

{% set title = entry.title %}

{% block content %}
<h1>{{ title }}</h1>
{% endblock %}
3 changes: 3 additions & 0 deletions tests/_craft/config/viget.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
<?php

return [
'scaffold' => [
'templatePrefix' => '/temp',
],
'partsKit' => [
'directory' => 'parts-kit',
'layout' => '_layouts/app',
Expand Down
11 changes: 10 additions & 1 deletion tests/fixtures/data/entry-types.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,18 @@
'fieldLayoutId' => null,
'name' => 'Test Entry Type 1',
'handle' => 'testEntryType1',
'titleLabel' => 'Title',
'titleFormat' => null,
'sortOrder' => '1',
'uid' => 'entry-type-1000------------------uid'
],
[
'id' => '1001',
'sectionId' => '1000',
'fieldLayoutId' => null,
'name' => 'Test Entry Type 2',
'handle' => 'testEntryType2',
'titleFormat' => null,
'sortOrder' => '2',
'uid' => 'entry-type-1001------------------uid'
],
];
1 change: 1 addition & 0 deletions tests/fixtures/data/section-settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@
'uriFormat' => null,
'template' => null,
'enabledByDefault' => true,
'template' => '_elements/test-section-1/index',
],
];
93 changes: 93 additions & 0 deletions tests/unit/console/GenerateControllerTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<?php
namespace vigetbasetests\unit\console;

use Craft;
use craft\helpers\FileHelper;
use craft\test\console\ConsoleTest;
use viget\base\Module;
use vigetbasetests\fixtures\EntryTypesFixture;
use vigetbasetests\fixtures\SectionsFixture;
use yii\base\InvalidConfigException;
use yii\console\ExitCode;

class GenerateControllerTest extends ConsoleTest
{
private $siteTemplatesPath;
private $templatesRoot;
private $partialsRoot;
private $partsKitRoot;

public function _fixtures(): array
{
return [
'entryTypes' => [
'class' => EntryTypesFixture::class,
],
'sections' => [
'class' => SectionsFixture::class,
],
];
}

protected function _before()
{
$templatePath = Craft::$app->getPath()->getSiteTemplatesPath();
$templatePrefix = Module::$config['scaffold']['templatePrefix'];
$partsKitDir = Module::$config['partsKit']['directory'];
$this->siteTemplatesPath = $templatePath . $templatePrefix;
$this->partialsRoot = $this->siteTemplatesPath . '/_partials'; // TODO - config?
$this->templatesRoot = $this->siteTemplatesPath . '/_elements'; // TODO - config?
$this->partsKitRoot = $this->siteTemplatesPath . '/' . $partsKitDir;
}

protected function _after()
{
FileHelper::removeDirectory($this->siteTemplatesPath);
}

/**
* @throws InvalidConfigException
*/
public function testCreatePartial()
{
$this->consoleCommand('viget-base/generate/partial', [
'foo',
])
->exitCode(ExitCode::OK)
->run();

$this->assertFileExists($this->partialsRoot . '/foo.html');
$this->assertFileExists($this->partsKitRoot . '/foo/default.html');
}

/**
* @throws InvalidConfigException
*/
public function testCreateTemplate()
{
$this->consoleCommand('viget-base/generate/template', [
'foo',
])
->exitCode(ExitCode::OK)
->run();

$this->assertFileExists($this->templatesRoot . '/foo.html');
}

/**
* @throws InvalidConfigException
*/
public function testCreateEntryTypes()
{
$this->consoleCommand('viget-base/generate/entrytypes', [
'testSection1',
])
->exitCode(ExitCode::OK)
->run();

$this->assertFileExists($this->templatesRoot . '/test-section-1/index.html');
$this->assertFileExists($this->templatesRoot . '/test-section-1/testEntryType1.html');
$this->assertFileExists($this->templatesRoot . '/test-section-1/testEntryType2.html');
}

}

0 comments on commit 9fb52dd

Please sign in to comment.