| 380 | | ++ Auto loading models |
| 381 | | ++ Command line interface |
| 382 | | ++ My first project tutorial |
| | 380 | ++ 自動的にモデルをロードする |
| | 381 | |
| | 382 | Doctrineには2種類のモデルをロードする方法があります。コンサバティブな(怠けた)ローディングとアグレッシブなローディングです。コンサバティブローディングはPHPファイルを最初は必要としませんが、その代わりクラスの名前にパスの名前をキャッシュしてパスの名前がspl_autoload_register(array('Doctrine', 'autoload'))で登録したDoctrine::autoload() によって使われます。以下が両方のタイプのモデルローディングの例です |
| | 383 | |
| | 384 | +++ コンサバティブ |
| | 385 | |
| | 386 | コンサバティブモデルローディングは公開環境に最適なモデルローディング法です。このやり方ではモデルローディングが実行されたときでは無く、すべてのモデルが何もしなくてもロードされます。 |
| | 387 | |
| | 388 | コンサバティブモデルローディングでは一つのファイルに必ず一つだけクラスが入っている必要があり、ファイル名をクラス名と同じにする必要があります。例えば、Userクラスがある場合ファイル名もUser.phpにする必要があります。 |
| | 389 | |
| | 390 | 以下がコンサバティブローディングを使った基本的なDoctrineの実装です |
| | 391 | |
| | 392 | <code type="php"> |
| | 393 | //Doctrineベースクラスをロード |
| | 394 | require_once('path-to-doctrine/lib/Doctrine.php'); |
| | 395 | |
| | 396 | //autoloaderを登録 |
| | 397 | spl_autoload_register(array('Doctrine', 'autoload')); |
| | 398 | |
| | 399 | Doctrine_Manager::getInstance()->setAttribute('model_loading', 'conservative'); |
| | 400 | Doctrine::loadModels('/path/to/models'); // これで.phpを指定する必要なし |
| | 401 | |
| | 402 | $user = new User(); // これでDoctrine::autoload()が起動され、ファイルがインクルードされ、Userクラスが扱えるようになります |
| | 403 | </code> |
| | 404 | |
| | 405 | +++ アグレッシブ |
| | 406 | |
| | 407 | アグレッシブモデルローディングはデフォルトのローディング法でとてもシンプルです。この方法では.php 拡張子のついたすべてのファイルを探し、見つかった全てのファイルをインクルードします。Doctrineはクラス継承を扱わないため、モデルが別のモデルを継承している場合はうまくモデルをインクルードできないので全ての依存関係を正常に保つのには注意が必要です。 |
| | 408 | |
| | 409 | アグレッシブモデルローディングを使うことで、一つのファイル内に複数のクラスを持たせることができ、ファイル名とクラス名を一致させる必要はありません。 |
| | 410 | |
| | 411 | アグレッシブモデルローディングの欠点リクエスト毎に全てのphpファイルがインクルードされてしまうことなので、モデルの数が増えてきた場合コンサバティブモデルローディングを使うことをお勧めします。 |
| | 412 | |
| | 413 | 以下がアグレッシブモデルローディングを使ったDoctrineの実装です |
| | 414 | |
| | 415 | <code type="php"> |
| | 416 | //ベースDoctrineクラスをインクルード |
| | 417 | require_once('path-to-doctrine/lib/Doctrine.php'); |
| | 418 | |
| | 419 | //autoloaderの登録 |
| | 420 | spl_autoload_register(array('Doctrine', 'autoload')); |
| | 421 | |
| | 422 | Doctrine_Manager::getInstance()->setAttribute('model_loading', 'aggressive'); |
| | 423 | Doctrine::loadModels('/path/to/models'); // This call will not require the found .php files |
| | 424 | |
| | 425 | $user = new User(); // これでDoctrine::autoload()が起動され、ファイルがインクルードされ、Userクラスが扱えるようになります |
| | 426 | </code> |
| | 427 | |
| | 428 | ++ コマンドラインインターフェース |
| | 429 | |
| | 430 | コマンドラインインターフェースはDoctrineで最もよく使われるタスクをコマンドラインから実行できるようにしたものです。コマンドラインインターフェースについての詳細は [doc utilities:command-line-interface :index :name] の節にあります。 |
| | 431 | |
| | 432 | ++ 一番最初のプロジェクトのチュートリアル |
| | 433 | |
| | 434 | +++ はじめに |
| | 435 | |
| | 436 | このチュートリアルでは機能満載のPHP Doctrine ORMを使ってあなたの一番最初のプロジェクトを作ってみます。このチュートリアルではすぐに使えるDoctrine sandboxパッケージを使います。またwebブラウザー、PHPとPDO + Sqliteが必要です。 |
| | 437 | |
| | 438 | +++ ダウンロード |
| | 439 | |
| | 440 | まず始めるにあたり最新のDoctrine sandboxパッケージをダウンロードします:http://www.phpdoctrine.org/download 次にダウンロードしたファイルを展開すると Doctrine-x.x.x-Sandbox というディレクトリが作られるはずです。このディレクトリにはDoctrineを使ったwebアプリケーションの簡単な例が入っています。 |
| | 441 | |
| | 442 | +++ パッケージの中身 |
| | 443 | |
| | 444 | ファイルやディレクトリの構造は以下の様になっているはずです |
| | 445 | <code> |
| | 446 | $ cd Doctrine-0.10.1-Sandbox |
| | 447 | $ ls |
| | 448 | config.php doctrine index.php migrations schema |
| | 449 | data doctrine.php lib models |
| | 450 | </code> |
| | 451 | |
| | 452 | このsandboxは設定をする必要はなく、sqlデータベースで使うことができるようになっています。以下が各ファイルの説明と目的です |
| | 453 | |
| | 454 | * doctrine - コマンドラインインターフェース実行のためのシェルスクリプト。./doctrine で実行してコマンド一覧を見るか、./doctrine help として各コマンドの詳細をみてください |
| | 455 | * doctrine.php - Doctrineのコマンドラインインターフェースを実装しているphpスクリプト。上のDoctrineシェルスクリプトでインクルードされる |
| | 456 | * index.php - webアプリケーションの為のフロントwebコントローラー |
| | 457 | * migrations - migrationクラスの為のフォルダ |
| | 458 | * schema - スキーマファイルのフォルダ |
| | 459 | * models - モデルファイルのフォルダ |
| | 460 | * lib - Doctrineコアライブラリファイルのフォルダ |
| | 461 | |
| | 462 | |
| | 463 | +++ CLI(クライアントプログラム)の実行 |
| | 464 | |
| | 465 | Doctrineのシェルスクリプトをコマンドラインから実行すると以下の様なアウトプットがでるはずです: |
| | 466 | |
| | 467 | <code> |
| | 468 | $ ./doctrine |
| | 469 | Doctrine Command Line Interface |
| | 470 | |
| | 471 | ./doctrine build-all |
| | 472 | ./doctrine build-all-load |
| | 473 | ./doctrine build-all-reload |
| | 474 | ./doctrine compile |
| | 475 | ./doctrine create-db |
| | 476 | ./doctrine create-tables |
| | 477 | ./doctrine dql |
| | 478 | ./doctrine drop-db |
| | 479 | ./doctrine dump-data |
| | 480 | ./doctrine generate-migration |
| | 481 | ./doctrine generate-migrations-db |
| | 482 | ./doctrine generate-migrations-models |
| | 483 | ./doctrine generate-models-db |
| | 484 | ./doctrine generate-models-yaml |
| | 485 | ./doctrine generate-sql |
| | 486 | ./doctrine generate-yaml-db |
| | 487 | ./doctrine generate-yaml-models |
| | 488 | ./doctrine load-data |
| | 489 | ./doctrine load-dummy-data |
| | 490 | ./doctrine migrate |
| | 491 | ./doctrine rebuild-db |
| | 492 | </code> |
| | 493 | |
| | 494 | +++ スキーマの定義 |
| | 495 | |
| | 496 | 以下がサンプルyamlスキーマファイルです。yamlファイルは schemas/schema.yml に保存します。このコマンドラインインターフェースはschemasフォルダ内にある全ての *.yml ファイルを探します。 |
| | 497 | |
| | 498 | |
| | 499 | <code type="yaml"> |
| | 500 | --- |
| | 501 | User: |
| | 502 | columns: |
| | 503 | id: |
| | 504 | primary: true |
| | 505 | autoincrement: true |
| | 506 | type: integer(4) |
| | 507 | username: string(255) |
| | 508 | password: string(255) |
| | 509 | relations: |
| | 510 | Groups: |
| | 511 | class: Group |
| | 512 | refClass: UserGroup |
| | 513 | foreignAlias: Users |
| | 514 | |
| | 515 | Group: |
| | 516 | tableName: groups |
| | 517 | columns: |
| | 518 | id: |
| | 519 | primary: true |
| | 520 | autoincrement: true |
| | 521 | type: integer(4) |
| | 522 | name: string(255) |
| | 523 | |
| | 524 | UserGroup: |
| | 525 | columns: |
| | 526 | user_id: integer(4) |
| | 527 | group_id: integer(4) |
| | 528 | relations: |
| | 529 | User: |
| | 530 | onDelete: CASCADE |
| | 531 | Group: |
| | 532 | onDelete: CASCADE |
| | 533 | </code> |
| | 534 | |
| | 535 | +++ データフィクスチャのテスト |
| | 536 | |
| | 537 | 以下がサンプルのデータフィクスチャのファイルになります。このファイルを data/fixtures/data.yml 以下に保存します。コマンドラインインターフェースは data/fixtures にある全ての *.yml ファイルを探します。 |
| | 538 | |
| | 539 | <code type="yaml"> |
| | 540 | --- |
| | 541 | User: |
| | 542 | zyne: |
| | 543 | username: zYne- |
| | 544 | password: changeme |
| | 545 | Groups: [founder, lead, documentation] |
| | 546 | jwage: |
| | 547 | username: jwage |
| | 548 | password: changeme |
| | 549 | Groups: [lead, documentation] |
| | 550 | |
| | 551 | Group: |
| | 552 | founder: |
| | 553 | name: Founder |
| | 554 | lead: |
| | 555 | name: Lead |
| | 556 | documentation: |
| | 557 | name: Documentation |
| | 558 | </code> |
| | 559 | |
| | 560 | +++ 全てのビルド |
| | 561 | |
| | 562 | これでスキーマファイルとデータフィクスチャが用意できたので、全てのビルドを行いモデルを使うことができるようになります。以下のコマンドを実行すると models フォルダにモデルが生成されます。 |
| | 563 | |
| | 564 | <code> |
| | 565 | $ ./doctrine build-all-reload |
| | 566 | build-all-reload - Are you sure you wish to drop your databases? (y/n) |
| | 567 | y |
| | 568 | build-all-reload - Successfully dropped database for connection "sandbox" at path "/Users/jwage/Sites/doctrine/branches/0.10/tools/sandbox/sandbox.db" |
| | 569 | build-all-reload - Generated models successfully from YAML schema |
| | 570 | build-all-reload - Successfully created database for connection "sandbox" at path "/Users/jwage/Sites/doctrine/branches/0.10/tools/sandbox/sandbox.db" |
| | 571 | build-all-reload - Created tables successfully |
| | 572 | build-all-reload - Data was successfully loaded |
| | 573 | </code> |
| | 574 | |
| | 575 | models フォルダを見ると modelクラスが生成されているのが確認できるはずです。これで index.php にコードを書いてDoctrineを使ってみることができるようになりました。index.php の中に以下の様なシンプルなテストを書いてみてください。 |
| | 576 | |
| | 577 | +++ テストの実行 |
| | 578 | |
| | 579 | <code type="php"> |
| | 580 | $query = new Doctrine_Query(); |
| | 581 | $query->from('User u, u.Groups g'); |
| | 582 | |
| | 583 | $users = $query->execute(); |
| | 584 | |
| | 585 | echo '<pre>'; |
| | 586 | print_r($users->toArray(true)); |
| | 587 | </code> |
| | 588 | |
| | 589 | print_r() が以下のデータの出力を行うはずです。このデータは data/fixtures の中に置いたyamlファイルから保存されたデータだということが分かるはずです。フィクスチャの中にデータを追加して、build-all-reloadをもう一度走らせデータベースを再初期化することも可能です。 |
| | 590 | |
| | 591 | |
| | 592 | <code> |
| | 593 | Array |
| | 594 | ( |
| | 595 | [0] => Array |
| | 596 | ( |
| | 597 | [id] => 1 |
| | 598 | [username] => zYne- |
| | 599 | [password] => changeme |
| | 600 | [Groups] => Array |
| | 601 | ( |
| | 602 | [0] => Array |
| | 603 | ( |
| | 604 | [id] => 1 |
| | 605 | [name] => Founder |
| | 606 | ) |
| | 607 | |
| | 608 | [1] => Array |
| | 609 | ( |
| | 610 | [id] => 2 |
| | 611 | [name] => Lead |
| | 612 | ) |
| | 613 | |
| | 614 | [2] => Array |
| | 615 | ( |
| | 616 | [id] => 3 |
| | 617 | [name] => Documentation |
| | 618 | ) |
| | 619 | |
| | 620 | ) |
| | 621 | |
| | 622 | ) |
| | 623 | |
| | 624 | [1] => Array |
| | 625 | ( |
| | 626 | [id] => 2 |
| | 627 | [username] => jwage |
| | 628 | [password] => changeme |
| | 629 | [Groups] => Array |
| | 630 | ( |
| | 631 | [0] => Array |
| | 632 | ( |
| | 633 | [id] => 2 |
| | 634 | [name] => Lead |
| | 635 | ) |
| | 636 | |
| | 637 | [1] => Array |
| | 638 | ( |
| | 639 | [id] => 3 |
| | 640 | [name] => Documentation |
| | 641 | ) |
| | 642 | |
| | 643 | ) |
| | 644 | |
| | 645 | ) |
| | 646 | |
| | 647 | ) |
| | 648 | </code> |
| | 649 | |
| | 650 | またdqlコマンドライン機能を使ってDQLクエリをデータベースに対して実行することも可能です。以下の様に使われます。 |
| | 651 | |
| | 652 | <code> |
| | 653 | jwage:sandbox jwage$ ./doctrine dql "FROM User u, u.Groups g" |
| | 654 | dql - executing: "FROM User u, u.Groups g" () |
| | 655 | dql - - |
| | 656 | dql - id: 1 |
| | 657 | dql - username: zYne- |
| | 658 | dql - password: changeme |
| | 659 | dql - Groups: |
| | 660 | dql - - |
| | 661 | dql - id: 1 |
| | 662 | dql - name: Founder |
| | 663 | dql - - |
| | 664 | dql - id: 2 |
| | 665 | dql - name: Lead |
| | 666 | dql - - |
| | 667 | dql - id: 3 |
| | 668 | dql - name: Documentation |
| | 669 | dql - - |
| | 670 | dql - id: 2 |
| | 671 | dql - username: jwage |
| | 672 | dql - password: changeme |
| | 673 | dql - Groups: |
| | 674 | dql - - |
| | 675 | dql - id: 2 |
| | 676 | dql - name: Lead |
| | 677 | dql - - |
| | 678 | dql - id: 3 |
| | 679 | dql - name: Documentation |
| | 680 | </code> |
| | 681 | |
| | 682 | +++ ユーザーCRUD |
| | 683 | |
| | 684 | これでDoctrineを使ってとっても単純なユーザーとパスワードを扱う実装をやってみることができるようになりました。以下のコードをindex.php内に置いてブラウザーから読み込んでください。簡単なアプリケーションが実行できます。 |
| | 685 | |
| | 686 | <code type="php"> |
| | 687 | require_once('config.php'); |
| | 688 | |
| | 689 | Doctrine::loadModels('models'); |
| | 690 | |
| | 691 | $module = isset($_REQUEST['module']) ? $_REQUEST['module']:'users'; |
| | 692 | $action = isset($_REQUEST['action']) ? $_REQUEST['action']:'list'; |
| | 693 | |
| | 694 | if ($module == 'users') { |
| | 695 | $userId = isset($_REQUEST['id']) && $_REQUEST['id'] > 0 ? $_REQUEST['id']:null; |
| | 696 | $userTable = Doctrine::getTable('User'); |
| | 697 | |
| | 698 | if ($userId === null) { |
| | 699 | $user = new User(); |
| | 700 | } else { |
| | 701 | $user = $userTable->find($userId); |
| | 702 | } |
| | 703 | |
| | 704 | switch ($action) { |
| | 705 | case 'edit': |
| | 706 | case 'add': |
| | 707 | echo '<form action="index.php?module=users&action=save" method="POST"> |
| | 708 | <fieldset> |
| | 709 | <legend>User</legend> |
| | 710 | <input type="hidden" name="id" value="' . $user->id . '" /> |
| | 711 | <label for="username">Username</label> <input type="text" name="user[username]" value="' . $user->username . '" /> |
| | 712 | <label for="password">Password</label> <input type="text" name="user[password]" value="' . $user->password . '" /> |
| | 713 | <input type="submit" name="save" value="Save" /> |
| | 714 | </fieldset |
| | 715 | </form>'; |
| | 716 | break; |
| | 717 | case 'save': |
| | 718 | $user->merge($_REQUEST['user']); |
| | 719 | $user->save(); |
| | 720 | |
| | 721 | header('location: index.php?module=users&action=edit&id=' . $user->id); |
| | 722 | break; |
| | 723 | case 'delete': |
| | 724 | $user->delete(); |
| | 725 | |
| | 726 | header('location: index.php?module=users&action=list'); |
| | 727 | break; |
| | 728 | default: |
| | 729 | $query = new Doctrine_Query(); |
| | 730 | $query->from('User u') |
| | 731 | ->orderby('u.username'); |
| | 732 | |
| | 733 | $users = $query->execute(); |
| | 734 | |
| | 735 | echo '<ul>'; |
| | 736 | foreach ($users as $user) { |
| | 737 | echo '<li><a href="index.php?module=users&action=edit&id=' . $user->id . '">' . $user->username . '</a> <a href="index.php?module=users&action=delete&id=' . $user->id . '">[X]</a></li>'; |
| | 738 | } |
| | 739 | echo '</ul>'; |
| | 740 | } |
| | 741 | |
| | 742 | echo '<ul> |
| | 743 | <li><a href="index.php?module=users&action=add">Add</a></li> |
| | 744 | <li><a href="index.php?module=users&action=list">List</a></li> |
| | 745 | </ul>'; |
| | 746 | } else { |
| | 747 | throw new Exception('Invalid module'); |
| | 748 | } |
| | 749 | </code> |