janisbiz / light-orm
Light ORM for database integrations
Requires
- php: >=7.1
- ext-pdo: *
- janisbiz/heredoc: ^1.0
- psr/log: ^1.0
Requires (Dev)
- behat/behat: ^3.0
- friendsofphp/php-cs-fixer: ^2.0
- infection/infection: ^0.13
- jakub-onderka/php-parallel-lint: ^1.0
- matthiasnoback/behat-local-code-coverage-extension: ^0.3
- monolog/monolog: ^1.0
- phpcompatibility/php-compatibility: ^9.0
- phpmd/phpmd: ^2.0
- phpro/grumphp: ^0.15.0
- phpstan/phpstan: ^0.11
- phpunit/php-code-coverage: ^6.0
- phpunit/phpcov: ^5.0
- phpunit/phpunit: ^7.0
- squizlabs/php_codesniffer: ^3.0
- symfony/var-dumper: ^4.0
- symfony/yaml: ^4.0
README
A light ORM for php with easy to use query builder, repository generator and connection pool manager.
Installing
composer require janisbiz/light-orm
About
light-orm has been used for a while in some of my work related projects. As it was growing, I decided to open-source it for the rest of community. It has good unit test coverage and a great support for integration testing together with desired DMS using Behat.
Currently these DMS are supported:
- MySQL
There is still a lot work to do, so it would be great to have some contributors for future improvements
Examples
Connection pool
Connection pool is a singleton (yes I know...), which holds all the DMS connections used by ORM. To set-up connection pool you need to create a config for your DMS. Afterwards, you can add this config to connection pool, and it will establish connection to server only when it is required. To set-up connection pool, see example below:
<?php declare(strict_types=1); use Janisbiz\LightOrm\Dms\MySQL\Connection\ConnectionConfigUrl as MySQLConnectionConfigUrl; $databaseName = 'light_orm_mysql'; $mysqlConnectionConfig = new MySQLConnectionConfigUrl( \sprintf('mysql://root:password@mysql/%s', $databaseName) ); $connectionPool = (new ConnectionPool())->addConnectionConfig($mysqlConnectionConfig);
Generator
Generator is built in repository and entity class generator. With generator, it is possible to make ORM easy to use. To use generator, you need to have pre-configured connection pool or one connection. To configure generator, see example below:
<?php declare(strict_types=1); $directoryPersistent = \implode( '', [ __DIR__, DIRECTORY_SEPARATOR, '..', DIRECTORY_SEPARATOR, 'tests', DIRECTORY_SEPARATOR, 'Behat', DIRECTORY_SEPARATOR, 'Bootstrap', DIRECTORY_SEPARATOR, 'Generated' ] ); $directoryNonPersistent = \implode( '', [ __DIR__, DIRECTORY_SEPARATOR, '..', DIRECTORY_SEPARATOR, 'var', DIRECTORY_SEPARATOR, 'light-orm', DIRECTORY_SEPARATOR, 'Generated' ] ); $namespacePersistent = 'Janisbiz\LightOrm\Tests\Behat\Generated'; $namespaceNonPersistent = 'Janisbiz\LightOrm\Variable\Generated'; $baseEntityClassWriter = new BaseEntityClassWriter(new WriterConfig( $directoryNonPersistent, $namespaceNonPersistent, 'Base' )); $entityClassWriter = new EntityClassWriter( new WriterConfig( $directoryPersistent, $namespacePersistent, '', 'Entity' ), $baseEntityClassWriter ); $repositoryClassWriter = new RepositoryClassWriter( new WriterConfig( $directoryPersistent, $namespacePersistent, '', 'Repository' ), $entityClassWriter ); (new Generator(new DmsFactory())) ->addWriter($baseEntityClassWriter) ->addWriter($entityClassWriter) ->addWriter($repositoryClassWriter) ->generate($connectionPool->getConnection($databaseName), $databaseName) ;
Repository & Query Builder
Repository is place where you can call query builder and then execute it against your configured DMS. Repository supports all basic CRUD actions against DMS, as well, it has built in paginator for result set pagination and result set count. To use query builder on repository, please see example below:
<?php declare(strict_types=1); namespace Janisbiz\LightOrm\Tests\Behat\Bootstrap\Generated\LightOrmMysql\Repository; use Janisbiz\LightOrm\Dms\MySQL\Enum\KeywordEnum; use Janisbiz\LightOrm\Dms\MySQL\QueryBuilder\QueryBuilderInterface; use Janisbiz\LightOrm\Dms\MySQL\Repository\AbstractRepository; use Janisbiz\LightOrm\Tests\Behat\Bootstrap\Generated\LightOrmMysql\Entity\TestTableOneEntity; use Janisbiz\LightOrm\Tests\Behat\Bootstrap\Generated\LightOrmMysql\Entity\TestTableOneTwoEntity; use Janisbiz\LightOrm\Tests\Behat\Bootstrap\Generated\LightOrmMysql\Entity\TestTableTwoEntity; class TestTableOneRepository extends AbstractRepository { /** * @param null|int $id * @param int $intColNotNull * @param string $varcharColNotNull * @param float $floatColNotNull * @param null|int $intColNull * @param null|string $varcharColNull * @param null|float $floatColNull * @param null|string $createdAt * @param null|string $updatedAt * * @return TestTableOneEntity */ public function create( ?int $id, int $intColNotNull, string $varcharColNotNull, float $floatColNotNull, ?int $intColNull = null, ?string $varcharColNull = null, ?float $floatColNull = null, ?string $createdAt = null, ?string $updatedAt = null ) { $testTableOneEntity = (new TestTableOneEntity()) ->setId($id) ->setIntColNotNull($intColNotNull) ->setVarcharColNotNull($varcharColNotNull) ->setFloatColNotNull($floatColNotNull) ->setIntColNull($intColNull) ->setVarcharColNull($varcharColNull) ->setFloatColNull($floatColNull) ->setCreatedAt($createdAt) ->setUpdatedAt($updatedAt) ; $this ->createQueryBuilder($testTableOneEntity) ->insert() ; return $testTableOneEntity; } /** * @return TestTableOneEntity[] */ public function readWithAllQueryParts() { return $this->readWithAllQueryPartsQuery()->find(); } /** * @return int */ public function readCountWithAllQueryParts() { return $this->readWithAllQueryPartsQuery()->count(); } /** * @param int $pageSize * @param int $currentPage * * @return TestTableOneEntity[] */ public function createPaginator($pageSize, $currentPage) { return $this->paginator($this->createQueryBuilder(), (int) $pageSize, (int) $currentPage); } /** * @param int $id * @param int $intColNotNull * @param string $varcharColNotNull * @param float $floatColNotNull * @param null|int $intColNull * @param null|string $varcharColNull * @param null|float $floatColNull * @param null|string $createdAt * @param null|string $updatedAt * * @return TestTableOneEntity */ public function updateRow( $id, $varcharColNotNull, $varcharColNull = null, $updatedAt = null ) { $testTableOneEntity = $this ->createQueryBuilder() ->where( 'test_table_one.id = :id', [ 'id' => $id, ] ) ->findOne() ; $testTableOneEntity ->setVarcharColNotNull($varcharColNotNull) ->setVarcharColNull($varcharColNull) ->setUpdatedAt($updatedAt) ; return $this->createQueryBuilder($testTableOneEntity)->update(); } /** * @param TestTableOneEntity $testTableOneEntity */ public function deleteEntity(TestTableOneEntity $testTableOneEntity) { $this->createQueryBuilder($testTableOneEntity)->delete(); } /** * @return QueryBuilderInterface */ private function readWithAllQueryPartsQuery() { return $this ->createQueryBuilder() ->column('test_table_two.id AS test_table_two_id') ->innerJoin(TestTableOneTwoEntity::TABLE_NAME, 'test_table_one_two.test_table_one_id = test_table_one.id') ->innerJoin(TestTableTwoEntity::TABLE_NAME, 'test_table_two.id = test_table_one_two.test_table_two_id') ->where('test_table_one.id != :id', ['id' => 1]) ->whereIn( 'test_table_one.id', [ 2, 3, 4, 5 ] ) ->whereNotIn( 'test_table_one.id', [ 6, 7, 8, 9, 10 ] ) ->groupBy('test_table_one.id') ->having('test_table_one.id != :havingId', ['havingId' => 3]) ->orderBy('test_table_one.id', KeywordEnum::ASC) ->limit(1) ->offset(1) ; } /** * @return string */ protected function getEntityClass(): string { return TestTableOneEntity::class; } }
More examples?
To see full power of light-orm, please see test cases:
- For connection handling, see Connection Feature
- For generator handling(MySQL), see MySQL Generator Feature
- For repository handling(MySQL), see MySQL Repository Feature and generated repositories with respective entity classes
Running tests
There are two ways to run tests:
- By using docker containers:
- Copy
.env.dist
to.env
and adjust defined values for your needs - Execute
make start_dev
- Execute
make test
- Copy
- By using your local php and mysql database environment:
- Ensure, that your php version is
7.1+
- Execute
composer install
- Execute
vendor/bin/phpcs --standard=phpcs.xml -p ./src -p ./tests; vendor/bin/phpunit; vendor/bin/behat;
- Ensure, that your php version is
TODO
- Add support for other DMS than MySQL (preferably - Postgres)
- Add migration support
- Add event dispatcher