PageRenderTime 42ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/application/modules/media/models/media.php

http://github.com/tcm-project/tangocms
PHP | 410 lines | 238 code | 21 blank | 151 comment | 45 complexity | 0f1aedf134c23d5bd7ba524bd7f9ed3c MD5 | raw file
Possible License(s): LGPL-2.1
  1. <?php
  2. /**
  3. * Zula Framework Module
  4. *
  5. * @patches submit all patches to patches@tangocms.org
  6. *
  7. * @author Alex Cartwright
  8. * @copyright Copyright (C) 2007, 2008, 2009, 2010 Alex Cartwright
  9. * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html GNU/GPL 2
  10. * @package TangoCMS_Media
  11. */
  12. class Media_model extends Zula_ModelBase {
  13. /**
  14. * Stores how many categories would have been returned, if not limit/offset
  15. * @var int|bool
  16. */
  17. protected $categoryCount = false;
  18. /**
  19. * Shows how many media items would have been returned, if no limit/offset
  20. * @var int|bool
  21. */
  22. protected $itemCount = false;
  23. /**
  24. * Gets all categories, can also limit the result set and check
  25. * user ACL permissions
  26. *
  27. * @param int $limit
  28. * @param int $offset
  29. * @param bool $aclCheck
  30. * @return array
  31. */
  32. public function getAllCategories( $limit=0, $offset=0, $aclCheck=true ) {
  33. $statement = 'SELECT SQL_CALC_FOUND_ROWS * FROM {PREFIX}mod_media_cats';
  34. if ( $limit != 0 || $offset != 0 ) {
  35. if ( $limit > 0 ) {
  36. $statement .= ' LIMIT '.(int) $limit;
  37. } else if ( empty( $limit ) && !empty( $offset ) ) {
  38. $statement .= ' LIMIT 1000000';
  39. }
  40. if ( $offset > 0 ) {
  41. $statement .= ' OFFSET '.(int) $offset;
  42. }
  43. $query = $this->_sql->query( $statement );
  44. } else {
  45. // Get from cache instead, if possible
  46. $cacheKey = 'media_cats';
  47. if ( !($categories = $this->_cache->get($cacheKey)) ) {
  48. $statement .= ' ORDER BY name ASC';
  49. $query = $this->_sql->query( $statement );
  50. }
  51. }
  52. if ( isset( $query ) ) {
  53. $categories = array();
  54. foreach( $query->fetchAll( PDO::FETCH_ASSOC ) as $row ) {
  55. $categories[ $row['id'] ] = $row;
  56. }
  57. $query->closeCursor();
  58. if ( isset( $cacheKey ) ) {
  59. $this->_cache->add( $cacheKey, $categories );
  60. }
  61. // Get how many results there would have been
  62. $this->categoryCount = $this->_sql->query( 'SELECT FOUND_ROWS()' )
  63. ->fetch( PDO::FETCH_COLUMN );
  64. } else {
  65. $this->categoryCount = count( $categories );
  66. }
  67. /**
  68. * Get the media item count for the categories, and check
  69. * ACL resource permission
  70. */
  71. $pdoSt = $this->_sql->prepare( 'SELECT COUNT(*) qty, outstanding
  72. FROM {PREFIX}mod_media_items
  73. WHERE cat_id = :cid
  74. GROUP BY outstanding HAVING qty > 0' );
  75. foreach( $categories as $key=>$cat ) {
  76. if ( $aclCheck && !$this->_acl->check('media-cat_view_'.$cat['id']) ) {
  77. unset( $categories[ $key ] );
  78. continue;
  79. }
  80. $categories[ $key ]['item_count'] = 0;
  81. $categories[ $key ]['outstanding_count'] = 0;
  82. $pdoSt->bindValue( ':cid', $cat['id'], PDO::PARAM_INT );
  83. $pdoSt->execute();
  84. foreach( $pdoSt->fetchAll( PDO::FETCH_ASSOC ) as $row ) {
  85. if ( $row['outstanding'] ) {
  86. $categories[ $key ]['outstanding_count'] += $row['qty'];
  87. } else {
  88. $categories[ $key ]['item_count'] += $row['qty'];
  89. }
  90. }
  91. }
  92. $pdoSt->closeCursor();
  93. return $categories;
  94. }
  95. /**
  96. * Gets how many true results would have been returned if
  97. * self::getAllCategories() has no limit/offset
  98. *
  99. * @return int|bool
  100. */
  101. public function getCategoryCount() {
  102. $count = $this->categoryCount;
  103. $this->categoryCount = false;
  104. return $count;
  105. }
  106. /**
  107. * Checks if a category exists
  108. *
  109. * @param int|string $cat
  110. * @param bool $byId
  111. * @return bool
  112. */
  113. public function categoryExists( $cat, $byId=true ) {
  114. try {
  115. $this->getCategory( $cat, $byId );
  116. return true;
  117. } catch ( Media_CategoryNoExist $e ) {
  118. return false;
  119. }
  120. }
  121. /**
  122. * Gets details for a single category by ID or identifier
  123. *
  124. * @param int|string $cat
  125. * @param bool $byId
  126. * @return array
  127. */
  128. public function getCategory( $cat, $byId=true ) {
  129. $pdoSt = $this->_sql->prepare( 'SELECT mcats.*, COUNT(mitems.id) AS item_count
  130. FROM
  131. {PREFIX}mod_media_cats mcats
  132. LEFT JOIN {PREFIX}mod_media_items mitems ON mitems.cat_id = mcats.id
  133. WHERE mcats.'.($byId ? 'id' : 'identifier').' = ?
  134. GROUP BY mcats.id' );
  135. $pdoSt->execute( array($cat) );
  136. $category = $pdoSt->fetch( PDO::FETCH_ASSOC );
  137. $pdoSt->closeCursor();
  138. if ( $category['id'] !== null ) {
  139. return $category;
  140. } else {
  141. throw new Media_CategoryNoExist( $cat );
  142. }
  143. }
  144. /**
  145. * Gets all media items for a category (or no category) and can limit
  146. * the result set. If no category is selected, it can check ACL permissions
  147. * on the parent category as well.
  148. *
  149. * @param int $limit
  150. * @param int $offset
  151. * @param mixed $cid
  152. * @param bool $aclCheck
  153. * @return array
  154. */
  155. public function getItems( $limit=0, $offset=0, $cid=null, $aclCheck=true ) {
  156. $statement = 'SELECT SQL_CALC_FOUND_ROWS *
  157. FROM {PREFIX}mod_media_items WHERE outstanding = 0';
  158. $params = array();
  159. if ( $cid ) {
  160. $statement .= ' AND cat_id = :cid';
  161. $params[':cid'] = $cid;
  162. }
  163. if ( $limit != 0 || $offset != 0 ) {
  164. $statement .= ' ORDER BY date DESC';
  165. if ( $limit > 0 ) {
  166. $statement .= ' LIMIT :limit';
  167. $params[':limit'] = $limit;
  168. } else if ( empty( $limit ) && !empty( $offset ) ) {
  169. $statement .= ' LIMIT 1000000';
  170. }
  171. if ( $offset > 0 ) {
  172. $statement .= ' OFFSET :offset';
  173. $params[':offset'] = $offset;
  174. }
  175. } else {
  176. $statement .= ' ORDER BY date DESC';
  177. }
  178. $pdoSt = $this->_sql->prepare( $statement );
  179. foreach( $params as $key=>$val ) {
  180. $pdoSt->bindValue( $key, (int) $val, PDO::PARAM_INT );
  181. }
  182. $pdoSt->execute();
  183. $items = array();
  184. foreach( $pdoSt->fetchAll( PDO::FETCH_ASSOC ) as $row ) {
  185. if ( !$cid && $aclCheck ) {
  186. // Check if user has permission to parent category
  187. $resource = 'media-cat_view_'.$row['cat_id'];
  188. if ( !$this->_acl->resourceExists( $resource ) || !$this->_acl->check( $resource ) ) {
  189. continue; # Don't return this result
  190. }
  191. }
  192. $items[ $row['id'] ] = $row;
  193. }
  194. // Get the real amount of rows that would have been returned
  195. $pdoSt->closeCursor();
  196. $this->itemCount = $this->_sql->query( 'SELECT FOUND_ROWS()' )
  197. ->fetch( PDO::FETCH_COLUMN );
  198. return $items;
  199. }
  200. /**
  201. * Gets how many media items would have been returned if
  202. * self::getItems() had no offset/limit
  203. *
  204. * @return int|bool
  205. */
  206. public function getItemCount() {
  207. $count = $this->itemCount;
  208. $this->itemCount = false;
  209. return $count;
  210. }
  211. /**
  212. * Gets details for an item by ID or identifier
  213. *
  214. * @param string|int $item
  215. * @param bool $byId
  216. * @return array
  217. */
  218. public function getItem( $item, $byId=true ) {
  219. $pdoSt = $this->_sql->prepare( 'SELECT * FROM {PREFIX}mod_media_items WHERE '.($byId ? 'id' : 'identifier').' = ?' );
  220. $pdoSt->execute( array($item) );
  221. $details = $pdoSt->fetch( PDO::FETCH_ASSOC );
  222. $pdoSt->closeCursor();
  223. if ( $details ) {
  224. // Add in the filesystem path
  225. $details['path_fs'] = $this->_zula->getDir( 'uploads' ).'/media/'.$details['cat_id'].'/'.$details['type'];
  226. return $details;
  227. } else {
  228. throw new Media_ItemNoExist( $item );
  229. }
  230. }
  231. /**
  232. * Gets all outstanding media items, ordered by date. Can limit to a
  233. * specified category if needed. If set to, ACL permissions will be
  234. * checked on the parent category.
  235. *
  236. * @param int $cid
  237. * @param bool $aclCheck
  238. * @return array
  239. */
  240. public function getOutstandingItems( $cid=null, $aclCheck=true ) {
  241. $statement = 'SELECT * FROM {PREFIX}mod_media_items WHERE outstanding = 1';
  242. if ( $cid ) {
  243. $statement .= ' AND cat_id = '.(int) $cid;
  244. }
  245. $items = array();
  246. foreach( $this->_sql->query( $statement, PDO::FETCH_ASSOC ) as $row ) {
  247. $resource = 'media-cat_upload_'.$row['cat_id'];
  248. if ( !$aclCheck || ($aclCheck && $this->_acl->resourceExists($resource) && $this->_acl->check($resource)) ) {
  249. $items[ $row['id'] ] = $row;
  250. }
  251. }
  252. return $items;
  253. }
  254. /**
  255. * Adds a new category and returns the ID
  256. *
  257. * @param string $name
  258. * @param string $desc
  259. * @return int
  260. */
  261. public function addCategory( $name, $desc='' ) {
  262. $i = null;
  263. do {
  264. try {
  265. $identifier = zula_clean( $name ).$i++;
  266. $this->getCategory( $identifier, false );
  267. } catch ( Media_CategoryNoExist $e ) {
  268. break;
  269. }
  270. } while ( true );
  271. // Insert new category
  272. $pdoSt = $this->_sql->prepare( 'INSERT INTO {PREFIX}mod_media_cats (name, description, identifier) VALUES(?, ?, ?)' );
  273. $pdoSt->execute( array($name, $desc, $identifier) );
  274. $this->_cache->delete( 'media_cats' );
  275. return $this->_sql->lastInsertId();
  276. }
  277. /**
  278. * Edits an existing category
  279. *
  280. * @param int $id
  281. * @param string $name
  282. * @param string $desc
  283. * @return bool
  284. */
  285. public function editCategory( $id, $name, $desc ) {
  286. $category = $this->getCategory( $id );
  287. $pdoSt = $this->_sql->prepare( 'UPDATE {PREFIX}mod_media_cats
  288. SET name = ?, description = ? WHERE id = ?' );
  289. $this->_cache->delete( 'media_cats' );
  290. return $pdoSt->execute( array($name, $desc, $id) );
  291. }
  292. /**
  293. * Deletes a media category and all media items under it. It does
  294. * not delete the files though. Returns how many media items were
  295. * deleted, or false on failure.
  296. *
  297. * @param int $id
  298. * @return int|bool
  299. */
  300. public function deleteCategory( $id ) {
  301. $category = $this->getCategory( $id );
  302. $query = $this->_sql->query( 'DELETE FROM {PREFIX}mod_media_cats WHERE id = '.(int) $category['id'] );
  303. if ( $query->rowCount() ) {
  304. $query->closeCursor();
  305. $this->_cache->delete( 'media_cats' );
  306. // Remove ACL resources
  307. $cid = $category['id'];
  308. $this->_acl->deleteResource( array('media-cat_view_'.$cid, 'media-cat_upload_'.$cid, 'media-cat_moderate_'.$cid) );
  309. // Delete all media items
  310. $query = $this->_sql->query( 'DELETE FROM {PREFIX}mod_media_items WHERE cat_id = '.(int) $cid );
  311. return $query->rowCount();
  312. } else {
  313. return false;
  314. }
  315. }
  316. /**
  317. * Purges a media category/removes all media items. This will not remove
  318. * any files, just the database entries. Returns number of media items deleted
  319. *
  320. * @param int $id
  321. * @return int
  322. */
  323. public function purgeCategory( $id ) {
  324. $category = $this->getCategory( $id );
  325. $query = $this->_sql->query( 'DELETE FROM {PREFIX}mod_media_items WHERE cat_id = '.(int) $category['id'] );
  326. return $query->rowCount();
  327. }
  328. /**
  329. * Adds a new media item to a category
  330. *
  331. * @param int $cid
  332. * @param string $name
  333. * @param string $desc
  334. * @param string $type Video/Image/Audio/External
  335. * @param string $filename
  336. * @param string $thumbnail
  337. * @param string $externalService
  338. * @param string $externalId
  339. * @return array
  340. */
  341. public function addItem( $cid, $name, $desc, $type, $filename, $thumbnail, $externalService='', $externalId='' ) {
  342. $category = $this->getCategory( $cid );
  343. // Create the identifier for the item
  344. $i = null;
  345. do {
  346. try {
  347. $identifier = zula_clean( $name ).$i;
  348. $this->getItem( $identifier, false );
  349. ++$i;
  350. } catch ( Media_ItemNoExist $e ) {
  351. break;;
  352. }
  353. } while( true );
  354. // Insert the new media item
  355. $pdoSt = $this->_sql->prepare( 'INSERT INTO {PREFIX}mod_media_items
  356. (cat_id, type, date, name, identifier, description, filename, thumbnail, external_service, external_id)
  357. VALUES(?, ?, UTC_TIMESTAMP(), ?, ?, ?, ?, ?, ?, ?)' );
  358. $pdoSt->execute( array($category['id'], $type, $name, $identifier, $desc, $filename, $thumbnail, $externalService, $externalId) );
  359. return array(
  360. 'id' => $this->_sql->lastInsertId(),
  361. 'identifier' => $identifier,
  362. );
  363. }
  364. /**
  365. * Edits a media item
  366. *
  367. * @param int $id
  368. * @param string $name
  369. * @param string $desc
  370. * @return bool
  371. */
  372. public function editItem( $id, $name, $desc ) {
  373. $item = $this->getItem( $id );
  374. $pdoSt = $this->_sql->prepare( 'UPDATE {PREFIX}mod_media_items SET name = ?, description = ?, outstanding = 0 WHERE id = ?' );
  375. return $pdoSt->execute( array($name, $desc, $id) );
  376. }
  377. /**
  378. * Deletes a a media item, but not the files.
  379. *
  380. * @param int $id
  381. * @return bool
  382. */
  383. public function deleteItem( $id ) {
  384. $item = $this->getItem( $id );
  385. $query = $this->_sql->query( 'DELETE FROM {PREFIX}mod_media_items WHERE id = '.(int) $item['id'] );
  386. return (bool) $query->rowCount();
  387. }
  388. }
  389. ?>