Skip to content

Commit

Permalink
[RELEASE] 1.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
NamelessCoder committed Feb 13, 2023
0 parents commit d55135a
Show file tree
Hide file tree
Showing 32 changed files with 2,464 additions and 0 deletions.
113 changes: 113 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
name: build

on:
push:
branches: [ master, develop, '[0-9]+.[0-9]+', '[0-9]+.[0-9]+.[0-9]+' ]
pull_request:
branches: [ master, develop, '[0-9]+.[0-9]', '[0-9]+.[0-9]+.[0-9]+' ]

jobs:
phpcs:
if: "!contains(github.event.head_commit.message, '[skip ci]')"
name: "CodeSniffer, PHP ${{ matrix.php }}"

strategy:
fail-fast: false
matrix:
php: ["7.4", "8.1", "8.2"]

runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v3

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: mbstring, json
ini-values: date.timezone="Europe/Copenhagen", opcache.fast_shutdown=0
tools: composer:v2.2

- name: Composer install
uses: ramsey/composer-install@v2

- name: Run phpcs
run: vendor/bin/phpcs Classes --standard=PSR2

phpstan:
if: "!contains(github.event.head_commit.message, '[skip ci]')"
name: "PHPStan, PHP ${{ matrix.php }} TYPO3 ${{ matrix.typo3 }}"

strategy:
fail-fast: false
matrix:
php: ["7.4", "8.1", "8.2"]

runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v3

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: mbstring, json
ini-values: date.timezone="Europe/Copenhagen", opcache.fast_shutdown=0
tools: composer:v2.2

- name: Composer install
uses: ramsey/composer-install@v2

- name: Run phpstan
run: vendor/bin/phpstan analyze

build:
if: "!contains(github.event.head_commit.message, '[skip ci]')"
name: "PHPUnit, PHP ${{ matrix.php }} TYPO3 ${{ matrix.typo3 }}"
needs: [phpcs, phpstan]

strategy:
fail-fast: false
matrix:
php: ["7.4", "8.1", "8.2"]

runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v3

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: mbstring, json
ini-values: date.timezone="Europe/Copenhagen", opcache.fast_shutdown=0
tools: composer:v2.2

- name: Composer install
uses: ramsey/composer-install@v2

- name: Run tests
run: vendor/bin/phpunit --coverage-clover=build/logs/clover.xml

- name: Upload test coverage
run: vendor/bin/php-coveralls -vvv
env:
COVERALLS_PARALLEL: true
COVERALLS_FLAG_NAME: typo3-${{ matrix.typo3 }}-php-${{ matrix.php }}
COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }}

finish:
needs: build
runs-on: ubuntu-latest
steps:
- name: Coveralls Finished
uses: coverallsapp/github-action@master
with:
github-token: ${{ secrets.github_token }}
parallel-finished: true
31 changes: 31 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
on:
push:
tags:
- "**"

jobs:
release:
runs-on: ubuntu-20.04
steps:
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: 8.2
extensions: mbstring, json
ini-values: date.timezone="Europe/Copenhagen", opcache.fast_shutdown=0
tools: composer:v2.2
- name: "create working directory"
run: "mkdir tailor"
- name: "Install Tailor"
working-directory: tailor
run: "composer require typo3/tailor"
- name: "Upload to TER"
working-directory: tailor
run: "./vendor/bin/tailor ter:publish $TAG $EXTENSION_KEY --artefact $ARTEFECT_URL --comment \"$MESSAGE\""
env:
TYPO3_API_USERNAME: ${{ secrets.TER_USERNAME }}
TYPO3_API_TOKEN: ${{ secrets.TER_TOKEN }}
TAG: ${{ github.ref_name }}
EXTENSION_KEY: fluid_parameters
ARTEFECT_URL: "https://github.com/${{ github.repository }}/archive/${{ github.ref }}.zip"
MESSAGE: "Automatic release built from GitHub. See the CHANGELOG.md file that is shipped with this release for details."
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.idea
.phpunit.cache
vendor
composer.lock
27 changes: 27 additions & 0 deletions Classes/Node/ParameterNode.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php
namespace NamelessCoder\FluidParameters\Node;

use NamelessCoder\FluidParameters\Parameter\ParameterHandler;
use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\NodeInterface;
use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\ViewHelperNode;
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;

class ParameterNode extends ViewHelperNode implements NodeInterface
{
public function __construct()
{
$this->uninitializedViewHelper = new ParameterHandler();
}

public function evaluate(RenderingContextInterface $renderingContext): string
{
ParameterHandler::validateParameterPresence($renderingContext);
return '';
}

public function removeChildNodes(): void
{
$this->childNodes = [];
$this->uninitializedViewHelper->setChildNodes([]);
}
}
27 changes: 27 additions & 0 deletions Classes/Parameter/ParameterDefinition.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php
namespace NamelessCoder\FluidParameters\Parameter;

use TYPO3Fluid\Fluid\Core\ViewHelper\ArgumentDefinition;

class ParameterDefinition extends ArgumentDefinition
{
private array $oneOf = [];

public function __construct(
string $name,
string $type,
?string $description = null,
bool $required = false,
array $oneOf = [],
$defaultValue = null,
?bool $escape = null
) {
parent::__construct($name, $type, (string) $description, $required, $defaultValue, $escape);
$this->oneOf = $oneOf;
}

public function getOneOf(): array
{
return $this->oneOf;
}
}
151 changes: 151 additions & 0 deletions Classes/Parameter/ParameterHandler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
<?php
namespace NamelessCoder\FluidParameters\Parameter;

