Because We Love Happy Coding

フリーライターからエンジニア × 講師。発信力だけあり余ってる感じ

ECCUBE3 にORMで新しい製品登録する

今日もまたコーディング。だって僕らはHappy Codingが大好きだから。

Requirements

  • ECCUBE3.0.16
  • Symfony2.7.28
  • PHP5.6.38

PHPから商品登録

PHPファイルから商品登録をさせるためにあれこれ調べる。

persist()がわからなかったので、Symfony2のORMに関する記述を読む。

Databases and the Doctrine ORM (Symfony Docs)

persist()でいったんため込んで、flush()で実際データベースに書き込む(execute()に似ている)。

ProductControllerの254行目付近からを参考に、データを準備する。

クラスなどをうまく読み込んでくれないのは、namespaceか何かの問題かと思って調べたけれどわからない。そうだ、ECCUBE3のWebAPIプラグインのソースがGitHubにあったし、参考になるかも…と見ていくと、オートロードの読み込みがあった。

require_once(__DIR__ . '/../vendor/autoload.php');

なるほど。

ところが動かしてみると、nullのメソッドを呼んでいる、と怒られた。調べてみると、そもそものApplication $appが読み込まれていないことに気がついた。うっかりさん。

これってどこから来てるんだっけ…と出自をたどると、そもそもメソッドの仮引数で与えられている。

…クラス化しないと無理ッ!

クラス化

なんとかプラグインに組み込んでクラス化してみた。

DOCTRINEでは、とりあえずクラスをnewでインスタンス化して、データをsetterで突っ込んでいって、persist()してflush()すればデータベースに書き込まれる、らしいのだが、ECCUBE3では製品の絡みもあるし、なかなかそうはいかないもんだ。

$Product = new \Eccube\Entity\Product();
$ProductClass = new \Eccube\Entity\ProductClass();
$ProductType = new \Eccube\Entity\Master\ProductType();
$Disp = $app['eccube.repository.master.disp']->find(\Eccube\Entity\Master\Disp::DISPLAY_HIDE);
$member = $app['eccube.repository.member']->find(2);

データをサーバーから欲しい時はこのrepositoryが役に立つ。repositoryがServiceProviderに登録さえされていれば、$appから呼び出してfind()メソッドでオブジェクトを取得できる。

セッターでデータをセットして、persist()して、最後にflush()

$app['orm.em']->persist($ProductClass);
$app['orm.em']->persist($Product);
$app['orm.em']->flush();

これがなかなかうまくいかない。あれが足りない、これが足りないというエラーを一つずつ消していく。

product_typeのリポジトリ

$ProductType = $app['eccube.repository.master.product_type']->find('1');

本体でリポジトリを設定していない場合は、EC-CUBE 開発コミュニティ - フォーラムリポジトリ登録の方法が記述されているのを参考に、プラグインServiceProviderで登録する。

同様にCreatorをセットしておかないとSQLに書き込まれないので、セットしてやる。

$member = $app['eccube.repository.member']->find(2);
$Product->setCreator($member);
$ProductClass->setCreator($member);
$ProductStock->setCreator($member);

find(2)の2は管理者アカウントのID。

Nullのnameが参照できない、とか。

次の表示問題を解決しているうちにいつのまにか直った。キャッシュの問題? 開発者モードで作業していたのだが……。

非公開フラグ

15ある商品のうち12しか表示されていない。おかしい。

よく調べていくと、データベースのdtb_productのstatusが2になっているものだけ表示されていない。

公開/非公開のフラグだった。DISPLAY_HIDEを設定しているのを見落としていた。

$Disp = $app['eccube.repository.master.disp']->find(\Eccube\Entity\Master\Disp::DISPLAY_HIDE);//公開・非公開のフラグ

1に変更して無事公開。は、いいけど、「画像をアップロードして登録する」ところがまだなので、これは別記事で。

画像をURLから取得しECCUBE3に登録する

参考URL

EC-CUBE3カスタマイズ - [必須] findByの便利な使い方を紹介! AND検索、OR検索、並び順、件数

