Skip to content
Draft
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
62 changes: 62 additions & 0 deletions .tmp_smoke_output.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Home</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
}
.container {
max-width: 800px;
margin: 0 auto;
}
.user-list {
margin-top: 20px;
}
.user-item {
padding: 10px;
border: 1px solid #ddd;
margin-bottom: 10px;
border-radius: 4px;
}
</style>
</head>
<body>
<div class="container">
<h1>Bem-vindo ao Template Engine</h1>

<!-- Exemplo com If -->

<div class="welcome">
<h2>Olá, JOÃO SILVA!</h2>
<p>Email: joao@example.com</p>
<p>Role: admin</p>
</div>


<!-- Exemplo com Foreach -->
<div class="user-list">
<h3>Usuários do Sistema</h3>

<div class="user-item">
<strong>#0: Maria</strong><br>
Email: maria@example.com
</div>

<div class="user-item">
<strong>#1: Pedro</strong><br>
Email: pedro@example.com
</div>

<div class="user-item">
<strong>#2: Ana</strong><br>
Email: ana@example.com
</div>

</div>
</div>
</body>
</html>
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
<?php
require_once 'autoload.php';

use Beobles\Core\View\Engine;
use Core\View\Engine;

$engine = new Engine([
'templates_dir' => __DIR__ . '/templates',
Expand Down Expand Up @@ -82,6 +82,14 @@ import { UserCard } from "@components/UserCard";

Veja [SYNTAX.md](./SYNTAX.md) para documentação completa da sintaxe.

## Validação rápida

```bash
find . -name '*.php' | xargs php -l
php examples/index.php
php examples/edge_matrix.php
```

## Estrutura do Projeto

```
Expand Down
2 changes: 1 addition & 1 deletion autoload.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/

spl_autoload_register(function ($class) {
$prefix = 'Beobles\\Core\\View\\';
$prefix = 'Core\\View\\';
$baseDir = __DIR__ . '/src/Core/View/';

if (strpos($class, $prefix) !== 0) {
Expand Down
138 changes: 138 additions & 0 deletions examples/edge_matrix.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
<?php

require_once __DIR__ . '/../autoload.php';

use Core\View\Engine;

/**
* Matriz de cenários de borda para diretivas e filtros.
* Execução: php examples/edge_matrix.php
*/

$baseDir = sys_get_temp_dir() . '/template_engine_edge_matrix_' . uniqid('', true);
$templatesDir = $baseDir . '/templates';
$cacheDir = $baseDir . '/cache';

if (!is_dir($templatesDir) && !mkdir($templatesDir, 0755, true) && !is_dir($templatesDir)) {
fwrite(STDERR, "Falha ao criar diretório de templates: {$templatesDir}\n");
exit(1);
}

if (!is_dir($cacheDir) && !mkdir($cacheDir, 0755, true) && !is_dir($cacheDir)) {
fwrite(STDERR, "Falha ao criar diretório de cache: {$cacheDir}\n");
exit(1);
}

$engine = new Engine([
'templates_dir' => $templatesDir,
'cache_dir' => $cacheDir,
'cache_enabled' => false,
'auto_escape' => true,
'debug' => true,
]);

$writeTemplate = static function (string $name, string $content) use ($templatesDir): void {
file_put_contents($templatesDir . '/' . $name, $content);
};

$normalize = static function (string $value): string {
return trim((string) preg_replace('/\s+/', ' ', $value));
};

$writeTemplate('partial.html', '[[{{ user.name }}]]');

$cases = [
// Diretivas
[
'name' => 'directive_if_elseif_else',
'template' => '<If condition={{ user.level === 1 }}>ONE<ElseIf condition={{ user.level === 2 }}>TWO<Else>OTHER</Else></If>',
'data' => ['user' => ['level' => 2]],
'expect' => 'TWO',
],
[
'name' => 'directive_foreach_loop_meta',
'template' => '<Foreach items={{ users }} as="user,index">{{ __loop.count }}-{{ index }}-{{ user.name }};</Foreach>',
'data' => ['users' => [['name' => 'Ana'], ['name' => 'Beto']]],
'expect' => '1-0-Ana;2-1-Beto;',
],
[
'name' => 'directive_set',
'template' => '<Set var="total" value={{ 2 + 3 }} />{{ total }}',
'data' => [],
'expect' => '5',
],
[
'name' => 'directive_include_with_data_expression',
'template' => '<Include path="partial.html" data={{ ["user" => ["name" => user.name]] }} />',
'data' => ['user' => ['name' => 'Carla']],
'expect' => '[[Carla]]',
],
[
'name' => 'directive_block_passthrough',
'template' => '<Block name="content">conteudo</Block>',
'data' => [],
'expect' => 'conteudo',
],

// Filtros de string
['name' => 'filter_uppercase_utf8', 'template' => '{{ value | uppercase }}', 'data' => ['value' => 'João'], 'expect' => 'JOÃO'],
['name' => 'filter_lowercase_utf8', 'template' => '{{ value | lowercase }}', 'data' => ['value' => 'AÇÃO'], 'expect' => 'ação'],
['name' => 'filter_ucfirst_utf8', 'template' => '{{ value | ucfirst }}', 'data' => ['value' => 'joão'], 'expect' => 'João'],
['name' => 'filter_trim', 'template' => '{{ value | trim }}', 'data' => ['value' => ' x '], 'expect' => 'x'],
['name' => 'filter_truncate', 'template' => '{{ value | truncate(4, "..") }}', 'data' => ['value' => 'abcdef'], 'expect' => 'abcd..'],
['name' => 'filter_slug', 'template' => '{{ value | slug }}', 'data' => ['value' => 'Ação de Teste!'], 'expect' => 'acao-de-teste'],
['name' => 'filter_reverse_utf8', 'template' => '{{ value | reverse }}', 'data' => ['value' => 'João'], 'expect' => 'oãoJ'],

// Filtros numéricos/data
['name' => 'filter_currency', 'template' => '{{ value | currency("BRL") }}', 'data' => ['value' => 1234.5], 'expect' => 'R$ 1.234,50'],
['name' => 'filter_number_format', 'template' => '{{ value | number_format(2) }}', 'data' => ['value' => 1234.5], 'expect' => '1.234,50'],
['name' => 'filter_abs', 'template' => '{{ value | abs }}', 'data' => ['value' => -10], 'expect' => '10'],
['name' => 'filter_date', 'template' => '{{ value | date("Y-m-d") }}', 'data' => ['value' => '2024-01-02'], 'expect' => '2024-01-02'],

// Filtros de array
['name' => 'filter_count', 'template' => '{{ value | count }}', 'data' => ['value' => [1, 2, 3]], 'expect' => '3'],
['name' => 'filter_first', 'template' => '{{ value | first }}', 'data' => ['value' => [10, 20]], 'expect' => '10'],
['name' => 'filter_last', 'template' => '{{ value | last }}', 'data' => ['value' => [10, 20]], 'expect' => '20'],
['name' => 'filter_join_nested_values', 'template' => '{! value | join(" | ") !}', 'data' => ['value' => ['a', ['k' => 'v'], true]], 'expectContains' => 'a | {"k":"v"} | 1'],
['name' => 'filter_json', 'template' => '{! value | json !}', 'data' => ['value' => ['a' => 1]], 'expectContains' => '"a": 1'],
];

$failures = [];

foreach ($cases as $case) {
$templateFile = $case['name'] . '.html';
$writeTemplate($templateFile, $case['template']);

try {
$output = $engine->render($templateFile, $case['data']);
} catch (\Throwable $e) {
$failures[] = $case['name'] . ': exception inesperada -> ' . $e->getMessage();
continue;
}

$normalizedOutput = $normalize($output);
if (array_key_exists('expect', $case)) {
$expected = $normalize((string) $case['expect']);
if ($normalizedOutput !== $expected) {
$failures[] = $case['name'] . ": esperado '{$expected}', obtido '{$normalizedOutput}'";
}
continue;
}

if (array_key_exists('expectContains', $case)) {
$expectedContains = (string) $case['expectContains'];
if (strpos($normalizedOutput, $expectedContains) === false) {
$failures[] = $case['name'] . ": saída não contém '{$expectedContains}', obtido '{$normalizedOutput}'";
}
}
}

if ($failures !== []) {
fwrite(STDERR, "Falhas na matriz de borda:\n");
foreach ($failures as $failure) {
fwrite(STDERR, "- {$failure}\n");
}
exit(1);
}

echo "OK: matriz de diretivas/filtros passou com " . count($cases) . " cenários.\n";
2 changes: 1 addition & 1 deletion examples/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

require_once __DIR__ . '/../autoload.php';

use Beobles\Core\View\Engine;
use Core\View\Engine;

// Criar engine
$engine = new Engine([
Expand Down
2 changes: 1 addition & 1 deletion src/Core/View/Abstract/AbstractDirective.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

namespace Beobles\Core\View\Abstract;
namespace Core\View\Abstract;

abstract class AbstractDirective
{
Expand Down
2 changes: 1 addition & 1 deletion src/Core/View/Abstract/AbstractFilter.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

namespace Beobles\Core\View\Abstract;
namespace Core\View\Abstract;

abstract class AbstractFilter
{
Expand Down
2 changes: 1 addition & 1 deletion src/Core/View/Abstract/AbstractMiddleware.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

namespace Beobles\Core\View\Abstract;
namespace Core\View\Abstract;

abstract class AbstractMiddleware
{
Expand Down
6 changes: 3 additions & 3 deletions src/Core/View/Abstract/AbstractNode.php
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<?php

namespace Beobles\Core\View\Abstract;
namespace Core\View\Abstract;

use Beobles\Core\View\Compiler;
use Beobles\Core\View\Nodes\NodeInterface;
use Core\View\Compiler;
use Core\View\Nodes\NodeInterface;

abstract class AbstractNode implements NodeInterface
{
Expand Down
2 changes: 1 addition & 1 deletion src/Core/View/Cache/CacheInterface.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

namespace Beobles\Core\View\Cache;
namespace Core\View\Cache;

/**
* Interface para adaptadores de cache
Expand Down
5 changes: 3 additions & 2 deletions src/Core/View/Cache/CacheKey.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

namespace Beobles\Core\View\Cache;
namespace Core\View\Cache;

class CacheKey
{
Expand All @@ -11,7 +11,8 @@ public function forTemplate(string $path, array $dependencies = []): string
foreach ($dependencies as $dep) {
$signature .= '|' . $dep;
if (is_file($dep)) {
$signature .= ':' . (string) filemtime($dep);
$mtime = filemtime($dep);
$signature .= ':' . ($mtime !== false ? (string) $mtime : '0');
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/Core/View/Cache/CacheManager.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

namespace Beobles\Core\View\Cache;
namespace Core\View\Cache;

/**
* Gerenciador de cache
Expand Down
2 changes: 1 addition & 1 deletion src/Core/View/Cache/FileCacheAdapter.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

namespace Beobles\Core\View\Cache;
namespace Core\View\Cache;

/**
* Adaptador de cache em arquivo
Expand Down
2 changes: 1 addition & 1 deletion src/Core/View/Cache/FileWatcher.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

namespace Beobles\Core\View\Cache;
namespace Core\View\Cache;

class FileWatcher
{
Expand Down
Loading