SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens

Posted by muchag | Symfony 1.x | 2015-11-17 (火) 16:12:02

【環境】
Symfony:1.4.13
doctrine:1.2.4
エラー
SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens

引数の数が合ってないよっと。

状況1

i18n データを取得しようとして、データ取得 の如く
find メソッドで取得しようとして起きた。

原因

i18n データを取得するのに、親テーブルへアクセスして
Translation テーブルの主キーのデータを渡していた。

  1. $category = Doctrine::getTable('Category')->find(Array($id, $culture));
解決

親テーブルの主キーは ID のみなので、下記のように変更して解決。

  1. $category = Doctrine::getTable('Category')->find($id);
状況2

DQL でサブクエリを利用しようとした。
ただ、メインクエリとサブクエリと
同一のテーブルだった。

  1. $query = Doctrine::getTable('Relation')->createQuery('r')
  2.     ->select('r.hoge_id');
  3.  
  4. $sub_query = $query->createSubquery()
  5.     ->select('sub.hoge_id')
  6.     ->from('Hoge sub')
  7.     ->where('sub.category_id = ?', 123);
  8.    
  9. $query->where("r.hoge_id IN ({$sub_query->getDql()})")
  10.     ->andWhere('r.category_id = ?', 456);
原因

テーブルエイリアスを変えてみたものの
category_id というカラムは同一と見なされ、値は2種類あるので、
数が合ってない、ということみたい。

解決

解決できてないけど、そもそもこの DQL は、本命からずれたお試しだったので
本命の DQL に戻しただけ。

直接の解決策は見つかっていない。

Symfony 1.x | 2015-11-17 (火) 16:12:02 |

Invalid hydration mode specified: ja_JP

Posted by muchag | Symfony 1.x | 2015-11-17 (火) 15:33:17

【環境】
Symfony:1.4.13
doctrine:1.2.4
状況

データ取得 の find メソッドを初めて実装したときに起きた。

Invalid hydration mode specified: ja_JP
原因

複合主キーの検索値を配列ではなく、そのまま引数に入れていたため。

  1. $category = Doctrine::getTable('Category')->find($id, $culture);
解決

配列に書きなおして無事解決。 😯

  1. $category = Doctrine::getTable('Category')->find(Array($id, $culture));
別の問題

この問題は解決したんだけど、別の問題が残っていたのは秘密
下記コードには別の間違いがありました。。。
SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens

Symfony 1.x | 2015-11-17 (火) 15:33:17 |

array_reduce

Posted by muchag | PHP | 2015-11-10 (火) 14:00:40

array_reduce は、配列要素を集約して単一の結果を返す関数。
階層構造の再帰処理 で参考にさせていただいたソースに使われていた。

【環境】
php:5.4.7
array_reduce

mixed array_reduce ( array $array , callable $callback [, mixed $initial = NULL ] )

配列 array の各要素に callback 関数を繰り返し適用し、 配列を一つの値に減らします。

php:array_reduce

第1引数:当該配列
第2引数:コールバック関数。無名関数可
第3引数:戻り値の初期値。省略可。省略した場合はデフォルトが null

イメージ

配列について、foreach でグルグル回す代わりに使う。

利用例
  1. // コールバック関数。その1
  2. function sum($carry, $item)
  3. {
  4.     $carry += $item;
  5.     return $carry;
  6. }
  7.  
  8. // コールバック関数。その2
  9. function product($carry, $item)
  10. {
  11.     $carry *= $item;
  12.     return $carry;
  13. }
  14.  
  15. $a = array(1, 2, 3, 4, 5);
  16. $x = array();
  17.  
  18. var_dump(array_reduce($a, "sum")); // int(15)
  19. var_dump(array_reduce($a, "product", 10)); // int(1200), because: 10*1*2*3*4*5
  20. var_dump(array_reduce($x, "sum", "No data to reduce")); // string(17) "No data to reduce"
コールバック関数

関数名そのものを文字列にて渡す。

  1. var_dump(array_reduce($a, "sum"));
