FirebirdとLaravelを使用してPHPでWebアプリケーションを作成する

firebird-logo こんにちはHabr!



前の記事で、LaravelフレームワークでFirebird DBMSをサポートするパッケージについて説明しました。 今回は、Laravelを使用してPHPでFirebird DBMSを使用してWebアプリケーションを作成するプロセスを見ていきます。



Firebirdを使用するためのドライバーの概要



Firebird DBMSを操作するためのPHPには2つのドライバーがあります。



Firebird / Interbase Extensionの概要



Firebird / Interbase拡張機能は以前に登場し、最もテストされています。 php.ini構成ファイルにFirebird / Interbase拡張機能をインストールするには、行のコメントを解除する必要があります



extension=php_interbase.dll
      
      





または、UNIXライクシステムの場合、次の行



 extension=php_interbase.so
      
      





この拡張機能では、適切なビットサイズのクライアントライブラリfbclient.dll / gds32.dll(UNIXのようなシステムの場合fbclient.so)がインストールされている必要があります。



Win32 / Win64ユーザー向けの注意



このWindows PATHシステム変数拡張が機能するには、fbclient.dllまたはgds32.dll DLLファイルが使用可能である必要があります。 DLLファイルをPHPディレクトリからWindowsシステムフォルダにコピーすることでも問題は解決しますが(システムディレクトリはデフォルトでPATH変数にあるため)、これはお勧めできません。 この拡張機能には、PATH変数に次のファイルが必要です:fbclient.dllまたはgds32.dll。



Linuxでは、この拡張機能は、ディストリビューションに応じて、次のコマンドのいずれかでインストールできます(サポートされているバージョンを明確にする必要があります。サードパーティのリポジトリを接続する必要がある場合があります)。



 apt-get install php5-firebird rpm –ihv php5-firebird yum install php70w-interbase zypper install php5-firebird
      
      





この拡張機能は、プログラムを作成するための手続き的なアプローチを取ります。 ibase_プレフィックスを持つ関数は、パラメータの1つとして、接続、トランザクション、準備されたクエリ、またはカーソル(SELECTクエリの結果)の識別子を返すか、受け入れることができます。 この識別子はリソースタイプです。 割り当てられたすべてのリソースは、不要になったらすぐに解放する必要があります。 各関数について詳しく説明するのではなく、参照して説明を見ることができますが、代わりにコメント付きの小さな例をいくつか示します。



 $db = 'localhost:example'; $username = 'SYSDBA'; $password = 'masterkey'; //    $dbh = ibase_connect($db, $username, $password); $sql = 'SELECT login, email FROM users'; //   $rc = ibase_query($dbh, $sql); //       while ($row = ibase_fetch_object($rc)) { echo $row->email, "\n"; } //       ibase_free_result($rc); //      ibase_close($dbh);
      
      





ibase_connect関数の代わりに、いわゆる永続的な接続を作成するibase_pconnect関数を使用できます。 この場合、ibase_closeが呼び出されると、接続は閉じられず、それに関連付けられているすべてのリソースが解放され、トランザクションはデフォルトで確認され、他のタイプのトランザクションはロールバックされます。 接続パラメーターが一致する場合、そのような接続は別のセッションで再利用できます。 場合によっては、永続的な接続により、Webアプリケーションのパフォーマンスが大幅に向上する場合があります。 これは、接続を確立するコストが高い場合に特に顕著です。 子プロセスは、SQLサーバーと対話する各ページを処理するときに作成するのではなく、ライフサイクル全体を通して同じ接続を使用できます。 これらの永続的な接続は、接続プールでの動作に似ています。 永続的な接続の詳細については、 こちらご覧ください



注意!



多くのibase関数では、接続識別子(トランザクション、準備された要求)をそれらに渡さないようにすることができます。 この場合、これらの関数は、確立された最後の接続(トランザクション開始)の識別子を使用します。 特にWebアプリケーションが複数の接続を使用できる場合は、これを行うことはお勧めしません。



ibase_query関数はSQLクエリを実行して結果識別子を返します。クエリがデータセットを返さない場合はtrueを返します。 接続識別子(トランザクション)とSQLクエリのテキストに加えて、この関数は可変数の引数をSQLクエリパラメータの値として受け入れることができます。 この場合、例は次のとおりです。



 $sql = 'SELECT login, email FROM users WHERE id=?'; $id = 1; //   $rc = ibase_query($dbh, $sql, $id); //       if ($row = ibase_fetch_object($rc)) { echo $row->email, "\n"; } //       ibase_free_result($rc);
      
      





多くの場合、パラメーター化されたクエリは異なるパラメーター値のセットで繰り返し使用されます;この場合、パフォーマンスを改善するために準備されたクエリを使用することが推奨されます。 この場合、最初にibase_prepare関数を使用して準備済みリクエストの識別子を取得し、次にibase_execute関数を使用して準備済みリクエストを実行する必要があります。



 $sql = 'SELECT login, email FROM users WHERE id=?'; //   $sth = ibase_prepare($dbh, $sql); $id = 1; //   $rc = ibase_execute($sth, $id); //       if ($row = ibase_fetch_object($rc)) { echo $row->email, "\n"; } //       ibase_free_result($rc); //    ibase_free_query($sth);
      
      





バルクデータが必要な場合は、準備済みクエリがはるかに頻繁に使用されます。



 $sql = 'INSERT INTO users(login, email) VALUES(?, ?)'; //   $sth = ibase_prepare($dbh, $sql); $users = [["user1", "user1@gmail.com"], ["user2", "user2@gmail.com"]]; //   foreach ($users as $user)) { ibase_execute($sth, $user[0], $user[1]); } //    ibase_free_query($sth);
      
      





最後の例では、この拡張機能の欠点の1つがわかります。つまり、引数の数が可変の関数は、パラメーター化されたクエリにはあまり便利ではありません。 この欠陥は、クエリを実行するためのユニバーサルクラスを作成しようとしている場合に特に顕著です。 パラメーターを1つの配列で渡すことができれば、はるかに便利です。 もちろん、次のような回避策があります。



 function fb_execute ($stmt, $data) { if (!is_array($data)) return ibase_execute($stmt, $data); array_unshift($data, $stmt); $rc = call_user_func_array('ibase_execute', $data); return $rc; }
      
      





Firebird / Interbase拡張機能は、名前付きクエリパラメーターでは機能しません。



デフォルトでは、Firebird / Interbase拡張機能は、接続後にデフォルトのトランザクションを自動的に開始します。 ibase_closeによって接続が閉じられると、デフォルトのトランザクションが確認されます。 接続識別子を渡してibase_commitまたはibase_rollbackメソッドを呼び出すか、何も渡さない(単一の接続を使用する場合)ことで、確認またはロールバックできます。



明示的なトランザクション管理が必要な場合は、 ibase_trans関数を使用してトランザクションを開始する必要があります。 トランザクションパラメータが指定されていない場合、トランザクションはIBASE_WRITE |で開始されます。 IBASE_CONCURRENCY | IBASE_WAIT トランザクションパラメータを設定するための定数の説明は、 php.net / manual / en / ibase.constants.phpにあります。 トランザクションは、ibase_commitまたはibase_rollbackメソッドを使用して完了し、これらの関数にトランザクション識別子を渡す必要があります。 これらの関数の代わりにibase_commit_retまたはibase_rollback_ret関数を使用すると、トランザクションはCOMMIT RETAINまたはROLLBACK RETAINとして終了します。



発言。



デフォルトのトランザクションパラメータは、ほとんどの場合に適しています。 実際、データベースへの接続は、それに関連付けられているすべてのリソースと同様に、最大でもPHPスクリプトの最後まで存在します。 永続的な接続を使用している場合でも、ibase_close関数を呼び出した後、関連するすべてのリソースが解放されます。 それにもかかわらず、対応するibase_関数を呼び出して、割り当てられたすべてのリソースを明示的に終了することを強くお勧めします。



ibase_commit_retおよびibase_rollback_ret関数を使用することはお勧めしません。これは意味をなさないためです。 COMMIT RETAINおよびROLLBACK RETAINは、トランザクションの終了時にデスクトップアプリケーションでカーソルを開いたままにするために導入されました。



 $sql = 'INSERT INTO users(login, email) VALUES(?, ?)'; //   $sth = ibase_prepare($dbh, $sql); $users = [["user1", "user1@gmail.com"], ["user2", "user2@gmail.com"]]; $trh = ibase_trans($dbh, IBASE_WRITE | IBASE_CONCURRENCY | IBASE_WAIT); try { //   foreach ($users as $user)) { $r = ibase_execute($sth, $user[0], $user[1]); if ($r === false) { //   ,   $err_msg = ibase_errmsg(); throw new \Exception($err_msg); } } ibase_commit($trh); } catch(\Exception $e) { ibase_rollback($trh); echo $e->getMessage(); } //    ibase_free_query($sth);
      
      





注意!



エラーが発生しても、ibase関数は例外をスローしません。 エラーが発生した場合、一部の関数はfalseを返します。 厳密な比較演算子===を使用して、結果をfalseと比較する必要があることに注意してください。 ibase関数の呼び出しフィールドでエラーが発生する可能性があります。 エラーテキストは、ibase_errmsg関数を使用して見つけることができます。 エラーコードは、ibase_errcode関数を使用して取得できます。



Firebird / Interbase拡張機能を使用すると、SQLクエリだけでなく、Service APIを使用してFirebirdサーバーと対話できます(関数ibase_service_attach、ibase_service_detach、ibase_server_info、ibase_maintain_db、ibase_db_info、ibase_backup、ibase_restoreを参照)。 これらの機能により、Firebirdサーバーに関する情報の取得、バックアップ、復元、または統計の取得が可能になります。 この機能は主にデータベース管理に必要であるため、詳細には検討しません。



Firebird / Interbase拡張機能は、Firebirdイベントの操作もサポートしています(ibase_set_event_handler、ibase_free_event_handler、ibase_wait_event関数を参照)。



PDO拡張機能の概要(Firebirdドライバー)



PDO拡張は、さまざまなタイプのデータベースにアクセスするための汎用インターフェースを提供します。 このインターフェイスを実装する各データベースドライバーは、標準の拡張機能の形式でデータベース固有の機能を提供できます。



PDOおよびすべての主要なドライバーは、ロード可能なモジュールとしてPHPに実装されています。 これらを使用するには、次のようにphp.iniファイルを編集して有効にするだけです。



 extension=php_pdo.dll
      
      





発言



PHP 5.3以降のバージョンでは、PDOが機能するためにDLLが不要になったため、この手順はオプションです。



次に、特定のデータベースのDLLを選択し、実行時にdl()関数を使用してロードするか、php_pdo.dllの後にphp.iniに含める必要があります。 例:



 extension=php_pdo.dll extension=php_pdo_firebird.dll
      
      





これらのDLLは、extension_dirディレクトリに存在する必要があります。 pdo_firebirdドライバーを使用するには、クライアントライブラリfbclient.dll / gds32.dll(UNIXのようなシステムの場合fbclient.so)を適切なビット深度でインストールする必要があります。



Linuxでは、この拡張機能はディストリビューションに応じて、次のコマンドのいずれかでインストールできます(サポートされているバージョンを明確にする必要があります。サードパーティのリポジトリを接続する必要がある場合があります)



 apt-get install php5-firebird rpm –ihv php5-firebird yum install php70w-firebird zypper install php5-firebird
      
      





PDOは、オブジェクト指向のアプローチを使用してプログラムを記述します。 PDOで使用されるドライバーは、DSN(データソース名)とも呼ばれる接続文字列によって異なります。 DSNは、データベースの種類を決定するプレフィックスと、セミコロン「;」で区切られた<key> = <value>の形式のパラメーターセットで構成されます。 有効なパラメーターセットは、データベースのタイプによって異なります。 Firebirdを使用するには、接続文字列がfirebird:プレフィックスで始まり、 PDO_FIREBIRD DSNセクションのドキュメントで説明されている形式である必要があります。



