diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml new file mode 100644 index 0000000..26c5802 --- /dev/null +++ b/.github/workflows/continuous-integration.yml @@ -0,0 +1,11 @@ +name: "Continuous Integration" + +on: + pull_request: + push: + branches: + tags: + +jobs: + ci: + uses: laminas/workflow-continuous-integration/.github/workflows/continuous-integration.yml@1.x diff --git a/.github/workflows/docs-build.yml b/.github/workflows/docs-build.yml new file mode 100644 index 0000000..1a7aa24 --- /dev/null +++ b/.github/workflows/docs-build.yml @@ -0,0 +1,16 @@ +name: docs-build + +on: + release: + types: [published] + workflow_dispatch: + +jobs: + build-deploy: + runs-on: ubuntu-latest + steps: + - name: Build Docs + uses: dotkernel/documentation-theme/github-actions/docs@main + env: + DEPLOY_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml new file mode 100644 index 0000000..8d71114 --- /dev/null +++ b/.github/workflows/static-analysis.yml @@ -0,0 +1,50 @@ +on: + - push + +name: Run PHPStan checks + +jobs: + mutation: + name: PHPStan ${{ matrix.php }}-${{ matrix.os }} + + runs-on: ${{ matrix.os }} + + strategy: + matrix: + os: + - ubuntu-latest + + php: + - "8.2" + - "8.3" + - "8.4" + - "8.5" + + steps: + - name: Checkout + uses: actions/checkout@v5 + + - name: Install PHP + uses: shivammathur/setup-php@v2 + with: + php-version: "${{ matrix.php }}" + coverage: pcov + ini-values: assert.exception=1, zend.assertions=1, error_reporting=-1, log_errors_max_len=0, display_errors=On + tools: composer:v2, cs2pr + + - name: Determine composer cache directory + run: echo "COMPOSER_CACHE_DIR=$(composer config cache-dir)" >> $GITHUB_ENV + + - name: Cache dependencies installed with composer + uses: actions/cache@v4 + with: + path: ${{ env.COMPOSER_CACHE_DIR }} + key: php${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }} + restore-keys: | + php${{ matrix.php }}-composer- + + - name: Install dependencies with composer + run: composer install --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi + + - name: Run static analysis with PHPStan + run: vendor/bin/phpstan analyse diff --git a/README.md b/README.md index 4e4f9d2..a102057 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,9 @@ # tutorial-101 + Book tutorial starting from Dotkernel Light: Level 101 beginner -### BRANCH : - main unde e documentatia , se compileaza documentatia. aplicatie din light, deploy functional !!!! --> 101.dotkernel.net +## BRANCH : - main unde e documentatia , se compileaza documentatia. aplicatie din light, deploy functional !!!! --> 101.dotkernel.net + 1. instalezi light la tine pe WSL2 2. iei chapter 1, citesti documentation, implementezi una cite una - CHAPTER-1-doctrine # protected - including Light, and add visible DIFF between branches @@ -12,5 +14,3 @@ Book tutorial starting from Dotkernel Light: Level 101 beginner main: incepi de la light , clone - adaigi folderul docs/book cu structura asta https://github.com/dotkernel/dot-session/tree/5.0/docs/book - cu fisier symlink si etc. - - diff --git a/docs/book/chapter-1.md b/docs/book/chapter-1.md deleted file mode 100644 index c6cb65f..0000000 --- a/docs/book/chapter-1.md +++ /dev/null @@ -1,312 +0,0 @@ -# Installing Doctrine - -## Composer Requirements - -The first step is to add alongside your current packages the required entries for our Doctrine installation. We would add the following to our `composer.json` file located in our root folder: - -```json -{ - "require": { - "dotkernel/dot-cache": "^4.0", - "ramsey/uuid": "^4.5.0", - "ramsey/uuid-doctrine": "^2.1.0", - "roave/psr-container-doctrine": "^5.2.2" - }, - "require-dev": { - "phpstan/phpstan-doctrine": "^2.0.3" - } -} -``` - -`dotkernel/dot-cache` - -Provides caching support for DotKernel applications. -It offers a PSR-6 and PSR-16 compatible caching system that integrates smoothly with DotKernel's service container. - -`ramsey/uuid` - -A widely used PHP library for generating and working with UUIDs (Universally Unique Identifiers). -It supports multiple UUID versions. - -`ramsey/uuid-doctrine` - -Adds UUID support to Doctrine ORM using ramsey/uuid. -It allows Doctrine to store and retrieve UUIDs as proper value objects instead of plain strings, improving type safety. - -`roave/psr-container-doctrine` - -Provides a set of factory classes that integrate Doctrine ORM with any PSR-11 container. -It simplifies wiring Doctrine EntityManager, DBAL, configuration, and related services in frameworks like DotKernel. - -`phpstan/phpstan-doctrine (dev requirement)` - -An extension for PHPStan that improves static analysis for Doctrine. -It understands entity metadata, repositories, and common Doctrine patterns, helping catch errors during development. - -## Setting Up Doctrine - -After successfully installing our dependencies we now need to configure our Doctrine instance. - -### Declare your database - -In the file `config/autoload/local.php`: - -```php -$databases = [ - 'default' => [ - 'host' => 'localhost', - 'dbname' => 'light', - 'user' => 'root', - 'password' => '123', - 'port' => 3306, - 'driver' => 'pdo_mysql', - 'charset' => 'utf8mb4', - 'collate' => 'utf8mb4_general_ci', - ], - // you can add more database connections into this array -]; - -return [ - 'databases' => $databases, - //the rest of your configuration variables -]; -``` - -### Declare the Doctrine Drivers and Migrations Location - -With the very nice utility of the package `laminas/laminas-config-aggregator` we can declare our doctrine settings in the `src/App/src/ConfigProvider.php` file. -This package takes all the provided configs from the `config/config.php` file and merges them into one. - -Our new `src/App/src/ConfigProvider.php` class would look like this now: - -```php -, - * templates: array, - * } - */ - public function __invoke(): array - { - return [ - 'dependencies' => $this->getDependencies(), - 'doctrine' => $this->getDoctrineConfig(), - 'templates' => $this->getTemplates(), - ]; - } - - /** - * @return array{ - * delegators: array>, - * factories: array, - * } - */ - public function getDependencies(): array - { - return [ - 'delegators' => [ - Application::class => [ - RoutesDelegator::class, - ], - ], - 'factories' => [ - 'doctrine.entity_manager.orm_default' => EntityManagerFactory::class, - GetIndexViewHandler::class => GetIndexViewHandlerFactory::class, - ], - 'aliases' => [ - EntityManager::class => 'doctrine.entity_manager.orm_default', - EntityManagerInterface::class => 'doctrine.entity_manager.orm_default', - ], - ]; - } - - /** - * @return array{ - * paths: array{ - * app: array{literal-string&non-falsy-string}, - * error: array{literal-string&non-falsy-string}, - * layout: array{literal-string&non-falsy-string}, - * partial: array{literal-string&non-falsy-string}, - * } - * } - */ - public function getTemplates(): array - { - return [ - 'paths' => [ - 'app' => [__DIR__ . '/../templates/app'], - 'error' => [__DIR__ . '/../templates/error'], - 'layout' => [__DIR__ . '/../templates/layout'], - 'partial' => [__DIR__ . '/../templates/partial'], - ], - ]; - } - - private function getDoctrineConfig(): array - { - return [ - 'cache' => [ - 'array' => [ - 'class' => ArrayAdapter::class, - ], - 'filesystem' => [ - 'class' => FilesystemAdapter::class, - 'directory' => getcwd() . '/data/cache', - 'namespace' => 'doctrine', - ], - ], - 'configuration' => [ - 'orm_default' => [ - 'result_cache' => 'filesystem', - 'metadata_cache' => 'filesystem', - 'query_cache' => 'filesystem', - 'hydration_cache' => 'array', - 'typed_field_mapper' => null, - 'second_level_cache' => [ - 'enabled' => true, - 'default_lifetime' => 3600, - 'default_lock_lifetime' => 60, - 'file_lock_region_directory' => '', - 'regions' => [], - ], - ], - ], - 'connection' => [ - 'orm_default' => [ - 'doctrine_mapping_types' => [ - UuidBinaryType::NAME => 'binary', - UuidBinaryOrderedTimeType::NAME => 'binary', - ], - ], - ], - 'driver' => [ - // The default metadata driver aggregates all other drivers into a single one. - // Override `orm_default` only if you know what you're doing. - 'orm_default' => [ - 'class' => MappingDriverChain::class, - ], - ], - 'migrations' => [ - // Modify this line based on where you would like to have you migrations - 'migrations_paths' => [ - 'Migrations' => 'src/Migrations', - ], - 'all_or_nothing' => true, - 'check_database_platform' => true, - ], - 'types' => [ - UuidType::NAME => UuidType::class, - UuidBinaryType::NAME => UuidBinaryType::class, - UuidBinaryOrderedTimeType::NAME => UuidBinaryOrderedTimeType::class, - ], - ]; - } -} - -``` - -We also require a new file `config/cli-config.php`. -It initializes and returns a `DependencyFactory` that Doctrine Migrations uses to run migrations. - -```php -get(EntityManager::class); -$entityManager->getEventManager(); - -return DependencyFactory::fromEntityManager( - new ConfigurationArray($container->get('config')['doctrine']['migrations']), - new ExistingEntityManager($entityManager) -); -``` - -## Running doctrine - -Now that everything has been configured we only need to do one last thing, to create an executable for the Doctrine CLI. -In our case we will create it as `/bin/doctrine` - -```php -#!/usr/bin/env php -get(EntityManager::class); -$entityManager->getEventManager(); - -ConsoleRunner::run(new SingleManagerProvider($entityManager)); -``` - -(Optional) To keep things tidy we recommend to make an executable for the migrations of Doctrine as well for example `/bin/doctrine-migrations`: - -```php -#!/usr/bin/env php - [ + 'host' => 'localhost', + 'dbname' => 'light', + 'user' => 'root', + 'password' => '123', + 'port' => 3306, + 'driver' => 'pdo_mysql', + 'charset' => 'utf8mb4', + 'collate' => 'utf8mb4_general_ci', + ], + // you can add more database connections into this array +]; + +return [ + 'databases' => $databases, + 'doctrine' => [ + 'connection' => [ + 'orm_default' => [ + 'params' => $databases['default'], + ], + ], + ], + // the rest of your configuration +]; +``` + +### Declare the Doctrine Drivers and Migrations Location + +With the very nice utility of the package `laminas/laminas-config-aggregator` we can declare our doctrine settings in the `src/App/src/ConfigProvider.php` file. +This package takes all the provided configs from the `config/config.php` file and merges them into one. + +Our new `src/App/src/ConfigProvider.php` class would look like this now: + +![Config provider factories update](images/config-provider-1.png) +![Doctrine config function](images/config-provider-2.png) + +```php +public function __invoke(): array +{ + return [ + 'dependencies' => $this->getDependencies(), + 'doctrine' => $this->getDoctrineConfig(), + 'templates' => $this->getTemplates(), + ]; +} + +public function getDependencies(): array +{ + return [ + 'delegators' => [ + Application::class => [ + RoutesDelegator::class, + ], + ], + 'factories' => [ + 'doctrine.entity_manager.orm_default' => EntityManagerFactory::class, + GetIndexViewHandler::class => GetIndexViewHandlerFactory::class, + ], + 'aliases' => [ + EntityManager::class => 'doctrine.entity_manager.orm_default', + EntityManagerInterface::class => 'doctrine.entity_manager.orm_default', + ], + ]; +} + +private function getDoctrineConfig(): array +{ + return [ + 'cache' => [ + 'array' => [ + 'class' => ArrayAdapter::class, + ], + 'filesystem' => [ + 'class' => FilesystemAdapter::class, + 'directory' => getcwd() . '/data/cache', + 'namespace' => 'doctrine', + ], + ], + 'configuration' => [ + 'orm_default' => [ + 'result_cache' => 'filesystem', + 'metadata_cache' => 'filesystem', + 'query_cache' => 'filesystem', + 'hydration_cache' => 'array', + 'typed_field_mapper' => null, + 'second_level_cache' => [ + 'enabled' => true, + 'default_lifetime' => 3600, + 'default_lock_lifetime' => 60, + 'file_lock_region_directory' => '', + 'regions' => [], + ], + ], + ], + 'driver' => [ + // The default metadata driver aggregates all other drivers into a single one. + // Override `orm_default` only if you know what you're doing. + 'orm_default' => [ + 'class' => MappingDriverChain::class, + ], + ], + 'migrations' => [ + // Modify this line based on where you would like to have you migrations + 'migrations_paths' => [ + 'Migrations' => 'src/Migrations', + ], + 'all_or_nothing' => true, + 'check_database_platform' => true, + ], + 'types' => [ + UuidType::NAME => UuidType::class, + ], + ]; +} +``` + +We also require a new file `config/cli-config.php`. +It initializes and returns a `DependencyFactory` that Doctrine Migrations uses to run migrations. + +![cli-config](images/cli-config.png) + +```php +get(EntityManager::class); +$entityManager->getEventManager(); + +return DependencyFactory::fromEntityManager( + new ConfigurationArray($container->get('config')['doctrine']['migrations']), + new ExistingEntityManager($entityManager) +); +``` + +## Running doctrine + +Now that everything has been configured we only need to do one last thing, to create an executable for the Doctrine CLI. +In our case we will create a `doctrine` file inside the application's `bin` directory: + +![bin/doctrine](images/doctrine.png) + +```php +#!/usr/bin/env php +get(EntityManager::class); +$entityManager->getEventManager(); + +ConsoleRunner::run(new SingleManagerProvider($entityManager)); +``` + +(Optional) To keep things tidy, we recommend making an executable for the migrations of Doctrine as well. +For this, we create `doctrine-migrations` file inside the application's `bin` directory: + +![bin/doctrine-migrations](images/doctrine-migrations.png) + +```php +#!/usr/bin/env php +