add product まとめ

        $Product = new \Eccube\Entity\Product();
        $ProductClass = new \Eccube\Entity\ProductClass();
        $ProductType = new \Eccube\Entity\Master\ProductType();
        $ProductType = $app['eccube.repository.master.product_type']->find('1');//今回ProductTypeは基本的に使用していないのでダミーのid=1を取り出す
        $Disp = $app['eccube.repository.master.disp']->find(\Eccube\Entity\Master\Disp::DISPLAY_SHOW);//公開・非公開のフラグ
        
        $Product
        ->setDelFlg(Constant::DISABLED)
        ->addProductClass($ProductClass)
        ->setStatus($Disp)
        ->setName('商品名を記述します')
        ->setDescriptionDetail('商品の詳細を記述します');
        $ProductClass
        ->setDelFlg(Constant::DISABLED)
        ->setStockUnlimited(true)
        ->setProduct($Product)
        ->setProductType($ProductType)
        ->setPrice02($price);//価格をセット
        $ProductStock = new \Eccube\Entity\ProductStock();
        $ProductClass->setProductStock($ProductStock);
        $ProductStock->setProductClass($ProductClass);
        
        //Creatorをセット
        $member = $app['eccube.repository.member']->find(2);//管理アカウントのid2を指定
        $Product->setCreator($member);
        $ProductClass->setCreator($member);
        $ProductStock->setCreator($member);
        
        // いったんpersist/flushしてProductのidを確定。Product idがないとこの後のproductCategoryの登録ができない。
        $app['orm.em']->persist($Product);
        $app['orm.em']->flush($Product);
        
        // カテゴリ登録
        $Category = $app['eccube.repository.category']->findOneBy(array('項目名'=>'データ'));//目的に合致するcategoryを一つ入手する
        if (!isset($Category)) {
            $Category = $app['eccube.repository.category']->find(7);//合致するカテゴリがなかった場合はデフォルトのカテゴリをセット
        }
        $ProductCategory = new \Eccube\Entity\ProductCategory();
        $ProductCategory->setProduct($Product);
        $ProductCategory->setProductId($Product->getId());
        $ProductCategory->setCategory($Category);
        $ProductCategory->setCategoryId($Category->getId());
        $ProductCategory->setRank('1');//今回はランクを使用しないので1をセット
        $app['orm.em']->persist($ProductCategory);
        $Product->addProductCategory($ProductCategory);
        
        // 今回はタグを使用しないが、使うならこの辺で登録

        $has_class = $Product->hasProductClass();
        if (!$has_class) {
            $ProductClass->setStockUnlimited((boolean)$ProductClass->getStockUnlimited());
            // 個別消費税
            $BaseInfo = $app['eccube.repository.base_info']->get();
            if ($BaseInfo->getOptionProductTaxRule() == Constant::ENABLED) {
                if ($ProductClass->getTaxRate() !== null) {
                    if ($ProductClass->getTaxRule()) {
                        if ($ProductClass->getTaxRule()->getDelFlg() == Constant::ENABLED) {
                            $ProductClass->getTaxRule()->setDelFlg(Constant::DISABLED);
                        }

                        $ProductClass->getTaxRule()->setTaxRate($ProductClass->getTaxRate());
                    } else {
                        $taxrule = $app['eccube.repository.tax_rule']->newTaxRule();
                        $taxrule->setTaxRate($ProductClass->getTaxRate());
                        $taxrule->setApplyDate(new \DateTime());
                        $taxrule->setProduct($Product);
                        $taxrule->setProductClass($ProductClass);
                        $ProductClass->setTaxRule($taxrule);
                    }
                } else {
                    if ($ProductClass->getTaxRule()) {
                        $ProductClass->getTaxRule()->setDelFlg(Constant::ENABLED);
                    }
                }
            }
        }

        $app['orm.em']->persist($ProductClass);
        $app['orm.em']->persist($Product);
        $app['orm.em']->flush();
        
        return new Response('', Response::HTTP_OK, array('Content-Type' => 'text/plain; charset=utf-8'));
    }
  }