基本クラスからPDOオブジェクトを作成すると、接続が自動的に確立されます。 クラスコンストラクターは、オプションのユーザー名とパスワード(存在する場合)と同様に、データソース(DSN)を指定するための引数を受け入れます。 4番目の引数は、キー=>値の形式でドライバー固有の接続設定の配列を渡すことです。



 $dsn = 'firebird:dbname=localhost:example;charset=utf8;'; $username = 'SYSDBA'; $password = 'masterkey'; try { //    $dbh = new \PDO($dsn, $username, $password, [\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION]); $sql = 'SELECT login, email FROM users'; //   $query = $dbh->query($sql); //       while ($row = $query->fetch(\PDO::FETCH_OBJ)) { echo $row->email, "\n"; } $query->closeCursor(); //   } catch (\PDOException $e) { echo $e->getMessage(); }
      
      





プロパティ\ PDO :: ATTR_ERRMODEを\ PDO :: ERRMODE_EXCEPTIONに設定することにより、データベースへの接続エラーを含むすべてのエラーが\ PDOException例外をスローするモードを設定します。 このモードでの作業は、ibase_関数を呼び出すたびにエラーをチェックするよりもはるかに便利です。



PDOが永続的な接続を使用するには、プロパティ配列のPDOコンストラクターにPDO :: ATTR_PERSISTENT => trueを渡す必要があります。



クエリメソッドはSQLクエリを実行し、結果セットを\ PDOStatementオブジェクトとして返します。 SQLクエリに加えて、フェッチ中に値を返すメソッドをこのメソッドに渡すことができます。 列、特定のクラスのインスタンス、オブジェクトのいずれかです。 リンクhttp://php.net/manual/ru/pdo.query.phpでさまざまな呼び出し方法を見ることができます。



データセットを返さないSQLクエリを実行する必要がある場合は、 execメソッドを使用して、関連する行の数を返すことができます。 このメソッドは、準備されたクエリを実行しません。



リクエストがパラメータを使用する場合、準備されたクエリを使用する必要があります。 この場合、クエリメソッドの代わりに、 prepareメソッドを呼び出す必要があります。 このメソッドは、準備されたクエリとその結果を操作するためのメソッドをカプセル化する\ PDOStatementクラスのオブジェクトを返します。 リクエストを実行するには、 executeメソッドを呼び出す必要があります。executeメソッドは、引数として名前付きまたは名前なしのパラメータを持つ配列を取ることができます。 選択クエリの結果は、メソッドfetchfetchAllfetchColumnfetchObjectを使用して取得できます。 fetchおよびfetchAllメソッドは、連想配列、オブジェクト、または特定のクラスのインスタンスなど、さまざまな方法で結果を返すことができます。 後者は、モデルを操作するときにMVCパターンでよく使用されます。



 $dsn = 'firebird:dbname=localhost:example;charset=utf8;'; $username = 'SYSDBA'; $password = 'masterkey'; try { //    $dbh = new \PDO($dsn, $username, $password, [\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION]); $sql = 'INSERT INTO users(login, email) VALUES(?, ?)'; $users = [ ["user1", "user1@gmail.com"], ["user2", "user2@gmail.com"] ]; //   $query = $dbh->prepare($sql); //   foreach ($users as $user)) { $query->execute($user); } } catch (\PDOException $e) { echo $e->getMessage(); }
      
      





名前付きパラメーターの使用例。



 $dsn = 'firebird:dbname=localhost:example;charset=utf8;'; $username = 'SYSDBA'; $password = 'masterkey'; try { //    $dbh = new \PDO($dsn, $username, $password, [\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION]); $sql = 'INSERT INTO users(login, email) VALUES(:login, :email)'; $users = [ [":login" => "user1", ":email" => "user1@gmail.com"], [":login" => "user2", ":email" => "user2@gmail.com"] ]; //   $query = $dbh->prepare($sql); //   foreach ($users as $user)) { $query->execute($user); } } catch (\PDOException $e) { echo $e->getMessage(); }
      
      





発言



名前付きパラメーターをサポートするために、PDOは要求を前処理し、次の形式のパラメーターを置き換えます:paramnameと「?」 このため、コロンでマークされた変数が内部で使用されている場合、EXECUTE BLOCKステートメントは機能しません。 現時点では、一部のアクセスコンポーネントで行われているように、代替パラメータープレフィックスを設定するなど、PDOを強制的にEXECUTE BLOCKステートメントで動作させる方法はありません。



いわゆるバインディングを使用して、別の方法でリクエストにパラメーターを渡すことができます。 bindValueメソッドは、値を名前付きまたは名前なしのパラメーターにバインドします。 bindParamメソッドは、変数を名前付きまたは名前なしのパラメーターにバインドします。 後者の方法は、OUTまたはIN OUTパラメータを介して値を返すストアドプロシージャに特に役立ちます(Firebirdでは、ストアドプロシージャから値を返すメカニズムが異なります)。



 $dsn = 'firebird:dbname=localhost:example;charset=utf8;'; $username = 'SYSDBA'; $password = 'masterkey'; try { //    $dbh = new \PDO($dsn, $username, $password, [\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION]); $sql = 'INSERT INTO users(login, email) VALUES(:login, :email)'; $users = [ ["user1", "user1@gmail.com"], ["user2", "user2@gmail.com"] ]; //   $query = $dbh->prepare($sql); //   foreach ($users as $user)) { $query->bindValue(":login", $user[0]); $query->bindValue(":email", $user[1]); $query->execute(); } } catch (\PDOException $e) { echo $e->getMessage(); }
      
      





ご注意



bindParamおよびbindValueメソッドの名前のないパラメーターの番号付けは1から始まります。



 $dsn = 'firebird:dbname=localhost:example;charset=utf8;'; $username = 'SYSDBA'; $password = 'masterkey'; try { //    $dbh = new \PDO($dsn, $username, $password, [\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION]); $sql = 'INSERT INTO users(login, email) VALUES(?, ?)'; $users = [ ["user1", "user1@gmail.com"], ["user2", "user2@gmail.com"] ]; //   $query = $dbh->prepare($sql); //   foreach ($users as $user)) { $query->bindValue(1, $user[0]); $query->bindValue(2, $user[1]); $query->execute(); } } catch (\PDOException $e) { echo $e->getMessage(); }
      
      





デフォルトでは、PDOは各SQLクエリの実行後にトランザクションを自動的に確認します。明示的なトランザクション管理が必要な場合は、 \ PDO :: beginTransactionメソッドを使用してトランザクションを開始する必要があります。 デフォルトでは、トランザクションはCONCURRENCY | 待機| READ_WRITE。 \ PDO :: commitまたは\ PDO :: rollbackメソッドを使用してトランザクションを完了できます。



 $dsn = 'firebird:dbname=localhost:example;charset=utf8;'; $username = 'SYSDBA'; $password = 'masterkey'; try { //    $dbh = new \PDO($dsn, $username, $password, [\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION]); //        $dbh->beginTransaction(); //      $users_stmt = $dbh->prepare('SELECT login, email FROM old_users'); $users_stmt->execute(); $users = $users_stmt->fetchAll(\PDO::FETCH_OBJECT); $users_stmt->closeCursor(); //      $sql = 'INSERT INTO users(login, email) VALUES(?, ?)'; //   $query = $dbh->prepare($sql); //   foreach ($users as $user)) { $query->bindValue(1, $user->LOGIN); $query->bindValue(2, $user->EMAIL]); $query->execute(); } //   $dbh->commit(); } catch (\PDOException $e) { //      ,   if ($dbh && $dbh->inTransaction()) $dbh->rollback(); echo $e->getMessage(); }
      
      





残念ながら、beginTransactionメソッドはトランザクションパラメータを変更する機能を提供しませんが、SET TRANSACTIONステートメントでトランザクションパラメータを設定することでトリックを行うことができます。



 $dbh = new \PDO($dsn, $username, $password); $dbh->setAttribute(\PDO::ATTR_AUTOCOMMIT, false); $dbh->exec("SET TRANSACTION READ ONLY ISOLATION LEVEL READ COMMITTED NO WAIT"); //     // …. $dbh->exec("COMMIT"); $dbh->setAttribute(\PDO::ATTR_AUTOCOMMIT, true);
      
      





以下は、Firebirdを操作するためのさまざまなドライバーの機能の概要表です。



機会 Firebird / Interbase Extension PDO
プログラミングのパラダイム 機能的 オブジェクト指向
サポートされているDB Firebird、Interbase、Yaffil、およびその他のInterbaseクローン。 Firebirdを含む、PDOドライバーがあるデータベース。
クエリパラメータの使用 名前のないパラメーターのみ、可変数の引数を持つ関数が使用されるため、作業にはあまり便利ではありません。 名前付きパラメーターと名前なしパラメーターの両方で作業することができます。 作業は非常に便利ですが、Firebirdの一部の機能(EXECUTE BLOCKステートメント)は機能しません。
エラー処理 ibase_errmsg、ibase_errcode関数の結果を確認します。 ibase関数を呼び出した後にエラーが発生する可能性があり、例外は発生しません。 エラーが例外につながるモードを設定することは可能です。
トランザクション管理 トランザクションパラメータを設定できます。 トランザクションパラメータを設定することはできません。 SET TRANSACTIONステートメントの実行による回避策があります。
特定のInterbase / Firebirdの機能 データベースイベントだけでなく、サービスAPI拡張(バックアップ、復元、統計など)を使用することもできます。 SQLを使用して作業することが不可能な特定の機能を使用することはできません。


表から、ほとんどのフレームワークがPDOを使用する方がはるかに便利であることがわかります。



WEBアプリケーションを構築するためのフレームワークの選択



MVCパターンを使用せずに小さなWebサイトを作成できます。ただし、サイトが大きくなると、特に複数の人がサイトで作業している場合、サイトを維持することが難しくなります。したがって、Webアプリケーションを開発する場合、このパターンの使用にすぐに同意します。



そこで、MVCパターンを使用することにしました。ただし、このパターンを使用したアプリケーションの作成は、特にサードパーティのライブラリを使用していない場合、見た目ほど簡単ではありません。すべてを自分で作成する場合、クラス定義、ルーティングなどを含む.phpファイルの自動ロードなど、多くの問題を解決する必要があります。これらの問題を解決するために、Yii、Laravel、Symphony、Kohanaなどの多数のフレームワークが作成されました。個人的に、私はLaravelが好きなので、このフレームワークを使用したアプリケーションの作成について以下に説明します。



Laravelをインストールしてプロジェクトを作成する



Laravelをインストールする前に、システム環境が要件を満たしていることを確認する必要があります。





LaravelはComposer使用して依存関係を管理します。したがって、最初にComposerをインストールしてから、Laravelをインストールしてください。Composer



をWindowsにインストールする最も簡単な方法は、Composer-Setup.exeインストーラーをダウンロードして実行することです。インストーラーは、Composerをインストールし、PATHを構成して、コマンドラインの任意のディレクトリからComposerを呼び出せるようにします。



Composerを手動でインストールする必要がある場合は、実行する必要があります



Composerインストールスクリプト
 php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" php -r "if (hash_file('SHA384', 'composer-setup.php') === 'aa96f26c2b67226a324c27919f1eb05f21c248b987e6195cad9690d5c1ff713d53020a02ac8c217dbf90a7eacc9d141d') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" php composer-setup.php php -r "unlink('composer-setup.php');"
      
      







このスクリプトは次のアクションを実行します。





このスクリプトを実行すると、composer.pharファイル(pharはアーカイブ)が表示されます。実際には、いくつかのコマンド(インストール、更新など)を受け入れ、ライブラリをダウンロードおよび展開できるPHPスクリプトです。Windowsで作業している場合は、composer.batファイルを作成してPATHに配置することにより、タスクを簡単にすることができます。これを行うには、クリック

echo @php "%~dp0composer.phar" %*>composer.bat







作曲のインストールについての詳細はこちらを参照してくださいここに



Laravel自体をインストールします。



 composer global require "laravel/installer"
      
      





インストールが成功した場合は、プロジェクトフレームワークの作成に進みます。



 laravel new fbexample
      
      





完成を待っています。その後、プロジェクトフレームワークを作成します。ディレクトリ構造の説明は、Laravelのドキュメントにあります次のディレクトリに関心があります。





アプリケーションフォルダーのルートにはcomposer.jsonファイルがあり、Laravelに既に存在するパッケージに加えて、アプリケーションが必要とするパッケージを記述しています。このようなパッケージが2つ必要です。「zofe / rapyd-laravel」-グリッドおよび編集ダイアログを使用してインターフェースを迅速に構築するため、および「sim1984 / laravel-firebird-Firebird DBMSを操作するための拡張機能です。 sim1984 / laravel-firebirdパッケージはjacquestvanzuydam / laravel-firebirdパッケージのフォークであるため、インストールが多少異なります(元のパッケージとの違いについては、記事「LaravelでFirebird DBMSを操作するためのパッケージ」を参照してください)。パッケージが安定していないため、最小安定性パラメーターをdevに設定することを忘れないでください。また、リポジトリーにリンクを追加します。



 "repositories": [ { "type": "package", "package": { "version": "dev-master", "name": "sim1984/laravel-firebird", "source": { "url": "https://github.com/sim1984/laravel-firebird", "type": "git", "reference": "master" }, "autoload": { "classmap": [""] } } } ], …
      
      





requireセクションで、次のように必要なパッケージを追加します。



 "zofe/rapyd": "2.2.*", "sim1984/laravel-firebird": "dev-master"
      
      





これで、コマンドを使用してパッケージの更新を開始できます(Webアプリケーションのルートで開始する必要があります)



 composer update
      
      





このコマンドを実行すると、新しいパッケージがアプリケーションにインストールされます。これでセットアップの準備が整いました。まず、コマンドを実行します



 php artisan vendor:publish
      
      





zofe / rapydパッケージ用の追加の構成ファイルが作成されます。



config / app.phpファイルで、2つの新しいプロバイダーを追加します。これを行うには、プロバイダーキーに2つの新しいエントリを追加します



  Zofe\Rapyd\RapydServiceProvider::class, Firebird\FirebirdServiceProvider::class,
      
      





それでは、データベースに接続するための設定を含むconfig / databases.confファイルに移りましょう。接続キーに次の行を追加します



  'firebird' => [ 'driver' => 'firebird', 'host' => env('DB_HOST', 'localhost'), 'port' => env('DB_PORT', '3050'), 'database' => env('DB_DATABASE', 'examples'), 'username' => env('DB_USERNAME', 'SYSDBA'), 'password' => env('DB_PASSWORD', 'masterkey'), 'charset' => env('DB_CHARSET', 'UTF8'), 'engine_version' => '3.0.0', ],
      
      





接続をデフォルトの接続として使用するため、以下を設定します



 'default' => env('DB_CONNECTION', 'firebird'),
      
      





プロジェクトのルートにある特別な.envファイルからアプリケーション環境変数を読み取るために使用されるenv関数に注意してください。この.envファイルの次の行を修正します



 DB_CONNECTION=firebird DB_HOST=localhost DB_PORT=3050 DB_DATABASE=examples DB_USERNAME=SYSDBA DB_PASSWORD=masterkey
      
      





config / rapid.php構成ファイルで、日付表示を変更して、ロシアで受け入れられる形式にします。



 'fields' => [ 'attributes' => ['class' => 'form-control'], 'date' => [ 'format' => 'dmY', ], 'datetime' => [ 'format' => 'dmY H:i:s', 'store_as' => 'Ymd H:i:s', ], ],
      
      





初期構成が完了しました。これで、Webアプリケーションのロジックの作成に直接進むことができます。



モデル作成



LaravelフレームワークはORM Eloquentをサポートしています。ORM Eloquentは、データベースを操作するためのActiveRecordパターンの美しくシンプルな実装です。各テーブルには対応するモデルクラスがあり、このクラスを使用してこのテーブルを操作します。モデルを使用すると、テーブルからデータを読み取り、テーブルにデータを書き込むことができます。



顧客モデルを作成しましょう。このプロセスを簡素化するために、Laravelには職人チームがいます。



 php artisan make:model Customer
      
      





このコマンドを使用して、モデルテンプレートを作成します。次のようにモデルを変更します。



 namespace App; use Firebird\Eloquent\Model; class Customer extends Model { /** * ,    * * @var string */ protected $table = 'CUSTOMER'; /** *    * * @var string */ protected $primaryKey = 'CUSTOMER_ID'; /** *       * * @var bool */ public $timestamps = false; /** *       * @var string */ protected $sequence = 'GEN_CUSTOMER_ID'; }
      
      





基本モデルとしてsim1984 / laravel-firebirdパッケージから変更されたFirebird \ Eloquent \ Modelモデルを使用していることに注意してください。これにより、$ sequenceプロパティで指定されたシーケンスを使用して、プライマリキー識別子の値を生成できます。



類推により、製品モデル-製品を作成します。



製品モデル
 namespace App; use Firebird\Eloquent\Model; class Product extends Model { /** * ,    * * @var string */ protected $table = 'PRODUCT'; /** *    * * @var string */ protected $primaryKey = 'PRODUCT_ID'; /** *       * * @var bool */ public $timestamps = false; /** *       * @var string */ protected $sequence = 'GEN_PRODUCT_ID'; }
      
      







次に、請求書のヘッダーのモデルを作成します。



請求書モデル
 namespace App; use Firebird\Eloquent\Model; class Invoice extends Model { /** * ,    * * @var string */ protected $table = 'INVOICE'; /** *    * * @var string */ protected $primaryKey = 'INVOICE_ID'; /** *       * * @var bool */ public $timestamps = false; /** *       * * @var string */ protected $sequence = 'GEN_INVOICE_ID'; /** *  * * @return \App\Customer */ public function customer() { return $this->belongsTo('App\Customer', 'CUSTOMER_ID'); } /** *    * @return \App\InvoiceLine[] */ public function lines() { return $this->hasMany('App\InvoiceLine', 'INVOICE_ID'); } /** *  */ public function pay() { $connection = $this->getConnection(); $attributes = $this->attributes; $connection->executeProcedure('SP_PAY_FOR_INOVICE', [$attributes['INVOICE_ID']]); } }
      
      







このモデルでは、いくつかの追加機能に注目できます。顧客関数は、CUSTOMER_IDフィールドを介して請求書に関連付けられた顧客を返します。この関係を実装するには、belongsToメソッドを使用します。このメソッドには、モデルクラスの名前と通信フィールドの名前が渡されます。 lines関数は、モデルのInvoiceLineコレクション(後述)で表される請求書アイテムを返します。 1対多の関係を実装するには、関数linesManでhasManyメソッドを使用します。このメソッドには、モデルクラス名と通信フィールドが渡されます。LaravelドキュメントのRelationshipsセクションで、エンティティ間の関係の定義に関する詳細を読むことができます。



支払機能は請求書を支払います。これを行うには、ストアドプロシージャSP_PAY_FOR_INVOICEが呼び出されます。請求書識別子が送信されます。任意のフィールドの値(モデル属性)は、attributesプロパティから取得できます。ストアドプロシージャは、executeProcedureメソッドを使用して呼び出されます。このメソッドは、sim1984 / laravel-firebird拡張機能を使用する場合にのみ使用できます。



次に、請求書アイテムのモデルを作成します。



InvoiceLineモデル
 namespace App; use Firebird\Eloquent\Model; use Illuminate\Database\Eloquent\Builder; class InvoiceLine extends Model { /** * ,    * * @var string */ protected $table = 'INVOICE_LINE'; /** *    * * @var string */ protected $primaryKey = 'INVOICE_LINE_ID'; /** *       * * @var bool */ public $timestamps = false; /** *       * * @var string */ protected $sequence = 'GEN_INVOICE_LINE_ID'; /** *     * * @var array */ protected $appends = ['SUM_PRICE']; /** *  * * @return \App\Product */ public function product() { return $this->belongsTo('App\Product', 'PRODUCT_ID'); } /** *    * * @return double */ public function getSumPriceAttribute() { return $this->SALE_PRICE * $this->QUANTITY; } /** *      *   , ..         * * @param \Illuminate\Database\Eloquent\Builder $query * @param array $options * @return bool */ protected function performInsert(Builder $query, array $options = []) { if ($this->fireModelEvent('creating') === false) { return false; } $connection = $this->getConnection(); $attributes = $this->attributes; $connection->executeProcedure('SP_ADD_INVOICE_LINE', [ $attributes['INVOICE_ID'], $attributes['PRODUCT_ID'], $attributes['QUANTITY'] ]); // We will go ahead and set the exists property to true, so that it is set when // the created event is fired, just in case the developer tries to update it // during the event. This will allow them to do so and run an update here. $this->exists = true; $this->wasRecentlyCreated = true; $this->fireModelEvent('created', false); return true; } /** *        *   , ..         * * @param \Illuminate\Database\Eloquent\Builder $query * @param array $options * @return bool */ protected function performUpdate(Builder $query, array $options = []) { $dirty = $this->getDirty(); if (count($dirty) > 0) { // If the updating event returns false, we will cancel the update operation so // developers can hook Validation systems into their models and cancel this // operation if the model does not pass validation. Otherwise, we update. if ($this->fireModelEvent('updating') === false) { return false; } $connection = $this->getConnection(); $attributes = $this->attributes; $connection->executeProcedure('SP_EDIT_INVOICE_LINE', [ $attributes['INVOICE_LINE_ID'], $attributes['QUANTITY'] ]); $this->fireModelEvent('updated', false); } } /** *       *   , ..         * * @return void */ protected function performDeleteOnModel() { $connection = $this->getConnection(); $attributes = $this->attributes; $connection->executeProcedure('SP_DELETE_INVOICE_LINE', [$attributes['INVOICE_LINE_ID']]); } }
      
      







このモデルには、請求書アイテムで指定された製品(アプリ/製品モデル)を返す製品関数があります。通信は、belongsToメソッドを使用してPRODUCT_IDフィールドを使用して行われます。



計算されたSumPriceフィールドは、getSumPriceAttribute関数を使用して計算されます。この計算フィールドをモデルで使用できるようにするには、その名前を計算フィールド$ appendsの名前の配列で指定する必要があります。



このモデルでは、ストアドプロシージャを使用して実行されるように、挿入、更新、削除の各操作を再定義しました。これらのストアドプロシージャは、挿入、編集、および削除の操作に加えて、請求書のヘッダーの金額を再集計します。これは実行できませんでしたが、1つのトランザクションで複数のモデルの変更を実行する必要がありました。これを行う方法については後で説明します。



Laravelでモデルを操作してデータを選択、挿入、編集、削除する方法について少し話しましょう。Laravelはクエリデザイナーを使用してデータを操作します。このコンストラクタの構文と機能の完全な説明は、リンクで見つけることができますたとえば、すべてのサプライヤ文字列を取得するには、次のクエリを実行できます



 $customers = DB::table('CUSTOMER')->get();
      
      





このクエリデザイナは、SQLクエリを構築および実行するための非常に強力なツールです。たとえば、テーブルをフィルタリング、ソート、結合することもできます。



 DB::table('users') ->join('contacts', function ($join) { $join->on('users.id', '=', 'contacts.user_id')->orOn(...); }) ->get();
      
      





ただし、モデルを使用して作業する方がはるかに便利です。Eloquent ORMモデルとクエリ構文の説明は、laravel.ru / docs / v5 / eloquentにあります。したがって、サプライヤコレクション内のすべてのアイテムを取得するには、次のクエリを実行する必要があります



 $customers = Customer::all();
      
      





次のクエリは、アルファベット順にソートされた最初の20のサプライヤを返します。



 $customers = App\Customer::select() ->orderBy('name') ->take(20) ->get();
      
      





複雑なモデルの場合、関連する関係または関係のコレクションは、動的属性を介して取得できます。たとえば、次のクエリは識別子1の請求書アイテムを返します。



 $lines = Invoice::find(1)->lines;
      
      





レコードの追加は、モデルのインスタンスを作成し、そのプロパティを初期化し、saveメソッドを使用してモデルを保存することにより行われます。



 $flight = new Flight; $flight->name = $request->name; $flight->save();
      
      





レコードを変更するには、レコードを見つけ、必要な属性を変更し、saveメソッドを使用して保存する必要があります。



 $flight = App\Flight::find(1); $flight->name = 'New Flight Name'; $flight->save();
      
      





レコードを削除するには、レコードを見つけてdeleteメソッドを呼び出す必要があります。



 $flight = App\Flight::find(1); $flight->delete();
      
      





destroyメソッドを使用すると、キーでレコードをさらに速く削除できます。この場合、モデルのインスタンスを取得せずにモデルを削除できます。



 App\Flight::destroy(1);
      
      





一時削除など、レコードを削除する方法は他にもあります。削除方法の詳細については、こちらをご覧ください



次に、トランザクションについて少し説明しましょう。それが何であるかはお話ししませんが、Eloquent ORMと組み合わせて使用​​する方法を示します。



 DB::transaction(function () { //       $line = new App\InvoiceLine(); $line->CUSTOMER_ID = 45; $line->PRODUCT_ID = 342; $line->QUANTITY = 10; $line->COST = 12.45; $line->save(); //         $invoice = App\Invoice::find($line->CUSTOMER_ID); $invoice->INVOICE_SUM += $line->SUM_PRICE; $invoice->save(); });
      
      





トランザクションメソッドの引数であるコールバック関数内のすべては、単一のトランザクション内で実行されます。



コントローラーの作成とルーティングの構成



Laravelフレームワークには強力なルーティングサブシステムがあります。ルートを単純なコールバック関数とコントローラーメソッドの両方にマップできます。ルートの最も単純な例は次のようになります



 Route::get('/', function () { return 'Hello World'; }); Route::post('foo/bar', function () { return 'Hello World'; });
      
      





最初のケースでは、サイトのルートのGETリクエストハンドラーを登録します。2番目のケースでは、ルート/ foo / barを使用したPOSTリクエストの場合。



たとえば、複数のタイプのHTTPリクエストのルートを一度に登録できます。



 Route::match(['get', 'post'], 'foo/bar', function () { return 'Hello World'; });
      
      





ルートからアドレスの一部を抽出して、ハンドラー関数のパラメーターとして使用できます



 Route::get('posts/{post}/comments/{comment}', function ($postId, $commentId) { // });
      
      





ルートパラメータは常に中括弧で囲まれます。ルーティングを構成する可能性の詳細については、ドキュメントの「ルーティングの章を参照してください。ルートは、Laravel 5.2のapp / Http / routes.phpファイルとLaravel 5.3のroutes / wep.phpで設定されます。



単一のルーティングファイルですべてのリクエストの処理を記述する代わりに、関連するリクエストハンドラーを個別のクラスにグループ化できるコントローラークラスを使用して整理できます。コントローラーはapp / Http / Controllersフォルダーに保存されます。



すべてのLaravelコントローラーは、デフォルトのLaravelに存在するベースコントローラークラスApp \ Http \ Controllers \ Controllerを拡張する必要があります。コントローラーの作成の詳細については、「HTTPコントローラー」の章のドキュメントを参照してください。



最初のコントローラーを作成します。



 /* *   */ namespace App\Http\Controllers; use App\Http\Controllers\Controller; use App\Customer; class CustomerController extends Controller { /** *    * * @return Response */ public function showCustomers() { //     20  //    $customers = Customer::select() ->orderBy('NAME') ->take(20) ->get(); var_dump($customers); } }
      
      





ここで、コントローラーメソッドをルートに関連付ける必要があります。これを行うには、routes.php(web.php)に行を入力します



 Route::get('/customers', 'CustomerController@showCustomers');
      
      





ここで、コントローラーの名前は、@記号によってメソッド名と分離されています。



グリッドと編集ダイアログを使用してインターフェイスをすばやく構築するには、「zofe / rapydパッケージを使用します以前に接続しました。zofe / rapydパッケージのクラスは、Eloquent ORMモデルの典型的なクエリの構築を引き受けます。カスタマーコントローラーを変更して、データをグリッドに出力し、フィルター処理できるようにします。また、編集ダイアログでレコードを追加、編集、削除します。



カスタマーコントローラー
 /* *   */ namespace App\Http\Controllers; use App\Http\Controllers\Controller; use App\Customer; class CustomerController extends Controller { /** *    * * @return Response */ public function showCustomers() { //     $filter = \DataFilter::source(new Customer); //      $filter->add('NAME', '', 'text'); //     $filter->submit(''); //         $filter->reset(''); //       $grid = \DataGrid::source($filter); //   // , ,  $grid->add('NAME', '', true); $grid->add('ADDRESS', ''); $grid->add('ZIPCODE', ''); $grid->add('PHONE', ''); //    ,     $grid->edit('/customer/edit', '', 'show|modify|delete'); //     $grid->link('/customer/edit', " ", "TR"); //   $grid->orderBy('NAME', 'asc'); //      $grid->paginate(10); //   customer        return view('customer', compact('filter', 'grid')); } /** * ,     * * @return Response */ public function editCustomer() { if (\Input::get('do_delete') == 1) return "not the first"; //   $edit = \DataEdit::source(new Customer()); //         switch ($edit->status) { case 'create': $edit->label(' '); break; case 'modify': $edit->label(' '); break; case 'do_delete': $edit->label(' '); break; case 'show': $edit->label(' '); //         $edit->link('customers', '', 'TR'); break; } //     ,    //     $edit->back('insert|update|do_delete', 'customers'); //    ,    //       $edit->add('NAME', '', 'text')->rule('required|max:60'); $edit->add('ADDRESS', '', 'textarea') ->attributes(['rows' => 3]) ->rule('max:250'); $edit->add('ZIPCODE', '', 'text')->rule('max:10'); $edit->add('PHONE', '', 'text')->rule('max:14'); //   customer_edit      return $edit->view('customer_edit', compact('edit')); } }
      
      







Laravelはデフォルトでブレードテンプレートエンジンを使用します。view関数は、resources / viewsディレクトリで必要なテンプレートを見つけ、それに必要な置換を行い、HTMLページのテキストを返します。さらに、変数を渡して、テンプレートで使用できるようにします。ブレードテンプレートの構文の説明については、「ブレードテンプレートエンジニア」セクションのドキュメントを参照してください



顧客を表示するためのテンプレートは次のとおりです。



 @extends('example') @section('title','') @section('body') <h1></h1> <p> {!! $filter !!} {!! $grid !!} </p> @stop
      
      





このテンプレートは、サンプルテンプレートから継承され、その本体セクションをオーバーライドします。$フィルターおよび$グリッド変数には、グリッド内のデータをフィルタリングおよび表示するためのHTMLコードが含まれています。サンプルテンプレートはすべてのページに共通です。



Example.bladeテンプレート
 @extends('master') @section('title', '   Firebird') @section('body') <h1></h1> @if(Session::has('message')) <div class="alert alert-success"> {!! Session::get('message') !!} </div> @endif <p>   Firebird.<br/> </p> @stop @section('content') @include('menu') @yield('body') @stop
      
      







このテンプレート自体は、マスターテンプレートから継承され、さらにメニューテンプレートも含まれています。メニューは非常にシンプルで、顧客、製品、請求書の3つの項目で構成されています。



 <nav class="navbar main"> <div class="navbar-header"> <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".main-collapse"> <span class="sr-only"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> </div> <div class="collapse navbar-collapse main-collapse"> <ul class="nav nav-tabs"> <li @if (Request::is('customer*')) class="active"@endif>{!! link_to("customers", "") !!}</li> <li @if (Request::is('product*')) class="active"@endif>{!! link_to("products", "") !!}</li> <li @if (Request::is('invoice*')) class="active"@endif>{!! link_to("invoices", " ") !!}</li> </ul> </div> </nav>
      
      





マスターテンプレートでは、CSSスタイルとライブラリを含むJavaScriptファイルが接続されています。



Master.bladeテンプレート
 <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>@yield('title', ' Web   Firebird')</title> <meta name="description" content="@yield('description', ' Web   Firebird')" /> @section('meta', '') <link href="http://fonts.googleapis.com/css?family=Bitter" rel="stylesheet" type="text/css" /> <link href="//netdna.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet"> <link href="//maxcdn.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css" rel="stylesheet"> {!! Rapyd::styles(true) !!} </head> <body> <div id="wrap"> <div class="container"> <br /> <div class="row"> <div class="col-sm-12"> @yield('content') </div> </div> </div> </div> <div id="footer"> </div> <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script> <script src="//netdna.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.pjax/1.9.6/jquery.pjax.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/riot/2.2.4/riot+compiler.min.js"></script> {!! Rapyd::scripts() !!} </body> </html>
      
      







Customer_editカスタマーエディターテンプレートは次のとおりです。



 @extends('example') @section('title', ' ') @section('body') <p> {!! $edit !!} </p> @stop
      
      





製品コントローラは、サプライヤコントローラと同様に作成されます。



製品コントローラー
 /* *   */ namespace App\Http\Controllers; use App\Http\Controllers\Controller; use App\Product; class ProductController extends Controller { /** *    * * @return Response */ public function showProducts() { //     $filter = \DataFilter::source(new Product); //      $filter->add('NAME', '', 'text'); $filter->submit(''); $filter->reset(''); //       $grid = \DataGrid::source($filter); //    // , ,  $grid->add('NAME', '', true); //    2    $grid->add('PRICE|number_format[2,., ]', ''); $grid->row(function($row) { //     $row->cell('PRICE')->style("text-align: right"); }); //    ,     $grid->edit('/product/edit', '', 'show|modify|delete'); //     $grid->link('/product/edit', " ", "TR"); //   $grid->orderBy('NAME', 'asc'); //      $grid->paginate(10); //   customer        return view('product', compact('filter', 'grid')); } /** * ,     * * @return Response */ public function editProduct() { if (\Input::get('do_delete') == 1) return "not the first"; //   $edit = \DataEdit::source(new Product()); //         switch ($edit->status) { case 'create': $edit->label(' '); break; case 'modify': $edit->label(' '); break; case 'do_delete': $edit->label(' '); break; case 'show': $edit->label(' '); $edit->link('products', '', 'TR'); break; } //     ,    //     $edit->back('insert|update|do_delete', 'products'); //    ,    //       $edit->add('NAME', '', 'text')->rule('required|max:100'); $edit->add('PRICE', '', 'text')->rule('max:19'); $edit->add('DESCRIPTION', '', 'textarea') ->attributes(['rows' => 8]) ->rule('max:8192'); //   product_edit      return $edit->view('product_edit', compact('edit')); } }
      
      







請求書コントローラーはより複雑です。請求書支払いの追加機能が追加されました。支払済みの請求書は別の色で強調表示されます。請求書を表示すると、その位置も表示されます。編集中、請求書の請求書には位置を編集する機能があります。次に、コントローラーのテキストに詳細なコメントを付けます。



請求書管理者
 /* *    */ namespace App\Http\Controllers; use App\Http\Controllers\Controller; use App\Invoice; use App\Customer; use App\Product; use App\InvoiceLine; class InvoiceController extends Controller { /** *   - * * @return Response */ public function showInvoices() { //      //    $invoices = Invoice::with('customer'); //     $filter = \DataFilter::source($invoices); //      $filter->add('INVOICE_DATE', '', 'daterange'); //      $filter->add('customer.NAME', '', 'text'); $filter->submit(''); $filter->reset(''); //       $grid = \DataGrid::source($filter); //    // , ,  //     ,      $grid->add('INVOICE_DATE|strtotime|date[dmY H:i:s]', '', true); //          $grid->add('TOTAL_SALE|number_format[2,., ]', ''); $grid->add('customer.NAME', ''); //  boolean   / $grid->add('PAID', '') ->cell(function( $value, $row) { return $value ? '' : ''; }); //      $grid->row(function($row) { //     $row->cell('TOTAL_SALE')->style("text-align: right"); //       if ($row->cell('PAID')->value == '') { $row->style("background-color: #ddffee;"); } }); //    ,     $grid->edit('/invoice/edit', '', 'show|modify|delete'); //    - $grid->link('/invoice/edit', " ", "TR"); //   $grid->orderBy('INVOICE_DATE', 'desc'); //      $grid->paginate(10); //   customer        return view('invoice', compact('filter', 'grid')); } /** * ,      * * @return Response */ public function editInvoice() { //    ,    $error_msg = \Request::old('error_msg'); //     $edit = \DataEdit::source(new Invoice()); //   ,        if (($edit->model->PAID) && ($edit->status === 'modify')) { $edit->status = 'show'; $error_msg = '  .   .'; } //   ,        if (($edit->model->PAID) && ($edit->status === 'delete')) { $edit->status = 'show'; $error_msg = '  .   .'; } //         switch ($edit->status) { case 'create': $edit->label(' '); break; case 'modify': $edit->label(' '); break; case 'do_delete': $edit->label(' '); break; case 'show': $edit->label(''); $edit->link('invoices', '', 'TR'); //     ,    if (!$edit->model->PAID) $edit->link('invoice/pay/' . $edit->model->INVOICE_ID, '', 'BL'); break; } //     ,    //      $edit->back('insert|update|do_delete', 'invoices'); //    ,    //      $edit->add('INVOICE_DATE', '', 'datetime') ->rule('required') ->insertValue(date('Ymd H:i:s')); //     .     //     $edit->add('customer.NAME', '', 'autocomplete') ->rule('required') ->options(Customer::lists('NAME', 'CUSTOMER_ID')->all()); //  ,     ,    $edit->add('TOTAL_SALE', '', 'text') ->mode('readonly') ->insertValue('0.00'); //    $paidCheckbox = $edit->add('PAID', '', 'checkbox') ->insertValue('0') ->mode('readonly'); $paidCheckbox->checked_output = ''; $paidCheckbox->unchecked_output = ''; //        $grid = $this->getInvoiceLineGrid($edit->model, $edit->status); //   invoice_edit       //     return $edit->view('invoice_edit', compact('edit', 'grid', 'error_msg')); } /** *    * * @return Response */ public function payInvoice($id) { try { //      $invoice = Invoice::findOrFail($id); //    $invoice->pay(); } catch (\Illuminate\Database\QueryException $e) { //   ,  //    $pos = strpos($e->getMessage(), 'E_INVOICE_ALREADY_PAYED'); if ($pos !== false) { //         return redirect('invoice/edit?show=' . $id) ->withInput(['error_msg' => '  ']); } else throw $e; } //     return redirect('invoice/edit?show=' . $id); } /** *       * @param \App\Invoice $invoice * @param string $mode * @return \DataGrid */ private function getInvoiceLineGrid(Invoice $invoice, $mode) { //     //           $lines = InvoiceLine::with('product')->where('INVOICE_ID', $invoice->INVOICE_ID); //       $grid = \DataGrid::source($lines); //    // , ,  $grid->add('product.NAME', ''); $grid->add('QUANTITY', ''); $grid->add('SALE_PRICE|number_format[2,., ]', '')->style('min-width: 8em;'); $grid->add('SUM_PRICE|number_format[2,., ]', '')->style('min-width: 8em;'); //      $grid->row(function($row) { $row->cell('QUANTITY')->style("text-align: right"); //     $row->cell('SALE_PRICE')->style("text-align: right"); $row->cell('SUM_PRICE')->style("text-align: right"); }); if ($mode == 'modify') { //    ,     $grid->edit('/invoice/editline', '', 'modify|delete'); //     $grid->link('/invoice/editline?invoice_id=' . $invoice->INVOICE_ID, " ", "TR"); } return $grid; } /** * ,       * * @return Response */ public function editInvoiceLine() { if (\Input::get('do_delete') == 1) return "not the first"; $invoice_id = null; //      $edit = \DataEdit::source(new InvoiceLine()); //         switch ($edit->status) { case 'create': $edit->label(' '); $invoice_id = \Input::get('invoice_id'); break; case 'modify': $edit->label(' '); $invoice_id = $edit->model->INVOICE_ID; break; case 'delete': $invoice_id = $edit->model->INVOICE_ID; break; case 'do_delete': $edit->label(' '); $invoice_id = $edit->model->INVOICE_ID; break; } //  url   $base = str_replace(\Request::path(), '', strtok(\Request::fullUrl(), '?')); $back_url = $base . 'invoice/edit?modify=' . $invoice_id; //     $edit->back('insert|update|do_delete', $back_url); $edit->back_url = $back_url; //        $edit->add('INVOICE_ID', '', 'hidden') ->rule('required') ->insertValue($invoice_id) ->updateValue($invoice_id); //     .     //     $edit->add('product.NAME', '', 'autocomplete') ->rule('required') ->options(Product::lists('NAME', 'PRODUCT_ID')->all()); //     $edit->add('QUANTITY', '', 'text') ->rule('required'); //   invoice_line_edit      return $edit->view('invoice_line_edit', compact('edit')); } }
      
      







請求書の位置を含むグリッドを表示する必要があるため、請求書エディターはzofe / rapydの標準ではありません。これを行うために、invoice_editテンプレートを次のように変更しました。



Invoice_edit.bladeテンプレート
 @extends('example') @section('title',' ') @section('body') <div class="container"> {!! $edit->header !!} @if($error_msg) <div class="alert alert-danger"> <strong>!</strong> {{ $error_msg }} </div> @endif {!! $edit->message !!} @if(!$edit->message) <div class="row"> <div class="col-sm-4"> {!! $edit->render('INVOICE_DATE') !!} {!! $edit->render('customer.NAME') !!} {!! $edit->render('TOTAL_SALE') !!} {!! $edit->render('PAID') !!} </div> </div> {!! $grid !!} @endif {!! $edit->footer !!} </div> @stop
      
      







すべてのコントローラーが作成されたので、ルートを変更して、Webサイトが開始ページで請求書のリストを開くようにします。ルートはLaravel 5.2のapp / Http / routes.phpファイルとLaravel 5.3のroutes / wep.phpで設定されることを思い出してください。



 //   Route::get('/', 'InvoiceController@showInvoices'); Route::get('/customers', 'CustomerController@showCustomers'); Route::any('/customer/edit', 'CustomerController@editCustomer'); Route::get('/products', 'ProductController@showProducts'); Route::any('/product/edit', 'ProductController@editProduct'); Route::get('/invoices', 'InvoiceController@showInvoices'); Route::any('/invoice/edit', 'InvoiceController@editInvoice'); Route::any('/invoice/pay/{id}', 'InvoiceController@payInvoice'); Route::any('/invoice/editline', 'InvoiceController@editInvoiceLine');
      
      





ここで、ルート/請求書/支払い/ {id}は、住所から請求書識別子を選択し、それをpayInvoiceメソッドに渡します。他のルートでは、個別の説明は不要です。



最後に、結果のWebアプリケーションのスクリーンショットをいくつか示します。











これで私の例を完了しました。ソースコードはhttps://github.com/sim1984/phpfbexampleからダウンロードできます



All Articles