eureka/component-orm

6.0.2 2024-04-24 12:20 UTC

README

Current version Supported PHP version CI Quality Gate Status Coverage

PHP简单ORM

Composer

要将此ORM添加到您的项目中,可以使用以下命令

~/path/to/your/project/$ composer require "eureka/component-orm"

您可以使用以下命令安装组件(用于测试)

make install

更新

您可以使用以下命令更新组件(用于测试)

make update

配置

如果您正在使用Symfony依赖注入和Yaml配置,您可以使用以下方式配置ORM

主orm.yaml配置

parameters:

    #~ Comment part
    orm.comment.author:    'Eureka Orm Generator'
    orm.comment.copyright: 'My Copyright name'

    #~ Namespace base config
    orm.base_namespace.entity:     'Application\Domain' # Base namespace for entities
    orm.base_namespace.mapper:     'Application\Domain' # Base namespace for mapper (repository interface implementation)
    orm.base_namespace.repository: 'Application\Domain' # Base namespace for repository interfaces

    #~ Path base config
    orm.base_path.entity:     '%kernel.directory.root%/src/Domain' # Base path for entities
    orm.base_path.mapper:     '%kernel.directory.root%/src/Domain' # Base path for mapper (repository interface implementation)
    orm.base_path.repository: '%kernel.directory.root%/src/Domain' # Base namespace for repository interfaces

    #~ Cache base config
    orm.cache.enabled: false                  # Define globally if cache is enable or not
    orm.cache.prefix: 'website.magiclegacy.'  # Cache prefix for application database data

    #~ Validation - /!\ Require "eureka/component-validation" when validation is enabled
    orm.validation.enabled: true              # false: no validation of value in entities setter
    orm.validation.auto: true                 # set true to generate auto validation regarding tables columns definitions

    #~ Define list of available config.
    # Alias name will be used in "joins" config part
    orm.configs:
        #~ Usage
        #alias: '%orm.config.{name}%'
        #~ Core website
        user:                 '%orm.config.user%'

        #~ Core Blog
        blog_post:     '%orm.config.blog_post%'
        blog_category: '%orm.config.blog_category%'
        blog_tag:      '%orm.config.blog_tag%'
        blog_post_tag: '%orm.config.blog_post_tag%'

示例yaml配置

# ORM Config file
parameters:

    orm.config.user:
        #~ Some meta data for phpdoc block comments
        comment:
            author:    '%orm.comment.author%'
            copyright: '%orm.comment.copyright%'

        #~ Namespace for generated files
        namespace:
            entity:     '%orm.base_namespace.entity%\User\Entity'
            mapper:     '%orm.base_namespace.mapper%\User\Infrastructure\Mapper'
            repository: '%orm.base_namespace.repository%\User\Repository'

        #~ Path for generated files
        path:
            entity:     '%orm.base_path.entity%/User/Entity'
            mapper:     '%orm.base_path.mapper%/User/Infrastructure/Mapper'
            repository: '%orm.base_path.repository%/User/Repository'
    
        #~ Cache configuration for this table 
        cache:
            enabled:    '%orm.cache.enabled%'
            prefix:     '%orm.cache.prefix%user'

        #~ Table config
        database:
            table:      'user' # Name of the table
            prefix:     'user' # Fields prefix to remove in generated method. (Field user_id will have getId() method with this example)

        class:
            classname: 'User' # Name of the class (Do not set namespace here)

        #~ List of join configuration for "eager or lazy loading"
        joins:
            UserPosts:                   # Suffix name for setter/getter (here: getAllUserPosts() / setAllUserPosts())
                eager_loading: false     # set to true to allow eager loading
                config:   'blog_post'    # config alias name (see orm.yaml > "orm.configs" part)
                relation: 'many'         # one: Return unique entity | many: return list of all found entities 
                type:     'inner'        # inner, left, right
                keys:
                    user_id: true        # key(s) for join. set "true" when column name is same in both table

            UserAddress:                 # Suffix name for setter/getter (here: getUserAddress() / setUserAddress())
                eager_loading: true      # set to true to allow eager loading
                config:   'user_address' # config alias name (see orm.yaml > "orm.configs" part)
                relation: 'one'          # one: Return unique entity | many: return list of all found entities 
                type:     'inner'        # inner, left, right
                keys:
                    user_id: user_id     # You also can mapping name (useful when name differ in both table)

        #~ Validation configuration 
        # /!\ Require "eureka/component-validation" when validation is enabled
        validation:
            enabled: '%orm.validation.enabled%'
            auto:    '%orm.validation.auto%'

            #~ Optional
            extended_validation:
                #~ Define or override validation config for some field if needed
                #~ Example
                user_name:
                    #type: string - optional when auto validation is enabled

                    #~ options values are merged with auto validation values.
                    #~ If any value is already defined with auto validation, this value override auto validation value
                    options:
                        min_length: 5

生成器

您必须使用以下命令生成所有ORM文件

~/path/to/your/project/$ bin/console Orm/Script/Generator

/!\ 此命令需要安装"eureka/component-console"并确保您的应用程序中有bin/console脚本(带有kernel-console)

实体

实体是表数据的“反射”。从数据库检索数据时,每个实体都是相应表的一行的表示。

实体不应该直接实例化。要获取新的实体,您应该使用以下映射方法

