ActiveRelation.php 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. <?php
  2. /**
  3. * @author Qiang Xue <[email protected]>
  4. * @link http://www.yiiframework.com/
  5. * @copyright Copyright (c) 2008 Yii Software LLC
  6. * @license http://www.yiiframework.com/license/
  7. */
  8. namespace yii\db;
  9. /**
  10. * ActiveRelation represents a relation between two Active Record classes.
  11. *
  12. * ActiveRelation instances are usually created by calling [[ActiveRecord::hasOne()]] and
  13. * [[ActiveRecord::hasMany()]]. An Active Record class declares a relation by defining
  14. * a getter method which calls one of the above methods and returns the created ActiveRelation object.
  15. *
  16. * A relation is specified by [[link]] which represents the association between columns
  17. * of different tables; and the multiplicity of the relation is indicated by [[multiple]].
  18. *
  19. * If a relation involves a pivot table, it may be specified by [[via()]] or [[viaTable()]] method.
  20. *
  21. * @author Qiang Xue <[email protected]>
  22. * @author Carsten Brandt <[email protected]>
  23. * @since 2.0
  24. */
  25. class ActiveRelation extends ActiveQuery implements ActiveRelationInterface
  26. {
  27. use ActiveRelationTrait;
  28. /**
  29. * @var string|array the join condition. Please refer to [[Query::where()]] on how to specify this parameter.
  30. * The condition will be used in the ON part when [[ActiveQuery::joinRelation()]] is called.
  31. * Otherwise, the condition will be used in the WHERE part of a query.
  32. */
  33. public $on;
  34. /**
  35. * Sets the ON condition for the query.
  36. * The condition will be used in the ON part when [[ActiveQuery::joinRelation()]] is called.
  37. * Otherwise, the condition will be used in the WHERE part of a query.
  38. * @param string|array $condition the ON condition. Please refer to [[Query::where()]] on how to specify this parameter.
  39. * @param array $params the parameters (name => value) to be bound to the query.
  40. * @return static the query object itself
  41. */
  42. public function onCondition($condition, $params = [])
  43. {
  44. $this->on = $condition;
  45. $this->addParams($params);
  46. return $this;
  47. }
  48. /**
  49. * Specifies the pivot table.
  50. * @param string $tableName the name of the pivot table.
  51. * @param array $link the link between the pivot table and the table associated with [[primaryModel]].
  52. * The keys of the array represent the columns in the pivot table, and the values represent the columns
  53. * in the [[primaryModel]] table.
  54. * @param callable $callable a PHP callback for customizing the relation associated with the pivot table.
  55. * Its signature should be `function($query)`, where `$query` is the query to be customized.
  56. * @return static
  57. */
  58. public function viaTable($tableName, $link, $callable = null)
  59. {
  60. $relation = new ActiveRelation([
  61. 'modelClass' => get_class($this->primaryModel),
  62. 'from' => [$tableName],
  63. 'link' => $link,
  64. 'multiple' => true,
  65. 'asArray' => true,
  66. ]);
  67. $this->via = $relation;
  68. if ($callable !== null) {
  69. call_user_func($callable, $relation);
  70. }
  71. return $this;
  72. }
  73. /**
  74. * Creates a DB command that can be used to execute this query.
  75. * @param Connection $db the DB connection used to create the DB command.
  76. * If null, the DB connection returned by [[modelClass]] will be used.
  77. * @return Command the created DB command instance.
  78. */
  79. public function createCommand($db = null)
  80. {
  81. if ($this->primaryModel === null) {
  82. // eager loading
  83. if (!empty($this->on)) {
  84. $where = $this->where;
  85. $this->andWhere($this->on);
  86. $command = parent::createCommand($db);
  87. $this->where = $where;
  88. return $command;
  89. } else {
  90. return parent::createCommand($db);
  91. }
  92. }
  93. // lazy loading
  94. $where = $this->where;
  95. if ($this->via instanceof self) {
  96. // via pivot table
  97. $viaModels = $this->via->findPivotRows([$this->primaryModel]);
  98. $this->filterByModels($viaModels);
  99. } elseif (is_array($this->via)) {
  100. // via relation
  101. /** @var ActiveRelation $viaQuery */
  102. list($viaName, $viaQuery) = $this->via;
  103. if ($viaQuery->multiple) {
  104. $viaModels = $viaQuery->all();
  105. $this->primaryModel->populateRelation($viaName, $viaModels);
  106. } else {
  107. $model = $viaQuery->one();
  108. $this->primaryModel->populateRelation($viaName, $model);
  109. $viaModels = $model === null ? [] : [$model];
  110. }
  111. $this->filterByModels($viaModels);
  112. } else {
  113. $this->filterByModels([$this->primaryModel]);
  114. }
  115. if (!empty($this->on)) {
  116. $this->andWhere($this->on);
  117. }
  118. $command = parent::createCommand($db);
  119. $this->where = $where;
  120. return $command;
  121. }
  122. }