無名関数

関数名を指定するのではなく、無名関数にてその場に定義してもOK。

  1. var_dump(array_reduce($a, function sum($carry, $item) {
  2.     $carry *= $item;
  3.     return $carry;
  4.   }
  5. ));
引数

$carry:戻り値。処理の間保持される
$item:配列の各要素。foreach($array as $key => $val) の $val

PHP | 2015-11-10 (火) 14:00:40 |

SQL の確認

Posted by muchag | OpenPNE 3.x,Symfony 1.x | 2015-10-08 (木) 18:34:07

発行されている SQL 文を確認する方法。

【環境】
OpenPNE:3.8.15
Symfony:1.4.13
doctrine:1.2.4
モデル

モデル生成時に自動的に生成される Table クラスで書く場合。

  1. $result = $this->createQuery('p')
  2.     ->leftJoin('p.Translation t WITH t.lang = ?', $culture)
  3.     ->andWhere('p.id = ?', 1)
  4.     ->execute();

上記のようにすることで目的のレコードを取得できるけど
createQuery メソッドで Doctrine_Query が返ってきているので
最後の execute メソッドを getSqlQuery に変更することで、生 SQL 文を取得できる。

  1. echo $this->createQuery('p')
  2.     ->leftJoin('p.Translation t WITH t.lang = ?', $culture)
  3.     ->andWhere('p.id = ?', 1)
  4.     ->getSqlQuery();
実際に利用してみて思った
  1. $query = $this->createQuery('p')
  2.     ->leftJoin('p.Translation t WITH t.lang = ?', $culture)
  3.     ->andWhere('p.id = ?', 1);
  4.  
  5. echo $query->getSqlQuery();
  6.  
  7. $result = $query->execute();

こういう風に記述してやると見やすい。

色々な記事で、execute() を切り離して記述しているのは
こういうことがあるからかも?

OpenPNE 3.x,Symfony 1.x | 2015-10-08 (木) 18:34:07 |

階層構造の再帰処理

Posted by muchag | PHP | 2015-09-25 (金) 17:27:28

多次元配列の階層構造をリスト表示したくて Google 先生へ質問した結果。

【環境】
php:5.4.7
手法

時間がないので、参考サイトの中から採用したものをコピペ。

  1. $data = [
  2.     [
  3.         'hoge_id' => 2,
  4.         'hoge' => '親2',
  5.         'parent_id' => 0,
  6.     ],
  7.     [
  8.         'hoge_id' => 8,
  9.         'hoge' => '孫',
  10.         'parent_id' => 4,
  11.     ],
  12.     [
  13.         'hoge_id' => 3,
  14.         'hoge' => '子2-1',
  15.         'parent_id' => 2,
  16.     ],
  17.     [
  18.         'hoge_id' => 4,
  19.         'hoge' => '子7-1',
  20.         'parent_id' => 7,
  21.     ],
  22.     [
  23.         'hoge_id' => 7,
  24.         'hoge' => '親7',
  25.         'parent_id' => 0,
  26.     ],
  27.     [
  28.         'hoge_id' => 1,
  29.         'hoge' => '親1',
  30.         'parent_id' => 0,
  31.     ]
  32. ];
  33.  
  34. class HtmlUlBuilder
  35. {
  36.     private $data;
  37.  
  38.     public function __construct($data)
  39.     {
  40.         $this->data = $data;
  41.     }
  42.  
  43.     public function buildFromParent($parent_id)
  44.     {
  45.         $children = array_filter($this->data, function ($element) use ($parent_id) {
  46.             return $element['parent_id'] === $parent_id;
  47.         });
  48.  
  49.         if (count($children) === 0) return '';
  50.  
  51.         return '<ul>' . array_reduce($children, function ($current, $element) {
  52.             return $current . PHP_EOL . '<li>' . $element['hoge'] . $this->buildFromParent($element['hoge_id']) . '</li>';
  53.         }, '') . '</ul>';
  54.     }
  55. }
  56.  
  57. usort($data, function ($a, $b) {
  58.     return $a['hoge_id'] > $b['hoge_id'];
  59. });
  60.  
  61. $builder = new HtmlUlBuilder($data);
  62. $html = $builder->buildFromParent(0);
  63.  
  64. echo $html;