/** @var \Symfony\Component\DependencyInjection\Container $container */
$postRepository = $container->get('post.mapper');
/** @var \Application\Domain\Blog\Infrastructure\Mapper\PostMapper $postRepository */
$post = $postRepository->newEntity();

映射器

当您需要从数据库检索数据时,您必须在映射器中添加一个方法来检索数据,通常以findfindAll(根据检索一个还是多个实体)为前缀。

映射器示例

检索10篇最新的博客文章(作为实体)

<?php

/*
 * Copyright (c) Romain Cottard
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

declare(strict_types=1);

namespace Application\Domain\Blog\Infrastructure\Mapper;

use Application\Domain\Blog\Entity\Post;
use Application\Domain\Blog\Repository\PostRepositoryInterface;
use Eureka\Component\Orm\EntityInterface;
use Eureka\Component\Orm\Exception\EntityNotExistsException;
use Eureka\Component\Orm\Exception\InvalidQueryException;
use Eureka\Component\Orm\Exception\OrmException;
use Eureka\Component\Orm\Query\SelectBuilder;

/**
 * Mapper class for table "blog_post"
 *
 * @author Eureka Orm Generator
 */
class PostMapper extends Abstracts\AbstractPostMapper implements PostRepositoryInterface
{
    /**
     * @param int $number
     * @return Post[]
     * @throws InvalidQueryException
     * @throws OrmException
     */
    public function findLatest(int $number = 10): iterable
    {
        //~ Create new query builder (for select)
        $queryBuilder = new SelectBuilder($this);

        //~ Add some restriction
        $queryBuilder->addWhere('blog_post_status', 3);

        //~ Ordering results
        $queryBuilder->addOrder('blog_post_id', 'DESC');

        //~ Limit number of results
        $queryBuilder->setLimit($number);

        //~ select result & return result
        return $this->select($queryBuilder);
    }

    /**
     * @param int $postId
     * @return Post[]
     * @throws OrmException
     */
    public function findPostWithUser(int $postId): iterable
    {
        //~ Create new query builder (for select)
        $queryBuilder = new SelectBuilder($this);

        //~ Add some restriction
        $queryBuilder->addWhere('blog_post_id', $postId);

        //~ Use eager loading to load user attach with Post (join only on user is this example)
        return $this->selectJoin($queryBuilder, ['user']);
    }

    /**
     * @return Post|EntityInterface
     * @throws EntityNotExistsException  
     * @throws OrmException
     */
    public function findLast(): Post
    {
        //~ Create new query builder (for select)
        $queryBuilder = new SelectBuilder($this);

        //~ Add some restriction
        $queryBuilder->addWhere('blog_post_status', 3);

        //~ Ordering results
        $queryBuilder->addOrder('blog_post_id', 'DESC');

        //~ When use selectOne(), not found entity will throw an EntityNotExistsException
        return $this->selectOne($queryBuilder);
    }
}

存储库

为了将存储库作为驱动设计领域(DDD)的表示,ORM生成存储库接口,应在您的应用程序中使用这些接口来签名方法。实际的实现是映射器。

存储库示例

这里,这是一个与上述实现对应的存储库接口的示例。

<?php

/*
 * Copyright (c) Romain Cottard
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Application\Domain\Blog\Repository;

use Application\Domain\Blog\Entity\Post;
use Eureka\Component\Orm\EntityInterface;
use Eureka\Component\Orm\Exception\EntityNotExistsException;
use Eureka\Component\Orm\Exception\InvalidQueryException;
use Eureka\Component\Orm\Exception\OrmException;
use Eureka\Component\Orm\RepositoryInterface;

/**
 * Post repository interface.
 *
 * @author Eureka Orm Generator
 */
interface PostRepositoryInterface extends RepositoryInterface
{
    /**
     * @param int $number
     * @return Post[]
     * @throws InvalidQueryException
     * @throws OrmException
     */
    public function findLatest(int $number = 10): iterable;

    /**
     * @param int $postId
     * @return Post[]
     * @throws OrmException
     */
    public function findPostWithUser(int $postId): iterable;

    /**
     * @return Post|EntityInterface
     * @throws EntityNotExistsException  
     * @throws OrmException
     */
    public function findLast(): Post;
}

测试和CI(持续集成)

您可以使用以下命令在您的本地运行测试

make tests   # run tests with coverage
make testdox # run tests without coverage reports but with prettified output

您还可以使用以下命令运行代码风格检查或修复

make phpcs   # run checks on check style
make phpcbf  # run check style auto fix

要执行代码的静态分析(使用phpstan,默认为级别9),可以使用以下命令

make phpstan
make analyze # Same as phpstan but with CLI output as table

为了确保您的代码与当前支持的PHP版本和未来版本兼容,您需要运行以下命令(两者都是全面支持所必需的)

make php74compatibility # run compatibility check on current minimal version of php we support
make php81compatibility # run compatibility check on last version of php we will support in future

最后,“辅助”命令,您可以在提交和推送之前运行

make ci

此命令会清除之前的报告,如果需要则安装组件,并运行测试(带有覆盖率报告),检查代码风格,并检查PHP兼容性检查,就像在我们的CI中做的那样。

贡献

查看CONTRIBUTING文件。

许可证

本项目目前采用MIT许可证(MIT)。有关更多信息,请参阅LICENCE文件。