1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
<?php
/*
Usage. Add a find option called scope. Something like:
 
'scope' => array(
    'AssociatedModel' => array(
        'conditions'=> array(
            'AssociatedModel.some_fk = MainModel.id'
        ),
        'AnotherModel' => array(
            'conditions' => array(
                'AnotherModel.some_fk = MainModel.id',
                'AnotherModel.type' => $array_of_types
            )
        )
    )
),
 
*/
class AppModel extends Model {
   
    /**
     * Creates jojn statements for model.
     * Hacked together from ContainableBehavior::containments()
     *
     * TODO: clean up, create tests, remove unneeded code?
     *
     * @param object $Model Model on which joining is being applied
     * @param array $scope Parameters to use for joining models
     * @param array $joins Current set of joins
     * @return array joins statements
     * @access private
     */
    private function _joinScope(&$Model, $scope, $joins = array()) {
        $options = array('className', 'joinTable', 'with', 'foreignKey', 'associationForeignKey', 'conditions', 'fields', 'order', 'limit', 'offset', 'unique', 'finderQuery', 'deleteQuery', 'insertQuery');
        $join_options = array();
       
        foreach ((array)$scope as $name => $children) {
            if (is_numeric($name)) {
                $name = $children;
                $children = array();
            }
            if (preg_match('/(?<!\.)\(/', $name)) {
                $name = str_replace('(', '.(', $name);
            }
            if (strpos($name, '.') !== false) {
                $chain = explode('.', $name);
                $name = array_shift($chain);
                $children = array(join('.', $chain) => $children);
            }
 
            $children = (array)$children;
            foreach ($children as $key => $val) {
                if (is_string($key) && is_string($val) && !in_array($key, $options, true)) {
                    $children[$key] = (array) $val;
                }
            }
 
            $keys = array_keys($children);
            if ($keys && isset($children[0])) {
                $keys = array_merge(array_values($children), $keys);
            }
 
            foreach ($keys as $i => $key) {
                if (is_array($key)) {
                    continue;
                }
                $optionKey = in_array($key, $options, true);
               
                if ($optionKey && isset($children[$key])) {                
                    $join_options[$key] = $children[$key];
                    unset($children[$key]);
                }
            }
 
            if (!isset($Model->{$name}) || !is_object($Model->{$name})) {
                trigger_error(sprintf(__('Model "%s" is not associated with model "%s"', true), $Model->alias, $name), E_USER_WARNING);
                continue;
            }
 
            $aJoin = array(
                'table' => $Model->{$name}->table,
                'alias' => $name,
                'type' => 'inner',
                'foreignKey' => false,
            );
            $joins[] = array_merge($aJoin, $join_options);
 
            $joins = $this->_joinScope($Model->{$name}, $children, $joins);
        }
        return $joins;
    }
   
   
    /**
     * find using option "scope" to join models
     * Syntax for scope is similar to Containable
     **/
    public function find($type, $options = array()) {
 
        if ( isset($options['scope']) ) {
           
            $joins = $this->_joinScope($this, $options['scope']);          
           
            if ( !isset($options['joins']) ) {
                $options['joins'] = array();
            }
           
            $options['joins'] = array_merge($options['joins'], $joins);
           
            if ( empty($options['joins']) ) {
                unset($options['joins']);
            }
        }
 
        return parent::find($type, $options);
    }
}
?>