参考サイト

stack overflow:PHP多次元配列から階層リストタグ(略)を出力したい

PHP | 2015-09-25 (金) 17:27:28 |

CSV ファイル出力

Posted by muchag | PHP | 2015-09-07 (月) 12:02:17

ずっと DB に頼ってばかりで、CSV ファイル出力って、ほとんどしてこなかったので
まとめた記事がなかった。

基本
文字コード変換

今では Web サイトは UTF-8 が主流になっているんだろうけど
Excel は、相変わらず Shift-JIS なので
文字コード変換が必要なときもあるでしょう。

  1. mb_convert_variables('SJIS-win', 'UTF-8', $string);
ファイル保存

試していないので、参考サイトのみ。

パス指定
ダウンロード

Qiita:PHPで連想配列を日本語エンコードしてCSV出力する
SCENE LIVE:【PHP】データをCSVでいい感じにエクスポートする方法

連想配列対応
  1. $fields = Array('name', 'content',);
  2.  
  3. $array = Array(
  4.     0 => Array('name' => 'yamada', 'content' => 'pitcher',),
  5.     1 => Array('name' => 'tanaka', 'content' => 'catcher',),
  6. );
  7.  
  8. /* ファイルポインタをオープン */
  9. $file = fopen("C:\Users\UserName\Downloads\test.csv", "w");
  10. fputcsv($file, $fields);
  11.  
  12. foreach( $array as $key => $assoc_row){
  13.   $numeric_row = array();
  14.   foreach ($fields as $header_name) {
  15.     $numeric_row[] = $assoc_row[$header_name];
  16.   }
  17.   fputcsv($file, $numeric_row);
  18. }
  19.  
  20. /* ファイルポインタをクローズ */
  21. fclose($file);
参考サイト

Qiita:PHPで連想配列を日本語エンコードしてCSV出力する

PHP | 2015-09-07 (月) 12:02:17 |

SoftDelete

Posted by muchag | OpenPNE 3.x,Symfony 1.x | 2015-09-06 (日) 17:41:37


SoftDelete:日本語版

レコードを削除する際に、本当に削除(物理削除)するのではなく
削除フラグを立てることによって、削除モードにする(論理削除)機能。

【環境】
OpenPNE:3.8.15
Symfony:1.4.13
doctrine:1.2.4
設定
ProjectConfiguration

ここまで実装方法などについて書いてきましたが、実はこれだけだと動きません。
Doctrineのデフォルトの設定では、Doctrine_Queryを実行前後で修正することが出来なくなっており、そこを設定してあげる必要があります。この設定の方法がsymfony 1.0とsymfony 1.1で変わってきます。

symfony 1.1ではProjectConfigurationクラスに設定を記述します。

アシアルブログ:Doctrineで論理削除を意識せずに扱う

ProjectConfiguration.class.php
  1. class ProjectConfiguration extends sfProjectConfiguration
  2. {
  3.   protected $plugins = array('sfDoctrinePlugin');
  4.  
  5.   public function configureDoctrine($manager)
  6.   {
  7.     $manager->setAttribute(Doctrine::ATTR_USE_DQL_CALLBACKS, true);
  8.   }
  9. }
OpnePNE3

OpenPNE3 では、こういう設定を追加する場所が用意されているっぽい。
まだ、成功体験をしていないので、本当にこれでよいかは不明。

(openpne3)\config\ProjectConfiguration.class.php
  1. public function setupProjectOpenPNEDoctrine($manager)
  2. {
  3.     // You can write your own configurations.
  4.  
  5.     // In default, OpenPNE uses foreign key.
  6.     // If you want not to use foreign key, comment out the following configuration:
  7.     // $manager->setAttribute(Doctrine::ATTR_EXPORT, Doctrine::EXPORT_ALL ^ Doctrine::EXPORT_CONSTRAINTS);
  8.  
  9.     $manager->setAttribute(Doctrine::ATTR_USE_DQL_CALLBACKS, true);
  10. }
