首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

Agavi MVC 框架實戰 (二-2):Doctrine ORM 整合、Listing 模組與資料庫讀取

     編輯:PHP 綜合知識

整合 Doctrine ORM

  1. 安裝:`composer require doctrine/orm doctrine/dbal symfony/cache`
  2. 配置連線 (app/config/databases.xml):
<?xml version="1.0" encoding="UTF-8"?>
<ae:configurations xmlns:ae="https://agavi.org/agavi/config/global/envelope/1.0"
                   xmlns="https://agavi.org/agavi/config/parts/database/1.0">
  <ae:configuration>
    <databases>
      <database name="default" dsn="mysql:host=localhost;dbname=wasp;charset=utf8mb4"
                user="wasp_user" password="secret"
                persistent="false" />
    </databases>
  </ae:configuration>
</ae:configurations>
  1. 建立 EntityManager 服務 (app/lib/DoctrineHelper.php):
<?php
// app/lib/DoctrineHelper.php
class DoctrineHelper
{
    private static $em = null;

    public static function getEntityManager(): \Doctrine\ORM\EntityManager
    {
        if (self::$em === null) {
            $config = new \Doctrine\ORM\Configuration();
            $config->setProxyDir(sys_get_temp_dir() . '/doctrine_proxies');
            $config->setAutoGenerateProxyClasses(true);
            $config->setMetadataCacheImpl(new \Doctrine\Common\Cache\ArrayCache());
            $config->setQueryCacheImpl(new \Doctrine\Common\Cache\ArrayCache());
            $config->setResultCacheImpl(new \Doctrine\Common\Cache\ArrayCache());

            // 讀取 Agavi 資料庫配置
            $dbConfig = AgaviConfig::get('databases.default');
            $conn = [
                'driver'   => 'pdo_mysql',
                'host'     => $dbConfig['host'] ?? 'localhost',
                'dbname'   => $dbConfig['dbname'] ?? 'wasp',
                'user'     => $dbConfig['user'] ?? 'root',
                'password' => $dbConfig['password'] ?? '',
                'charset'  => 'utf8mb4',
            ];

            self::$em = \Doctrine\ORM\EntityManager::create($conn, $config);
        }
        return self::$em;
    }
}

建立 Listing 模組與 Entity

./bin/agavi module-create
# Module name: Listing

./bin/agavi action-wizard
# Module: Listing
# Action: Display
# Views: Error Success

Entity 範例 (app/lib/Entity/Listing.php)

<?php
// app/lib/Entity/Listing.php
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\Table(name="listing")
 */
class Listing
{
    /** @ORM\Id @ORM\Column(type="integer") @ORM\GeneratedValue */
    private $recordId;

    /** @ORM\Column(type="string", length=100) */
    private $ownerName;

    /** @ORM\Column(type="string", length=50) */
    private $vehicleModel;

    /** @ORM\Column(type="integer") */
    private $vehicleYear;

    /** @ORM\Column(type="decimal", precision=10, scale=2) */
    private $vehicleSalePriceMin;

    // ... 其他欄位、getter/setter 省略
}

DisplayAction 讀取資料

<?php
// app/modules/Listing/actions/DisplayAction.class.php
class Listing_DisplayAction extends AgaviAction
{
    public function execute(AgaviRequestDataHolder $rd)
    {
        $id = $rd->getParameter('id');
        if (!$id) {
            return 'Error';
        }

        $em = DoctrineHelper::getEntityManager();
        $listing = $em->find('Listing', (int)$id);

        if (!$listing) {
            return 'Error';
        }

        $this->setAttribute('listing', $listing);
        return 'Success';
    }
}

Success 模板

<?php // app/modules/Listing/templates/DisplaySuccess.php ?>
<h1><?= $listing->getVehicleModel() ?> (<?= $listing->getVehicleYear() ?>)</h1>
<dl class="dl-horizontal">
  <dt>車主</dt><dd><?= $listing->getOwnerName() ?></dd>
  <dt>價格區間</dt><dd><?= number_format($listing->getVehicleSalePriceMin()) ?> - <?= number_format($listing->getVehicleSalePriceMax()) ?></dd>
  <dt>里程</dt><dd><?= number_format($listing->getVehicleMileage()) ?> km</dd>
  <dt>顏色</dt><dd><?= $listing->getVehicleColor() ?></dd>
  <dt>備註</dt><dd><?= nl2br($listing->getNote()) ?></dd>
</dl>
<p><a href="<?= $ro->gen('listing.index') ?>">回列表</a></p>

路由 (app/modules/Listing/config/routing.xml)

<route name="listing" pattern="^/listing" module="Listing">
  <route name=".display" pattern="^/display/(?P\d+)$" action="Display" />
</route>

巢狀路由:`listing.display` 完整模式 `^/listing/display/(?P\d+)$`。

測試資料插入 (MySQL CLI)

INSERT INTO listing (RecordID, RecordDate, OwnerName, OwnerTel, OwnerEmail,
  VehicleManufacturerID, VehicleModel, VehicleYear, VehicleColor, VehicleMileage,
  VehicleIsFirstOwned, VehicleAccessoryBit, VehicleIsCertified, VehicleCertificationDate,
  VehicleSalePriceMin, VehicleSalePriceMax, VehicleSalePriceIsNegotiable, Note,
  OwnerCity, OwnerCountryID, DisplayStatus, DisplayUntilDate)
VALUES (1, '2024-01-15', 'John Doe', '0912345678', 'john@example.com',
  2, 'Boxster', 2005, 'Yellow', 15457, 1, 23, 1,
  '2023-01-01', 35000, 40000, 1, 'Well maintained.', 'Taipei', 1, 1, '2024-12-31');

關鍵點回顧

  • Agavi **不綁定特定 ORM**,Doctrine、Propel、Eloquent、PDO 皆可透過服務類整合。
  • `DoctrineHelper` 單例模式管理 `EntityManager`,避免重複建立連線。
  • Action 僅負責**協調**:取參數 → 呼叫 Model/Service → 設定屬性 → 返回 View 名稱。
  • 模板僅負責**呈現**,不含業務邏輯,嚴格分離關注點。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved