Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>It turns out you can't. At least not with the syntax provided above and not with CakePHP 1.2.6. I went over the source (yay! to open source frameworks!) and found the file <code>cake/libs/model/datasources/dbo_source.php</code> which contains the code for the joins.</p> <p>It all starts with <code>DboSource::renderStatement()</code> which does a shallow walk of the <code>$query['joins']</code> array, replacing those join definitions with SQL fragments via <code>DboSource::buildJoinStatement($join)</code>, which does some tidying up of the arguments (filling in blanks etc.) and then calls <code>DboSource::renderJoinStatement</code> to create the SQL fragment of a single join clause.</p> <blockquote> <p><em>me:</em> That should be easy to fix!</p> </blockquote> <p>I was told not to edit stuff in <code>cake/libs</code>, so instead I copied the file <code>dbo_source.php</code> to <code>app/models/datasources/</code> for editing. Then I took my axe and refactored the shallow walk of the <code>$query['joins']</code> array in <code>DboSource::renderStatement()</code> into a new method <code>DboSource::buildJoinStatementArray()</code> resulting in these two methods:</p> <pre><code>function buildStatement($query, $model) { $query = array_merge(array('offset' =&gt; null, 'joins' =&gt; array()), $query); # refactored (extract method) to make recursion easier $query['joins'] = $this-&gt;buildJoinStatementArray($query['joins']); return $this-&gt;renderStatement('select', array( 'conditions' =&gt; $this-&gt;conditions($query['conditions'], true, true, $model), 'fields' =&gt; implode(', ', $query['fields']), 'table' =&gt; $query['table'], 'alias' =&gt; $this-&gt;alias . $this-&gt;name($query['alias']), 'order' =&gt; $this-&gt;order($query['order']), 'limit' =&gt; $this-&gt;limit($query['limit'], $query['offset']), 'joins' =&gt; implode(' ', $query['joins']), 'group' =&gt; $this-&gt;group($query['group']) )); } /** * Replaces the join statement array syntax with SQL join clauses. */ function buildJoinStatementArray($joins) { if (!empty($joins)) { $count = count($joins); for ($i = 0; $i &lt; $count; $i++) { if (is_array($joins[$i])) { $joins[$i] = $this-&gt;buildJoinStatement($joins[$i]); # $joins[$i] now contains something like "LEFT JOIN users As User on User.group_id = Group.id" } } } return $joins; } </code></pre> <p>Once I had <code>DboSource::buildJoinStatementArray()</code>, it was time to change <code>DboSource::buildJoinStatement()</code> - all I did was added a check for <code>$data['joins']</code> and an alternative rendering method for that case:</p> <pre><code>function buildJoinStatement($join) { $data = array_merge(array( 'type' =&gt; null, 'alias' =&gt; null, 'table' =&gt; 'join_table', 'conditions' =&gt; array() ), $join); if (!empty($data['alias'])) { $data['alias'] = $this-&gt;alias . $this-&gt;name($data['alias']); } if (!empty($data['conditions'])) { $data['conditions'] = trim($this-&gt;conditions($data['conditions'], true, false)); } # allow for nested joins if (!empty($data['joins']) and is_array($data['joins'])) { $data['joins'] = $this-&gt;buildJoinStatementArray($data['joins']); return $this-&gt;renderNestedJoinStatement($data); } else { return $this-&gt;renderJoinStatement($data); } } </code></pre> <p>The new <code>renderNestedJoinStatement()</code> method is pretty similar to <code>DboSource::renderJoinStatement()</code>:</p> <pre><code>/** * Renders a final SQL JOIN that contains nested join statements * * @param array $data * @return string */ function renderNestedJoinStatement($data) { extract($data); $nestedJoins = implode(' ', $joins); return trim("{$type} JOIN ({$table} {$alias} {$nestedJoins})ON ({$conditions})"); } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload