Skip to content

Commit 2a347de

Browse files
committed
feat: Add PHPStan configuration and PHPUnit setup
- Introduced phpstan.neon for static analysis with level 8 and specific ignore patterns. - Created phpunit.xml for PHPUnit configuration, including coverage reporting and environment setup. feat: Implement command structure for Cycle ORM - Added BaseCommand class to serve as a foundation for other commands. - Refactored EntityCommand, MigrateCommand, and SchemaCommand to extend BaseCommand, improving code reuse and structure. - Enhanced error handling and validation in commands. fix: Update CycleServiceProvider for better integration - Refined service registration and booting processes. - Improved error handling and logging mechanisms. - Adjusted database and entity configuration retrieval methods. feat: Introduce EnvironmentHelper for environment checks - Added EnvironmentHelper class to streamline environment checks (production, development, testing). feat: Enhance middleware functionality - Updated EntityValidationMiddleware to include entity validation logic. - Improved TransactionMiddleware for better transaction management and error handling. test: Add unit tests for CycleServiceProvider - Implemented tests to verify service registration and configuration validation.
1 parent 6845d9a commit 2a347de

16 files changed

Lines changed: 698 additions & 498 deletions

.github/workflows/ci.yml

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [ main, develop ]
6+
pull_request:
7+
branches: [ main ]
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
13+
strategy:
14+
matrix:
15+
php-version: [8.1, 8.2, 8.3]
16+
17+
steps:
18+
- uses: actions/checkout@v3
19+
20+
- name: Setup PHP
21+
uses: shivammathur/setup-php@v2
22+
with:
23+
php-version: ${{ matrix.php-version }}
24+
extensions: mbstring, xml, ctype, iconv, intl, pdo_sqlite
25+
26+
- name: Cache Composer packages
27+
id: composer-cache
28+
uses: actions/cache@v3
29+
with:
30+
path: vendor
31+
key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }}
32+
restore-keys: |
33+
${{ runner.os }}-php-
34+
35+
- name: Install dependencies
36+
run: composer install --prefer-dist --no-progress
37+
38+
- name: Run PHPStan
39+
run: vendor/bin/phpstan analyse --no-progress
40+
41+
- name: Run PHP CS Fixer
42+
run: vendor/bin/php-cs-fixer fix --dry-run --diff
43+
44+
- name: Run PHPUnit
45+
run: vendor/bin/phpunit --coverage-clover=coverage.xml
46+
47+
- name: Upload coverage to Codecov
48+
uses: codecov/codecov-action@v3
49+
with:
50+
file: ./coverage.xml

.gitignore

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Dependencies
2+
/vendor/
3+
4+
# IDE
5+
.idea/
6+
.vscode/
7+
*.swp
8+
*.swo
9+
10+
# Testing
11+
.phpunit.cache/
12+
coverage-html/
13+
coverage.xml
14+
junit.xml
15+
16+
# Logs
17+
*.log
18+
19+
# Environment
20+
.env
21+
.env.*
22+
!.env.example
23+
24+
# Build artifacts
25+
/build/
26+
/dist/
27+
28+
# OS
29+
.DS_Store
30+
Thumbs.db
31+
32+
# Database
33+
*.sqlite
34+
*.sqlite3

CHANGELOG.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Changelog
2+
3+
All notable changes to `express-php-cycle-orm-extension` will be documented in this file.
4+
5+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7+
8+
## [Unreleased]
9+
10+
### Added
11+
- Initial release of Express-PHP Cycle ORM Extension
12+
- Auto-discovery Service Provider
13+
- CycleMiddleware for automatic ORM injection
14+
- TransactionMiddleware for automatic transaction management
15+
- EntityValidationMiddleware for entity validation
16+
- Console commands for schema management and entity generation
17+
- Comprehensive configuration system
18+
- Performance optimizations for Express-PHP integration
19+
20+
### Security
21+
- Database connection encryption support
22+
- Query audit logging capabilities
23+
- Raw query execution controls
24+
25+
## [1.0.0] - 2025-01-01
26+
27+
### Added
28+
- First stable release
29+
- Full Express-PHP v2.1+ compatibility
30+
- Cycle ORM v2.7+ integration
31+
- Production-ready features

config/CycleConfigValidator.php

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
4+
class CycleConfigValidator
5+
{
6+
public static function validate(array $config): array
7+
{
8+
$errors = [];
9+
10+
// Validar configuração de database
11+
if (!isset($config['database']['default'])) {
12+
$errors[] = 'Missing database.default configuration';
13+
}
14+
15+
$default = $config['database']['default'];
16+
if (!isset($config['database']['connections'][$default])) {
17+
$errors[] = "Default connection '{$default}' not configured";
18+
}
19+
20+
// Validar configuração de entidades
21+
if (!isset($config['entities']['directories']) || empty($config['entities']['directories'])) {
22+
$errors[] = 'At least one entity directory must be configured';
23+
}
24+
25+
// Verificar se diretórios existem
26+
foreach ($config['entities']['directories'] as $dir) {
27+
if (!is_dir($dir)) {
28+
$errors[] = "Entity directory does not exist: {$dir}";
29+
}
30+
}
31+
32+
// Validar migrations directory
33+
$migrationDir = $config['migrations']['directory'];
34+
if (!is_dir($migrationDir) && !is_writable(dirname($migrationDir))) {
35+
$errors[] = "Migration directory is not writable: {$migrationDir}";
36+
}
37+
38+
return $errors;
39+
}
40+
}

config/cycle.php

Lines changed: 101 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,35 @@
11
<?php
22

3+
// Helper functions para compatibilidade
4+
if (!function_exists('env')) {
5+
function env(string $key, $default = null) {
6+
return $_ENV[$key] ?? getenv($key) ?: $default;
7+
}
8+
}
9+
10+
if (!function_exists('app_path')) {
11+
function app_path(string $path = ''): string {
12+
$basePath = dirname(__DIR__, 4); // Assumindo vendor/package/src/config
13+
return $basePath . '/app' . ($path ? '/' . ltrim($path, '/') : '');
14+
}
15+
}
16+
17+
if (!function_exists('database_path')) {
18+
function database_path(string $path = ''): string {
19+
$basePath = dirname(__DIR__, 4);
20+
return $basePath . '/database' . ($path ? '/' . ltrim($path, '/') : '');
21+
}
22+
}
23+
24+
if (!function_exists('config_path')) {
25+
function config_path(string $path = ''): string {
26+
$basePath = dirname(__DIR__, 4);
27+
return $basePath . '/config' . ($path ? '/' . ltrim($path, '/') : '');
28+
}
29+
}
30+
331
return [
4-
// CORREÇÃO: Configuração de database mais completa
32+
// CORREÇÃO: Configuração de database mais robusta
533
'database' => [
634
'default' => env('DB_CONNECTION', 'mysql'),
735
'databases' => [
@@ -15,15 +43,14 @@
1543
'database' => env('DB_DATABASE'),
1644
'username' => env('DB_USERNAME'),
1745
'password' => env('DB_PASSWORD', ''),
18-
'charset' => 'utf8mb4',
19-
'collation' => 'utf8mb4_unicode_ci',
46+
'charset' => env('DB_CHARSET', 'utf8mb4'),
47+
'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'),
2048
'timezone' => env('DB_TIMEZONE', '+00:00'),
2149
'options' => [
2250
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
2351
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
2452
PDO::ATTR_EMULATE_PREPARES => false,
2553
PDO::ATTR_STRINGIFY_FETCHES => false,
26-
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true,
2754
]
2855
],
2956
'postgres' => [
@@ -33,54 +60,100 @@
3360
'database' => env('DB_DATABASE'),
3461
'username' => env('DB_USERNAME'),
3562
'password' => env('DB_PASSWORD', ''),
36-
'charset' => 'utf8',
63+
'charset' => env('DB_CHARSET', 'utf8'),
3764
'timezone' => env('DB_TIMEZONE', 'UTC'),
3865
],
3966
'sqlite' => [
4067
'driver' => 'sqlite',
4168
'database' => env('DB_DATABASE', database_path('database.sqlite')),
42-
'foreign_key_constraints' => true,
69+
'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true),
4370
]
4471
]
4572
],
4673

47-
// CORREÇÃO: Configuração de entidades melhorada
74+
// CORREÇÃO: Configuração de entidades com fallbacks
4875
'entities' => [
4976
'directories' => [
5077
app_path('Models'),
51-
app_path('Entities')
78+
app_path('Entities'),
79+
// Fallback para estrutura alternativa
80+
dirname(__DIR__, 4) . '/src/Models',
5281
],
53-
'namespace' => 'App\\Models'
82+
'namespace' => env('CYCLE_ENTITY_NAMESPACE', 'App\\Models')
5483
],
5584

56-
// CORREÇÃO: Schema com mais opções
85+
// CORREÇÃO: Schema com configurações mais detalhadas
5786
'schema' => [
58-
'cache' => env('CYCLE_SCHEMA_CACHE', true),
59-
'cache_key' => 'cycle_schema',
60-
'auto_sync' => env('CYCLE_AUTO_SYNC', false),
61-
'strict' => env('CYCLE_SCHEMA_STRICT', false),
62-
'warmup' => env('CYCLE_WARMUP', true)
87+
'cache' => (bool) env('CYCLE_SCHEMA_CACHE', true),
88+
'cache_key' => env('CYCLE_CACHE_KEY', 'cycle_schema'),
89+
'auto_sync' => (bool) env('CYCLE_AUTO_SYNC', false),
90+
'strict' => (bool) env('CYCLE_SCHEMA_STRICT', false),
91+
'warmup' => (bool) env('CYCLE_WARMUP', true),
92+
93+
// NOVO: Configurações específicas de schema
94+
'generators' => [
95+
'reset_tables' => true,
96+
'validate_entities' => true,
97+
'render_tables' => true,
98+
'render_relations' => true,
99+
]
63100
],
64101