schema
schema.yml
  1. Category:
  2.   actAs:
  3.    - SoftDelete
設定変更

カラム名やデータ型を変更したい場合は、下記のように記述すればよいみたい。
Symfony world:Doctrine SoftDelete behavior usage
→この記事のコメント投稿内情報。未検証。

  1. Category:
  2.   actAs:
  3.     SoftDelete:
  4.       name: is_deleted
  5.       type: datetime

力技でやっている人もいるみたい。
@chisei のはてなブログ:Doctrineの論理削除

マニュアルとの差異

このように設定することで、当該テーブルへ deleted_at カラムが追加される
んだけど・・・

公式マニュアル では、delete カラムが追加される、とされている。
データ型も、公式マニュアルでは、TYNYINT とあるけど、実際は DATETIME になる。
バージョンの問題かしらね~。

データ挿入

んで、実際に試してみた。
CSV で、データを突っ込む際に、deleted_at カラムには null を指定しておいたところ
当該カラムの値は 0000-00-00 00:00:00 となった。

CSV から Null を放り込む方法

文系プログラマによるTIPSブログ:MySQLのload dataで日付型にnullをセットする
こちらの記事がビンゴ!

  1. LOAD DATA
  2.     LOCAL INFILE 'data.csv'
  3.     INTO TABLE [table_name]
  4.     FIELDS TERMINATED BY ','
  5.     ENCLOSED BY '"'
  6.     SET
  7.         deleted_at = nullif(deleted_at, '0000-00-00 00:00:00')
  8. ;

上記記事では、指定項目がもっといっぱいあったけど
ひとまず、私の今回の環境およびデータでは、上記 SQL にて、
無事に daleted_at カラムへ Null 値を放り込めた。

nullif

どうやら第2引数に、データ型に合わせたデフォルト値を設定するみたい。
なので、その他のデータ型は下記の通り。

  1. SET
  2.         datetime = nullif(datetime, '0000-00-00 00:00:00')
  3.         date = nullif(date, '0000-00-00')
  4.         time = nullif(time, '00:00:00')
データ取得
  1. $result = $this->createQuery('c')
  2.     ->execute();

データ取得を試みたところ
取得データ数は 0 。

SQL 確認

SQL の確認 のごとく、発行された SQL 文を確認すると、
ちゃんと WHERE 句が付記されている。

  1. WHERE (o.deleted_at IS NULL)

※エイリアスに p を指定しているのに、テーブル名の先頭文字 o をエイリアスにされているが気になるけど。。。

エイリアス o

これは、こちらの指定した DQL から Doctrine が SQL を生成する際に、
指定されたテーブルを順番に o1, o2, o3, … と再指定しているためだった。

その o も、恐らく、テーブル名の頭文字を取っていると思われる。
OpenPNE3 の場合、テーブル接頭辞を付けているため
全テーブルが op_ で始まるのよね。

原因

Doctrine が NULL を探しているのに対して、
データ側は ‘0000-00-00 00:00:00’ という値であるため
スルーされていた。

解決

上記 データ挿入→CSV から Null を放り込む方法 を用いて
値を Null にしてやることで、ちゃんとデータを取得できるようになった。

過去の対応策
  1. $result = $this->createQuery('p')
  2.     ->andWhere('p.deleted_at = ?', '0000-00-00 00:00:00')
  3.     ->execute();

これで一応拾ってくることはできた。

とりあえずはこれでいくしかないけど。。。意味なーい!
いつか解明しなければ。。。
(やっと解明できた)

エイリアス

ちなみにテーブルエイリアスを付けないと、上記記述でも拾ってこない。

  1. // NG
  2. $result = $this->createQuery()
  3.     ->andWhere('deleted_at = ?', '0000-00-00 00:00:00')
  4.     ->execute();

