mattsmithdev/pdo-crud-for-free-repositories

使使用 PDO 进行数据库 CRUD 操作变得非常简单

v2.6 2024-02-17 14:03 UTC

This package is auto-updated.

Last update: 2024-09-17 15:34:04 UTC


README

Build Status Latest Stable Version Total Downloads Latest Unstable Version License

注意 - 这实际上是 pdo-crud-for-free 包的另一种方法

此包提供了一些类,旨在以简单的方式为使用 PDO(与 MySQL 一起)的程序员提供一些实例 CRUD(创建-读取-更新-删除)方法,'免费'地仅通过创建 Mattsmithdev\PdoCrudRepo\DatabaseTableRepository 的实体仓库子类即可。

所有代码都遵循 PSR-1、PSR-12 编码标准。类遵循 PSR-4 自动加载标准。

使用此库的示例项目

有一个示例项目展示了如何使用此库

安装

通过 Composer

$ composer require mattsmithdev/pdo-crud-for-free-repositories

用法

此示例假设您有一个名为 'movie' 的 MySQL 数据库表,其中包含列 'id' 和 'title'。您需要编写相应的类 'Movie'(请注意首字母大写 - 因为这是一个 PHP 类)。此外,您还需要编写一个仓库类,在您的 PHP 类和相应的表之间工作,在此示例中,仓库类命名为 'MovieRepository'

    // file: /src/Movie.php
    namespace <MyNameSpace>;
    
    class Movie
    {
        // private properties with EXACTLY same names as DB table columns
        private $id;
        private $title;
        
        public function getId()
        {
            return $this->id;
        }
        
        public function getTitle()
        {
            return $this->title;
        }
    }
    // file: /src/MovieRepository.php
    namespace <MyNameSpace>;
    
    use Mattsmithdev\PdoCrudRepo\DatabaseTableRepository;
    
    class MovieRepository extends DatabaseTableRepository
    {
        // no methods needed if you've followed defaults
        // all the 'magic' is done through relfection ...
    }
    // file: /public-web/index.php or /src/SomeController->method()
    
    require_once __DIR__ . '/<PATH_TO_AUTLOAD>';
    
    // create a repository object
    use <MyNameSpace>\MovieRepository;
    $movieRepository = new MovieRepository();
    
    // get all records from DB as an array of Dvd objects
    $movies = $movieRepository->findAll();
    
    // output each Dvd object as HTML lines in the form 'title = Jaws II'
    foreach($movies as $movie){
        /**
         * @var $movie <MyNameSpace>\Movie
         */
        print 'id = ' . $movie->getId();
        print '<br>';
        print 'title = ' . $movie->getTitle();
        print '<br>';
    }

最后,您需要在文件 .env 中定义您的数据库连接凭据,如下所示

    MYSQL_USER=root
    MYSQL_PASSWORD=passpass
    MYSQL_HOST=127.0.0.1
    MYSQL_PORT=3306
    MYSQL_DATABASE=evote

如果尚未存在,将创建命名的数据库模式...

更多详细信息请见下文。此外,在 GitGub 上有一个完整的示例网络应用程序项目:pdo-crud-for-free-repositories-example-project

更详细的用法说明(以及重要假设)

假设 1:lowerCamelCase - 数据库表列名与 PHP 类属性匹配

此工具假设您的数据库表列名以及它们对应的 PHP 私有类属性以 'lowerCamelCase' 一致命名,例如。

id
title
category
price
vatRate
firstName
aLongVariableNameOfSeveralWords

假设 2:PHP 类没有构造函数。

由于 PDO 将数据库行转换为对象实例时填充对象的属性,因此您的 DB 表对应的 PHP 类不需要构造函数

因此,您会创建一个新对象,并使用对象的公共 'setter' 方法,例如。

    $m = new Movie();
    $m->setTitle('Jaws');
    $m->setPrice(9.99);
    etc.

假设 3:每个类都有一个整数 id 属性

每个实体类都应该有一个整数 id 属性。此属性应在数据库表模式中是 AUTO_INCREMENT 主键,例如。

    -- SQL statement to create the table --
    create table if not exists movie (
        id integer primary key AUTO_INCREMENT,
        title text,
        price float
    );

