| 224 | | |
|---|
| 225 | | /** |
|---|
| 226 | | * |
|---|
| 227 | | * Support method to create a new selection tool based on tag lists. |
|---|
| 228 | | * |
|---|
| 229 | | * @param array $tag_list The list of tags to select by. |
|---|
| 230 | | * |
|---|
| 231 | | * @param array &$params A reference to added parameters for the SELECT. |
|---|
| 232 | | * |
|---|
| 233 | | * @return Solar_Sql_Select |
|---|
| 234 | | * |
|---|
| 235 | | */ |
|---|
| 236 | | protected function _newSelectByTags($tag_list, &$params) |
|---|
| 237 | | { |
|---|
| 238 | | // setup |
|---|
| 239 | | $params = $this->fixSelectParams($params); |
|---|
| 240 | | $select = $this->newSelect($params['eager']); |
|---|
| 241 | | |
|---|
| 242 | | // catalog entries for joining |
|---|
| 243 | | $taggings = $this->_related['taggings']; |
|---|
| 244 | | $tags = $this->_related['tags']; |
|---|
| 245 | | |
|---|
| 246 | | // primary key on the nodes table as an alias; e.g., "nodes.id" |
|---|
| 247 | | $native_primary = "{$this->_model_name}.{$this->_primary_col}"; |
|---|
| 248 | | |
|---|
| 249 | | // http://forge.mysql.com/wiki/TagSchema |
|---|
| 250 | | // build the select differently from other fetchAll() statements |
|---|
| 251 | | $select->distinct($params['distinct']) |
|---|
| 252 | | ->from("{$this->_table_name} AS {$this->_model_name}", $params['cols']) |
|---|
| 253 | | // join taggings on nodes |
|---|
| 254 | | ->join( |
|---|
| 255 | | "{$taggings->foreign_table} AS {$taggings->foreign_alias}", |
|---|
| 256 | | "{$taggings->foreign_alias}.node_id = $native_primary" |
|---|
| 257 | | ) |
|---|
| 258 | | // join tags on taggings |
|---|
| 259 | | ->join( |
|---|
| 260 | | "{$tags->foreign_table} AS {$tags->foreign_alias}", |
|---|
| 261 | | "{$tags->foreign_alias}.id = {$taggings->foreign_alias}.tag_id" |
|---|
| 262 | | ) |
|---|
| 263 | | // select for the listed tags |
|---|
| 264 | | ->where("{$tags->foreign_alias}.name IN (?)", $tag_list) |
|---|
| 265 | | // user-provided WHERE |
|---|
| 266 | | ->multiWhere($params['where']) |
|---|
| 267 | | // group by nodes.id to collapse multiple nodes (1 for each tag) |
|---|
| 268 | | ->group($native_primary) |
|---|
| 269 | | // make sure the tag-count matches |
|---|
| 270 | | ->having("COUNT($native_primary) = ?", count($tag_list)) |
|---|
| 271 | | // user-provided ORDER, paging, etc |
|---|
| 272 | | ->order($params['order']) |
|---|
| 273 | | ->setPaging($params['paging']) |
|---|
| 274 | | ->limitPage($params['page']) |
|---|
| 275 | | ->bind($params['bind']); |
|---|
| 276 | | |
|---|
| 277 | | // done! |
|---|
| 278 | | return $select; |
|---|
| 279 | | } |
|---|
| 280 | | |
|---|
| 281 | | /** |
|---|
| 282 | | * |
|---|
| 283 | | * Gets a count of nodes and pages-of-nodes with certain tags. |
|---|
| 284 | | * |
|---|
| 285 | | * @param array $tag_list Count only nodes with all of these tags. |
|---|
| 286 | | * |
|---|
| 287 | | * @param array $params Added parameters for the SELECT. |
|---|
| 288 | | * |
|---|
| 289 | | * @return array An array with elemets 'count' (the number of nodes) and |
|---|
| 290 | | * 'pages' (the number of pages-of-nodes). |
|---|
| 291 | | * |
|---|
| 292 | | */ |
|---|
| 293 | | public function countPagesByTags($tag_list, $params = null) |
|---|
| 294 | | { |
|---|
| 295 | | $tag_list = $this->_fixTagList($tag_list); |
|---|
| 296 | | if (! $tag_list) { |
|---|
| 297 | | return $this->countPages($params); |
|---|
| 298 | | } |
|---|
| 299 | | |
|---|
| 300 | | // we need to select the nodes + tags as an "inner" sub-select; |
|---|
| 301 | | // clear any limits on it. |
|---|
| 302 | | $inner = $this->_newSelectByTags($tag_list, $params); |
|---|
| 303 | | $inner->clear('limit'); |
|---|
| 304 | | |
|---|
| 305 | | // set up the outer select, which will wrap the inner sub-select |
|---|
| 306 | | $outer = Solar::factory($this->_select_class, array( |
|---|
| 307 | | 'sql' => $this->_sql |
|---|
| 308 | | )); |
|---|
| 309 | | |
|---|
| 310 | | // wrap the sub-select and make sure paging is correct |
|---|
| 311 | | $outer->fromSelect($inner, $this->_model_name); |
|---|
| 312 | | $outer->setPaging($this->_paging); |
|---|
| 313 | | |
|---|
| 314 | | // *now* get the count of pages with the tags requested |
|---|
| 315 | | return $outer->countPages("{$this->_model_name}.{$this->_primary_col}"); |
|---|
| 316 | | } |
|---|