Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,7 @@
/yarn.lock export-ignore
/doc export-ignore
/.editorconfig export-ignore
/tests export-ignore
/phpunit.xml.dist export-ignore
/phpstan.neon.dist export-ignore
/phpstan-baseline.neon export-ignore
55 changes: 55 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
name: CI

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
tests:
name: PHP ${{ matrix.php }}
runs-on: ubuntu-latest

strategy:
fail-fast: false
matrix:
php: ['8.4']

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: mbstring, xml, ctype, iconv, intl, pdo_sqlite
coverage: none

- name: Get composer cache directory
id: composer-cache
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT

- name: Cache composer dependencies
uses: actions/cache@v4
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}
restore-keys: ${{ runner.os }}-composer-

- name: Install dependencies
run: composer update --prefer-dist --no-progress

- name: Initialize PHPUnit Bridge
run: vendor/bin/simple-phpunit -v

- name: Run PHP CS Fixer (Code Style)
if: matrix.php == '8.4'
run: composer cs:check

- name: Run PHPStan (Static Analysis)
run: composer stan

- name: Run PHPUnit (Tests)
run: composer tests
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
composer.lock
var
vendor/*
.phpunit.result.cache
/phpunit.xml
.php-cs-fixer.cache

/node_modules/
npm-debug.log
Expand Down
32 changes: 32 additions & 0 deletions .php-cs-fixer.dist.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

declare(strict_types=1);

$finder = PhpCsFixer\Finder::create()
->in(__DIR__ . '/src')
->in(__DIR__ . '/tests')
->append([__FILE__])
->ignoreDotFiles(true)
->ignoreVCS(true)
->files()
->name('*.php');

return new PhpCsFixer\Config()
->setParallelConfig(PhpCsFixer\Runner\Parallel\ParallelConfigFactory::detect())
->setRules([
'@Symfony' => true,
'@Symfony:risky' => true,
'@PHP84Migration' => true,
'declare_strict_types' => true,
'global_namespace_import' => [
'import_classes' => true,
'import_constants' => true,
'import_functions' => true,
],
'yoda_style' => false, // Disable the Yoda style (e.g., if (null === $var)) if you prefer the classic style (if ($var === null)).
'concat_space' => ['spacing' => 'one'], // Adds a space around the concatenation points
])
->setUsingCache(true)
->setRiskyAllowed(true)
->setFinder($finder)
->setCacheFile(__DIR__ . '/var/cache/.php-cs-fixer.cache'); // Put the cache away neatly.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<a href="https://packagist.org/packages/ezar101/easyadmin-trix-extension-bundle"><img src="https://poser.pugx.org/ezar101/easyadmin-trix-extension-bundle/v" alt="Latest Stable Version"></a>
<a href="https://packagist.org/packages/ezar101/easyadmin-trix-extension-bundle"><img src="https://poser.pugx.org/ezar101/easyadmin-trix-extension-bundle/downloads" alt="Total Downloads"></a>
<a href="LICENSE"><img src="https://poser.pugx.org/ezar101/easyadmin-trix-extension-bundle/license" alt="License"></a>
<a href="https://github.com/Ezar101/EasyAdminTrixExtensionBundle/actions/workflows/ci.yaml"><img src="https://github.com/Ezar101/EasyAdminTrixExtensionBundle/actions/workflows/ci.yaml/badge.svg" alt="CI"></a>
</p>

This Symfony bundle extends the native capabilities of EasyAdmin's `TextEditorField` (based on Trix). It offers an enhanced writing experience by adding essential features that are missing by default, all without any complex front-end configuration.
Expand Down
25 changes: 25 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,42 @@
"symfony/framework-bundle": "^6.0|^7.0|^8.0",
"easycorp/easyadmin-bundle": "^4.0|^5.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.94",
"phpstan/extension-installer": "^1.4",
"phpstan/phpstan": "^2.0",
"phpstan/phpstan-phpunit": "^2.0",
"phpstan/phpstan-strict-rules": "^2.0",
"symfony/phpunit-bridge": "^6.4.26|^7.0|^8.0"
},
"autoload": {
"psr-4": {
"Ezar101\\EasyAdminTrixExtensionBundle\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"Ezar101\\EasyAdminTrixExtensionBundle\\Tests\\": "tests/"
}
},
"config": {
"sort-packages": true,
"allow-plugins": {
"phpstan/extension-installer": true,
"symfony/flex": true,
"symfony/runtime": false
}
},
"scripts": {
"tests": "simple-phpunit",
"cs:check": "php-cs-fixer fix --dry-run --diff",
"cs:fix": "php-cs-fixer fix",
"stan": "phpstan analyse",
"qa": [
"@cs:check",
"@stan",
"@tests"
]
},
"minimum-stability": "stable"
}
21 changes: 21 additions & 0 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
parameters:
level: 6
phpVersion: 80400
paths:
- src/
- tests/

excludePaths:
- vendor/

bootstrapFiles:
- vendor/bin/.phpunit/phpunit/vendor/autoload.php

ignoreErrors:
-
identifier: missingType.generics

treatPhpDocTypesAsCertain: false
reportUnmatchedIgnoredErrors: false

tmpDir: var/cache/phpstan
28 changes: 28 additions & 0 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>

<!-- https://phpunit.de/manual/current/en/appendixes.configuration.html -->
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="vendor/bin/.phpunit/phpunit.xsd"
colors="true"
bootstrap="tests/bootstrap.php">

<php>
<ini name="display_errors" value="1" />
<ini name="error_reporting" value="-1" />
<server name="APP_ENV" value="test" force="true" />
<server name="APP_DEBUG" value="true" force="true" />
<server name="SHELL_VERBOSITY" value="-1" />
</php>

<testsuites>
<testsuite name="EasyAdmin Trix Extension Unit Test Suite">
<directory>tests/</directory>
</testsuite>
</testsuites>

<coverage processUncoveredFiles="true">
<include>
<directory suffix=".php">src</directory>
</include>
</coverage>
</phpunit>
9 changes: 7 additions & 2 deletions src/Config/Asset.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,13 @@

namespace Ezar101\EasyAdminTrixExtensionBundle\Config;

use JsonException;

use const JSON_THROW_ON_ERROR;

final class Asset
{
/** @var array<string, string>|null */
private static ?array $manifest = null;