注意:请不要将此命名为其他名称,例如 idMoviemovieIdID 等。 - 只需简单的 id

假设 4:数据库表名是单数形式且全部小写

此工具假设您的数据库表名是单数形式,全部 小写。例如。

  • 表名: movie

    • 实体类名: Movie.php
  • 表名: moviecategory

    • 实体类名: MovieCategory.php
  • 表名: alongtablename

    • 实体类名: ALongTableName

步骤 1:创建您的数据库表。

您需要一个数据库模式

  • 如果不存在,将创建一个新的模式

对于每个实体类,您需要一个相应的数据库表(具有整数 'id' 字段,主键,自增)

  • 您可以在您的数据库管理工具中创建这些表
  • 您可以使用仓库方法 createTable()
    • 可以从您的实体属性中尝试推断列数据类型,或者使用您提供的自己的SQL

步骤 2:创建相应的PHP(实体)类

例如:

    <?php
    namespace Whatever;
    

    class Movie
    {
        private int $id;
        private string $title;
        private string $category;
        private float $price;
        
        // and public getters and setters ...
        `

步骤 3:创建一个将数据库表映射到您的PHP实体类的仓库类(这是一个从 Mattsmithdev\PdoCrudRepo\DatabaseTableRepository 继承的子类)

例如:创建仓库类 MovieRepository,将表 movie 映射到PHP类 Evote\Movie

    <?php
    namespace Whatever; // same as for Entity calss
    
    use Mattsmithdev\PdoCrudRepo\DatabaseManager;
    use Mattsmithdev\PdoCrudRepo\DatabaseTableRepository;
    
    class MovieRepository extends DatabaseTableRepository
    {
    }
    

注意 - 我个人觉得添加一个创建新对象并将其插入数据库的方法很方便 - 例如:

    <?php
    namespace Tudublin;
    
    
    use Mattsmithdev\PdoCrudRepo\DatabaseTableRepository;
    
    class MovieRepository extends DatabaseTableRepository
    {
        public function createAndInsert($title, $price, $category): void
        {
            $m = new Movie();
            $m->setTitle($title);
            $m->setPrice($price);
            $m->setCategory($category);
    
            $this->insert($m);
        }
    }

步骤 4:在文件 .env 中定义您的MySQL数据库凭据

在文件 .env 中如下定义您的数据库连接凭据

    MYSQL_USER=root
    MYSQL_PASSWORD=passpass
    MYSQL_HOST=127.0.0.1
    MYSQL_PORT=3306
    MYSQL_DATABASE=evote

步骤 5:现在使用“神奇出现”的DB CRUD方法。

例如,要从表 'movie' 获取所有电影记录的数组,只需编写

    $movieRepository = new MovieRepository();
    $movies = $movieRepository->getAll();    

注意:可以在创建仓库类时传递可选参数以覆盖默认值

  • 如果仓库在另一个命名空间中,请传递命名空间名称

    $params = [
        'namespace' => 'DifferentNameSpace'
    ];
    $repo = new MovieRepository($params);
  • 类名 - 如果不是 Repository 前面的名称

    $params = [
        'className' => 'differentClassName'
    ];
    $repo = new MovieRepository($params);
  • 表名不是实体类仓库的小写版本

    $params = [
        'tableName' => 'differentTableName'
    ];
    $repo = new MovieRepository($params);

->findAll()

此方法返回对应数据库表每行的所有对象的数组,例如:

    // array of Movie objects, populated from database table 'movie'
    $movieRepository = new MovieRepository();
    $movies = $movieRepository->findAll();

->find($id)

此方法返回对应数据库表记录的给定 'id' 的一个对象(如果不存在具有该主键id的记录,则返回 'null')

    // one Movie object (or 'null'), populated by row in database table 'movie' with id=27
    $movieRepository = new MovieRepository();
    $movie = $movieRepository->find(27);

->delete($id)

此方法删除与给定 'id' 相关的记录,根据删除的成功与否返回 true/false

    // delete row in database table 'movie' with id=12
    $movieRepository = new MovieRepository();
    $deleteSuccess = $movieRepository->delete(12);

->deleteAll()

此方法删除关联数据库表的所有记录

    // delete all rows in database table 'movie'
    $movieRepository = new MovieRepository();
    $deleteSuccess = $movieRepository->deleteAll();

->insert($movie)

此方法基于提供的对象的内容(此对象中的任何 'id' 都会被忽略,因为表是自增的,因此它留给数据库分配新的唯一 'id' 给新记录)返回新记录的 'id'(或 -1 如果插入时出错)

    // create new object
    $movie = new Movie();
    $movie->setTitle('Jaws II');
    $movie->setCategory('thriller');
    $movie->setPrice(9.99);
    
    // attempt to inset row in database table 'movie' - auto assign new unique `id`
    $movieRepository = new MovieRepository();
    $id = $movieRepository->insert($movie);
    
    // decision based on success/failure of insert
    if ($id < 0){
        // error action
    } else {
        // success action
    }

->update($movie)

此方法基于提供的对象的内容添加或更新数据库中的现有行,根据删除的成功与否返回 true/false

例如:

    // update DB record for object 'movie'
    $movieRepository = new MovieRepository();
    $updateSuccess = $movieRepository->update($movie);

->searchByColumn($columnName, $searchText))

对给定列执行带有给定搜索文本的SQL '%' 通配符搜索,返回匹配SQL 'LIKE' 查询的对象数组

例如:

    // get all Movies with 'jaws' in the title
    $movieRepository = new MovieRepository();
    $jawsMovies = $movieRepository->searchByColumn('title', 'jaws');

->dropTable()

删除关联的数据库表及其所有数据

例如:

    // drop table `movie` from DB
    $movieRepository = new MovieRepository();
    $movieRepository->dropTable();

->createTable()

(方法 1) 如果没有提供SQL参数,则代码会在关联的实体类中查找常量 CREATE_TABLE_SQL,并执行该SQL。 (方法 2) 如果没有找到此类常量,则仓库类将尝试根据实体类属性的数据类型推断数据库列类型。

方法 2 - 自动DB列类型推断

具有如下类型属性的类不需要您提供任何SQL即可使方法正常工作

    class Movie
    {
        private int $id;
        private string $title;
        private float $price;
        private string $category;

方法 1 - 声明创建表的常量SQL

以下是一个示例,其中类明确声明了一个常量 CREATE_TABLE_SQL,包含您要使用的表创建SQL

    class Movie
    {
        const CREATE_TABLE_SQL =
    <<<HERE
     CREATE TABLE IF NOT EXISTS movie (
         id integer PRIMARY KEY AUTO_INCREMENT,
         title text,
         price float,
         category text
     )
     HERE;
    
        ... rest of class ...

->createTable($sql)

与上面相同,但创建表的SQL可以作为字符串参数传递给方法

->resetTable( $sql = null )

运行删除/创建/删除所有序列

    $this->dropTable();
    $this->createTable($sql); // pass through any SQL provided
    $this->deleteAll();

提供的任何SQL作为参数传递给 createTable(...)

然后在我们的迁移代码(例如)中,我们可以删除旧表并创建新表,如下所示

    $movieRepository = new MovieRepository();
    $movieRespository->resetTable();

自定义PDO方法

如果“免费”的DB方法不足,可以很容易地为您自己的PHP类添加对应于您的数据库表的方法。

以下是一个可以添加到类 Product 的方法,允许通过 'id' 和 'description' 中的文本进行自定义搜索

    <?php
    namespace Whatever; // same as for Entity calss
    
    use Mattsmithdev\PdoCrudRepo\DatabaseManager;
    use Mattsmithdev\PdoCrudRepo\DatabaseTableRepository;
    
    class ProductRepository extends DatabaseTableRepository
    {
    
        /**
         * illustrate custom PDO DB method
         * in this case we search for products with an id >= $minId, and whose descrption contains $searchText
         *
         * @param $minId
         * @param $searchText
         *
         * @return array
         */
        public function getAllAboveMinIdContainsString($minId, $searchText)
        {
            $db = new DatabaseManager();
            $connection = $db->getDbh();
    
            // wrap wildcard '%' around the search text for the SQL query
            $searchText = '%' . $searchText . '%';
    
            $sql = 'SELECT * FROM product WHERE (description LIKE :searchText) AND (id > :minId)';
    
            $statement = $connection->prepare($sql);
            $statement->bindParam(':minId', $minId, \PDO::PARAM_INT);
            $statement->bindParam(':searchText', $searchText, \PDO::PARAM_STR);
            $statement->setFetchMode(\PDO::FETCH_CLASS, $this->getClassNameForDbRecords());
            $statement->execute();
    
            $products = $statement->fetchAll();
    
            return $products;
        }

下面是一个使用示例,在一个控制器函数中

    // get products from DB as array of Product objects - id > minId, description containing $searchText
    $minId = 2;
    $searchText = 'er';
    $productRepository = new ProductRepository();
    $products = $productRepository->getAllAboveMinIdContainsString($minId, $searchText);

    // outputs something like:
    //  [5] pliers
    //  [7] hammer
    foreach ($products as $product){
        print '<p>';
        print 'id [' . $product->getId() . '] ';
        print $product->getDescription();
    }

    //  [1] nut -- not listed due to search criteria

迁移和固定数据

这里有一些简单脚本的示例,用于更新表架构和插入一些初始数据。

使用 createAndInsert(...) 存储库方法

如果我们已经在我们的存储库类中添加了 createAndInsert(...) 方法,那么重置数据库并插入固定数据可以像这样简单

<?php
require_once __DIR__ . '/../vendor/autoload.php';

use Tudublin\MovieRepository;

$movieRepository = new MovieRepository();

// (1) drop then re-create table
$movieRepository->resetTable();

// (2) create objects
$movieRepository->createAndInsert('Jaws', 9.99, 'horror');
$movieRepository->createAndInsert('Jumanji', 7, 'entertainment');

// (3) test objects are there
$movies = $movieRespository->findAll();
print '<pre>';
var_dump($movies);

这就是 createAndInsert(...) 方法可能的样子

    class MovieRepository extends DatabaseTableRepository
    {
        public function createAndInsert($title, $price, $category)
        {
            $m = new Movie();
            $m->setTitle($title);
            $m->setPrice($price);
            $m->setCategory($category);
    
            $this->insert($m);
        }
    }

使用访问器方法创建对象数据

如果我们没有 createAndInsert(...) 方法,那么我们必须创建每个对象,然后使用 insert(...) 方法将其插入到数据库表中

<?php
require_once __DIR__ . '/../vendor/autoload.php';

use Tudublin\Movie;
use Tudublin\MovieRepository;

$movieRespository = new MovieRepository();

// (1) drop then create table
$movieRespository->resetTable();

// (3) create objects
$m1 = new Movie();
$m1->setTitle('Jaws');
$m1->setPrice(9.99);
$m1->setCategory('horror');

$m2 = new Movie();
$m2->setTitle('Jumanji');
$m2->setPrice(9.99);
$m2->setCategory('entertainment');

// (3) insert objects into DB
$movieRespository->insert($m1);
$movieRespository->insert($m2);

// (4) test objects are there
$movies = $movieRespository->findAll();
print '<pre>';
var_dump($movies);

输出

<pre>/Users/matt/Documents/github/pdo-crud-for-free-repositories/db/movieMigrationAndFixtures.php:35:
array(2) {
  [0] =>
  class Tudublin\Movie#8 (4) {
    private $id =>
    string(1) "1"
    private $title =>
    string(4) "Jaws"
    private $price =>
    string(4) "9.99"
    private $category =>
    string(6) "horror"
  }
  [1] =>
  class Tudublin\Movie#9 (4) {
    private $id =>
    string(1) "2"
    private $title =>
    string(7) "Jumanji"
    private $price =>
    string(4) "9.99"
    private $category =>
    string(13) "entertainment"
  }
}

变更日志

请参阅 变更日志 以获取更多最近更改的信息。

测试

$ composer test

贡献

请参阅 贡献指南行为准则 以获取详细信息。

安全性

如果您发现任何安全问题,请通过电子邮件 dr_matt_smith@me.com 而不是使用问题跟踪器来联系。

鸣谢

许可证

MIT许可证(MIT)。有关更多信息,请参阅 许可证文件