必ずエイリアスをつける必要があります。
ただしこれはSELECT限定で、DELETEのときはエイリアスがなくても動くようです。

アシアルブログ:Doctrineで論理削除を意識せずに扱う

OpenPNE 3.x,Symfony 1.x | 2015-09-06 (日) 17:41:37 |

php.ini

Posted by muchag | PHP | 2015-05-29 (金) 12:53:43

初期設定項目。

extention
extension=php_openssl.dll

外部 API からレスポンスがない

PHP | 2015-05-29 (金) 12:53:43 |

外部 API からレスポンスがない

Posted by muchag | PHP | 2015-05-29 (金) 12:50:56

まさかこんなところが原因だとは思わず、24時刊無駄にしちゃった。 😥

【環境】
php:5.4.7
現象

Google Places API を利用しようと思ってコーディングしたところ
file_get_contents の戻り値が false になった。

原因

API 問い合わせ先が https であるのに対して
php の openssl が ON になっていなかった。

解決
(xampp)\php\php.ini
  1. - ;extension=php_openssl.dll
  2. + extension=php_openssl.dll
試行錯誤
cURL

file_get_contents がだめだったので、cURL も試してみたけどだめだった。

ブラウザでチェック

試しに要求 URL をブラウザに直接入力してみると
ちゃんとレスポンスが返ってきて、json 文字列が表示された。

API キー

Google Developer Console を見ると、API キーには4種類
サーバー キー、ブラウザ キー、Android キー、iOS キー
があるようで、サーバーサイドの場合は、サーバー キーが必要なんかと思い
これを取得、設定を変更したけど、ダメ。

解決後調査結果

サーバーサイドスクリプト内であろうが、ブラウザ直接入力であろうが
サーバー キーでも、ブラウザ キーでも、どちらでもレスポンスが返ってきた。

素の php

はた、と思いついて、マッサラのテストページを作り
当該箇所のみを記述して読み込んでみた。

  1. $url  = sprintf( 'https://maps.googleapis.com/maps/api/place/textsearch/json?query=%s&sensor=false&key=%s', $word, $key );
  2. $json = file_get_contents( $url );
  3. echo $json;
Warning

すると、下記のような Warning が。

file_get_contents(): Unable to find the wrapper…

「file_get_contents(): Unable to find the wrapper」

Symfony でも、エラーを表示するように設定しないと時間の無駄だね。。。

Google 先生

で、Google 先生に質問したら、下記記事が一番上に表示された。
YAHOO! JAPAN 知恵袋:PHPでhttps://から始まるURLのオープンに…

こちらの回答に従って、extention を ON にしたところ、無事に解決した。

PHP | 2015-05-29 (金) 12:50:56 |

SQLSTATE[HY000]: General error: 1005 Can’t create table

Posted by muchag | OpenPNE 3.x,Symfony 1.x | 2015-05-21 (木) 22:49:18

【環境】
Symfony:1.4.13
OpnePNE:3.8.15
状況

OpenPNE3 のプラグインを開発していて、DB の再構築を行ったところ
下記のようなエラーメッセージが出た。

エラーメッセージ
SQLSTATE[HY000]: General error: 1005 Can’t create table ‘database_name.#sql-16e8_55a’
(errno: 150).
Failing Query:
“ALTER TABLE op_my_hoge ADD CONSTRAINT op_my_hoge_parent_id_op_my_parent_id FOREIGN KEY (parent_id) REFERENCES op_my_parent(id)”.
Failing Query:
ALTER TABLE op_my_hoge ADD CONSTRAINT op_my_hoge_parent_id_op_my_parent_id FOREIGN KEY (parent_id) REFERENCES op_my_parent(id)
原因

よく見てみると
op_my_hoge.parent_id と op_my_parent.id のデータ型が異なっていた。

OpenPNE 3.x,Symfony 1.x | 2015-05-21 (木) 22:49:18 |
« 前ページへ次ページへ »