private function __construct()
Expand All @@ -20,8 +25,8 @@ public static function from(string $filename): string
if (file_exists($path)) {
try {
$content = file_get_contents($path);
self::$manifest = json_decode($content, true, 512, JSON_THROW_ON_ERROR) ?: [];
} catch (\JsonException $e) {
self::$manifest = json_decode($content, true, 512, JSON_THROW_ON_ERROR) ?? [];
} catch (JsonException $e) {
self::$manifest = [];
}
} else {
Expand Down
10 changes: 7 additions & 3 deletions src/Field/ExtendedTextEditorField.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,24 @@

namespace Ezar101\EasyAdminTrixExtensionBundle\Field;

use EasyCorp\Bundle\EasyAdminBundle\Config\Asset as EasyAdminAsset;
use EasyCorp\Bundle\EasyAdminBundle\Contracts\Field\FieldInterface;
use EasyCorp\Bundle\EasyAdminBundle\Field\FieldTrait;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextEditorField;
use EasyCorp\Bundle\EasyAdminBundle\Form\Type\TextEditorType;
use Ezar101\EasyAdminTrixExtensionBundle\Config\Asset;
use InvalidArgumentException;
use Symfony\Contracts\Translation\TranslatableInterface;
use EasyCorp\Bundle\EasyAdminBundle\Config\Asset as EasyAdminAsset;

use function sprintf;

final class ExtendedTextEditorField implements FieldInterface
{
use FieldTrait;

public static function new(string $propertyName, TranslatableInterface|bool|string|null $label = null): self
{
return (new self)
return new self()
->setProperty($propertyName)
->setLabel($label)
->setTemplateName('crud/field/text_editor')
Expand All @@ -41,7 +44,7 @@ public static function new(string $propertyName, TranslatableInterface|bool|stri
public function setNumOfRows(int $rows): self
{
if ($rows < 1) {
throw new \InvalidArgumentException(sprintf('The argument of the "%s()" method must be 1 or higher (%d given).', __METHOD__, $rows));
throw new InvalidArgumentException(sprintf('The argument of the "%s()" method must be 1 or higher (%d given).', __METHOD__, $rows));
}

$this->setCustomOption(TextEditorField::OPTION_NUM_OF_ROWS, $rows);
Expand All @@ -51,6 +54,7 @@ public function setNumOfRows(int $rows): self

/**
* @param array<string, mixed> $config
*
* @see TextEditorField::setTrixEditorConfig()
*/
public function setTrixEditorConfig(array $config): self
Expand Down
68 changes: 68 additions & 0 deletions tests/Unit/Config/AssetTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?php

declare(strict_types=1);

namespace Ezar101\EasyAdminTrixExtensionBundle\Tests\Unit\Config;

use Ezar101\EasyAdminTrixExtensionBundle\Config\Asset;
use ReflectionClass;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;

class AssetTest extends KernelTestCase
{
protected function tearDown(): void
{
// After each test, the static property $manifest is reset to null.
// to prevent the state of one test from contaminating the next.
$reflection = new ReflectionClass(Asset::class);
$reflection->setStaticPropertyValue('manifest', null);

parent::tearDown();
}

public function testAssetReturnsCleanPathWhenManifestDoesNotContainFile(): void
{
// We simulate a manifest that has been loaded but does not contain the file,
// (or the case where the file did not exist and returned an empty array).
// By using an empty array [], we prevent the class from reading the actual file on disk.
$reflection = new ReflectionClass(Asset::class);
$reflection->setStaticPropertyValue('manifest', []);

$result = Asset::from('extended-trix.css');

self::assertSame('bundles/easyadmintrixextension/extended-trix.css', $result);
}

public function testAssetUsesManifestWhenAvailable(): void
{
// We simulate a loaded manifest by directly injecting an array
// via Reflection, without having to create a fake physical file.
$manifestMock = [
'extended-trix.css' => 'extended-trix.8b7c6d5e.css',
'extended-trix.js' => 'extended-trix.1a2b3c4d.js',
];

$reflection = new ReflectionClass(Asset::class);
$reflection->setStaticPropertyValue('manifest', $manifestMock);

$resultCss = Asset::from('extended-trix.css');
$resultJs = Asset::from('extended-trix.js');

self::assertSame('bundles/easyadmintrixextension/extended-trix.8b7c6d5e.css', $resultCss);
self::assertSame('bundles/easyadmintrixextension/extended-trix.1a2b3c4d.js', $resultJs);
}

public function testAssetStripsLeadingDotSlash(): void
{
// Sometimes Webpack Encore generates manifests with "./file.css"
// We check that ltrim($target, './') works correctly.
$reflection = new ReflectionClass(Asset::class);
$reflection->setStaticPropertyValue('manifest', [
'app.css' => './assets/app.1234.css',
]);

$result = Asset::from('app.css');

self::assertSame('bundles/easyadmintrixextension/assets/app.1234.css', $result);
}
}
Loading
Loading