use NamelessCoder\FluidParameters\ViewHelpers\Parameter\ModeViewHelper;
use NamelessCoder\FluidParameters\ViewHelpers\ParameterViewHelper;
use TYPO3Fluid\Fluid\Core\Compiler\TemplateCompiler;
use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\ViewHelperNode;
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
use TYPO3Fluid\Fluid\Core\ViewHelper\Exception;

class ParameterHandler extends AbstractViewHelper
{
public function render(): void
{
self::validateParameterPresence($this->renderingContext);
}

public static function renderStatic(
array $arguments,
\Closure $renderChildrenClosure,
RenderingContextInterface $renderingContext
) {
self::validateParameterPresence($renderingContext);
return '';
}

public static function validateParameterPresence(RenderingContextInterface $renderingContext): void
{
$viewHelperVariableContainer = $renderingContext->getViewHelperVariableContainer();
$variableProvider = $renderingContext->getVariableProvider();
/** @var array $variables */
$variables = $variableProvider->getAll();
/** @var ParameterDefinition[] $definitions */
$definitions = $viewHelperVariableContainer->get(
ParameterViewHelper::class,
ParameterViewHelper::PARAMETER_REGISTRY_VARIABLE
);
/** @var array $options */
$options = $viewHelperVariableContainer->get(
ParameterViewHelper::class,
ParameterViewHelper::OPTION_REGISTRY_VARIABLE
) ?? [];

foreach ($definitions as $name => $definition) {
if ($definition->isRequired() && !array_key_exists($name, $variables)) {
throw new Exception('Required variable "' . $name . '" was not passed', 1675268804);
}
$type = $definition->getType();
$value = $variables[$name] ?? $definition->getDefaultValue();
$value = self::cast($value, $type);

if (!empty(($oneOf = $definition->getOneOf()))) {
$oneOf = array_map(
function ($value) use ($type) {
return self::cast($value, $type);
},
$oneOf
);
if (!in_array($value, $oneOf, true)) {
throw new Exception(
'Parameter "' . $name . '" with value ' . json_encode($value) .
' was not one of the allowed values: ' . json_encode($oneOf),
1675268818
);
}
}

$variableProvider->add($name, $value);
unset($variables[$name]);
}

// Validate that no unexpected variables were assigned; ignoring the special always-present "settings" variable.
unset($variables['settings']);
if (!empty($variables) && ($options[ModeViewHelper::OPTION_MODE] ?? null) === ModeViewHelper::MODE_STRICT) {
throw new Exception(
'Unxpected (undefined) template variable(s) encountered: ' . implode(', ', array_keys($variables)),
1675268804
);
}

$viewHelperVariableContainer->remove(
ParameterViewHelper::class,
ParameterViewHelper::PARAMETER_REGISTRY_VARIABLE
);
$viewHelperVariableContainer->remove(
ParameterViewHelper::class,
ParameterViewHelper::OPTION_REGISTRY_VARIABLE
);
}

/**
* @param mixed $value
* @param string $type
* @return mixed
*/
private static function cast($value, string $type)
{
switch ($type) {
case 'int':
case 'integer':
$value = is_scalar($value) || is_null($value) ? (int) $value : $value;
break;
case 'float':
case 'double':
case 'decimal':
$value = $value = is_scalar($value) || is_null($value) ? (float) $value : $value;
break;
case 'string':
$value = is_scalar($value) || is_null($value) ? (string) $value : $value;
break;
case 'array':
if (is_string($value)) {
$value = array_map('trim', explode(',', $value));
} else {
$value = (array) $value;
}
break;
case 'bool':
case 'boolean':
$value = (bool) $value;
break;
case 'DateTime':
if (is_numeric($value)) {
$value = \DateTime::createFromFormat('U', (string) $value);
} elseif (is_string($value)) {
$value = new \DateTime($value);
}
break;
case 'object':
$value = (object) $value;
// Fall-through is intentional; default handling is to check for specific type of object by class name
default:
if (class_exists($type)) {
$value = new $type($value);
}
break;
}
return $value;
}

public function compile(
$argumentsName,
$closureName,
&$initializationPhpCode,
ViewHelperNode $node,
TemplateCompiler $compiler
) {
return self::class . '::validateParameterPresence($renderingContext)';
}
}
39 changes: 39 additions & 0 deletions Classes/Reflection/AbstractReflection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php
namespace NamelessCoder\FluidParameters\Reflection;

use NamelessCoder\FluidParameters\Parameter\ParameterDefinition;

abstract class AbstractReflection
{
/**
* @var array<string, ParameterDefinition>
*/
private array $parameterDefinitions;
private ?string $description;
private string $parameterMode;

public function __construct(array $parameterDefinitions, ?string $description, string $parameterMode)
{
$this->parameterDefinitions = $parameterDefinitions;
$this->description = $description;
$this->parameterMode = $parameterMode;
}

/**
* @return array<string, ParameterDefinition>
*/
public function getParameterDefinitions(): array
{
return $this->parameterDefinitions;
}

public function getDescription(): ?string
{
return $this->description;
}

public function getParameterMode(): string
{
return $this->parameterMode;
}
}

0 comments on commit d55135a

Please sign in to comment.