65-
// CORREÇÃO: Migrations melhoradas
102+
// CORREÇÃO: Migrations com configurações expandidas
66103
'migrations' => [
67-
'directory' => database_path('migrations'),
68-
'table' => 'cycle_migrations',
69-
'safe' => env('CYCLE_SAFE_MIGRATIONS', true),
70-
'auto_run' => env('CYCLE_AUTO_MIGRATE', false)
104+
'directory' => env('CYCLE_MIGRATIONS_PATH', database_path('migrations')),
105+
'table' => env('CYCLE_MIGRATIONS_TABLE', 'cycle_migrations'),
106+
'namespace' => env('CYCLE_MIGRATIONS_NAMESPACE', 'Database\\Migrations'),
107+
'safe' => (bool) env('CYCLE_SAFE_MIGRATIONS', true),
108+
'auto_run' => (bool) env('CYCLE_AUTO_MIGRATE', false)
71109
],
72110

73-
// NOVO: Performance settings
111+
// NOVO: Performance settings expandidas
74112
'performance' => [
75-
'query_cache' => env('CYCLE_QUERY_CACHE', false),
76-
'lazy_loading' => env('CYCLE_LAZY_LOADING', true),
77-
'collection_factory' => 'array'
113+
'query_cache' => (bool) env('CYCLE_QUERY_CACHE', false),
114+
'lazy_loading' => (bool) env('CYCLE_LAZY_LOADING', true),
115+
'collection_factory' => env('CYCLE_COLLECTION_FACTORY', 'array'),
116+
'preload_relations' => (bool) env('CYCLE_PRELOAD_RELATIONS', false),
117+
118+
// Connection pooling
119+
'connection_pool' => [
120+
'min_connections' => (int) env('CYCLE_MIN_CONNECTIONS', 1),
121+
'max_connections' => (int) env('CYCLE_MAX_CONNECTIONS', 10),
122+
'idle_timeout' => (int) env('CYCLE_IDLE_TIMEOUT', 60),
123+
]
78124
],
79125

80-
// NOVO: Development settings
126+
// NOVO: Development settings expandidas
81127
'development' => [
82-
'log_queries' => env('CYCLE_LOG_QUERIES', false),
128+
'log_queries' => (bool) env('CYCLE_LOG_QUERIES', false),
83129
'slow_query_threshold' => (int) env('CYCLE_SLOW_QUERY_MS', 100),
84-
'debug_mode' => env('CYCLE_DEBUG', false)
130+
'debug_mode' => (bool) env('CYCLE_DEBUG', false),
131+
'profile_queries' => (bool) env('CYCLE_PROFILE_QUERIES', false),
132+
133+
// Schema validation
134+
'validate_schema_on_boot' => (bool) env('CYCLE_VALIDATE_SCHEMA', false),
135+
'schema_validation_strict' => (bool) env('CYCLE_SCHEMA_VALIDATION_STRICT', false),
136+
],
137+
138+
// NOVO: Security settings
139+
'security' => [
140+
'encrypt_connection' => (bool) env('DB_ENCRYPT', false),
141+
'verify_ssl' => (bool) env('DB_VERIFY_SSL', true),
142+
'connection_timeout' => (int) env('DB_TIMEOUT', 30),
143+
144+
// Query security
145+
'disable_raw_queries' => (bool) env('CYCLE_DISABLE_RAW_QUERIES', false),
146+
'audit_queries' => (bool) env('CYCLE_AUDIT_QUERIES', false),
147+
],
148+
149+
// NOVO: Monitoring and observability
150+
'monitoring' => [
151+
'metrics_enabled' => (bool) env('CYCLE_METRICS_ENABLED', false),
152+
'slow_query_log' => (bool) env('CYCLE_SLOW_QUERY_LOG', false),
153+
'query_stats' => (bool) env('CYCLE_QUERY_STATS', false),
154+
155+
// Health checks
156+
'health_check_enabled' => (bool) env('CYCLE_HEALTH_CHECK', true),
157+
'health_check_interval' => (int) env('CYCLE_HEALTH_CHECK_INTERVAL', 300),
85158
]
86-
];
159+
];

phpstan.neon

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
parameters:
2+
level: 8
3+
paths:
4+
- src
5+
- tests
6+
excludePaths:
7+
- tests/Fixtures
8+
ignoreErrors:
9+
- '#Call to an undefined method Express\\.*#'
10+
- '#Access to an undefined property Express\\.*#'
11+
- '#Class Express\\.*not found#'
12+
13+
checkMissingIterableValueType: false
14+
checkGenericClassInNonGenericObjectType: false
15+
16+
# Express-PHP specific ignores
17+
universalObjectCratesClasses:
18+
- Express\Http\Request
19+
- Express\Http\Response
20+
- Express\Core\Application

0 commit comments

Comments
 (0)