1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10:
11: class Trean_Bookmarks
12: {
13: 14: 15: 16: 17:
18: var $_datatree;
19:
20: 21: 22: 23: 24: 25:
26: var $_cache = array();
27:
28: 29: 30: 31: 32:
33: var $_shareMap = array();
34:
35: 36: 37: 38: 39:
40: var $_listcache = array();
41:
42: 43: 44: 45: 46: 47:
48: var $_counts = array();
49:
50: 51: 52: 53: 54: 55:
56: var $_sortList;
57:
58: 59: 60:
61: function Trean_Bookmarks()
62: {
63: global $conf, $registry;
64:
65: if (empty($conf['datatree']['driver'])) {
66: throw new Horde_Exception('You must configure a Horde_DataTree backend to use Trean.');
67: }
68:
69: $driver = $conf['datatree']['driver'];
70: $this->_datatree = Horde_DataTree::singleton(
71: $driver,
72: array_merge(Horde::getDriverConfig('datatree', $driver), array('group' => 'horde.shares.trean'))
73: );
74:
75: try {
76: Horde::callHook('share_init', array($this, 'trean'));
77: } catch (Horde_Exception_HookNotSet $e) {}
78: }
79:
80: 81: 82:
83: function searchBookmarks($search_criteria, $search_operator = 'OR',
84: $sortby = 'title', $sortdir = 0, $from = 0, $count = 0)
85: {
86:
87: switch ($search_operator) {
88: case 'AND':
89: case 'OR':
90: break;
91:
92: default:
93: $search_operator = 'AND';
94: }
95:
96:
97: $folderIds = $this->listFolders($GLOBALS['registry']->getAuth(), Horde_Perms::READ);
98:
99: $clauses = array();
100: $values = array();
101: foreach ($search_criteria as $criterion) {
102: $clause = $GLOBALS['trean_db']->buildClause(
103: 'bookmark_' . $criterion[0],
104: $criterion[1],
105: Horde_String::convertCharset($criterion[2],
106: $GLOBALS['conf']['sql']['charset'],
107: 'UTF-8'),
108: true,
109: isset($criterion[3]) ? $criterion[3] : array());
110: $clauses[] = $clause[0];
111: $values = array_merge($values, $clause[1]);
112: }
113:
114: $GLOBALS['trean_db']->setLimit($count, $from);
115:
116: $sql = 'SELECT bookmark_id, folder_id, bookmark_url, bookmark_title, bookmark_description,
117: bookmark_clicks, bookmark_rating
118: FROM trean_bookmarks
119: WHERE folder_id IN (' . implode(',', $folderIds) . ')
120: AND (' . implode(' ' . $search_operator . ' ', $clauses) . ')
121: ORDER BY bookmark_' . $sortby . ($sortdir ? ' DESC' : '');
122: $query = $GLOBALS['trean_db']->prepare($sql);
123: if (is_a($query, 'PEAR_Error')) {
124: Horde::logMessage($query, __FILE__, __LINE__, PEAR_LOG_ERR);
125: return array();
126: }
127:
128: $result = $query->execute($values);
129: if (is_a($result, 'PEAR_Error')) {
130: Horde::logMessage($result, __FILE__, __LINE__, PEAR_LOG_ERR);
131: return array();
132: }
133:
134: return Trean_Bookmarks::resultSet($result->fetchAll(MDB2_FETCHMODE_ASSOC));
135: }
136:
137: 138: 139: 140:
141: function sortBookmarks($sortby = 'title', $sortdir = 0, $from = 0, $count = 10)
142: {
143:
144: $folderIds = $this->listFolders($GLOBALS['registry']->getAuth(), Horde_Perms::READ);
145:
146:
147: switch ($sortby) {
148: case 'rating':
149: case 'clicks':
150: break;
151:
152: default:
153: $sortby = 'title';
154: }
155:
156: if ($count > 100) {
157: return PEAR::raiseError('Max of 100 results');
158: }
159:
160: $GLOBALS['trean_db']->setLimit($count, $from);
161: return Trean_Bookmarks::resultSet($GLOBALS['trean_db']->queryAll('
162: SELECT bookmark_id, folder_id, bookmark_url, bookmark_title, bookmark_description,
163: bookmark_clicks, bookmark_rating
164: FROM trean_bookmarks
165: WHERE folder_id IN (' . implode(',', $folderIds) . ')
166: ORDER BY bookmark_' . $sortby . ($sortdir ? ' DESC' : ''), null, MDB2_FETCHMODE_ASSOC));
167: }
168:
169: 170: 171: 172: 173:
174: function countBookmarks()
175: {
176: $folderIds = $this->listFolders($GLOBALS['registry']->getAuth(), Horde_Perms::EDIT);
177: $sql = 'SELECT COUNT(*) FROM trean_bookmarks WHERE folder_id IN (' . implode(',', $folderIds) . ')';
178: return $GLOBALS['trean_db']->queryOne($sql);
179: }
180:
181: 182: 183:
184: function groupBookmarks($groupby)
185: {
186: $folderIds = $this->listFolders($GLOBALS['registry']->getAuth(), Horde_Perms::READ);
187:
188: switch ($groupby) {
189: case 'status':
190: $sql = 'SELECT bookmark_http_status AS status, COUNT(*) AS count
191: FROM trean_bookmarks
192: WHERE folder_id IN (' . implode(',', $folderIds) . ')
193: GROUP BY bookmark_http_status';
194: break;
195:
196: default:
197: return array();
198: }
199:
200: return $GLOBALS['trean_db']->queryAll($sql, null, MDB2_FETCHMODE_ASSOC);
201: }
202:
203: 204: 205: 206: 207: 208: 209: 210:
211: function getShares($cids)
212: {
213: $all_shares = array();
214: $missing_ids = array();
215: foreach ($cids as $cid) {
216: if (isset($this->_shareMap[$cid])) {
217: $all_shares[$this->_shareMap[$cid]] = $this->_cache[$this->_shareMap[$cid]];
218: } else {
219: $missing_ids[] = $cid;
220: }
221: }
222:
223: if (count($missing_ids)) {
224: $shares = $this->_datatree->getObjects($missing_ids, 'DataTreeObject_Folder');
225: if (is_a($shares, 'PEAR_Error')) {
226: return $shares;
227: }
228:
229: $keys = array_keys($shares);
230: foreach ($keys as $key) {
231: if (is_a($shares[$key], 'PEAR_Error')) {
232: return $shares[$key];
233: }
234:
235: $shares[$key]->setShareOb($this);
236: $all_shares[$key] = $shares[$key];
237: $this->_cache[$key] = $shares[$key];
238: $this->_shareMap[$shares[$key]->getId()] = $key;
239: }
240: }
241:
242: return $all_shares;
243: }
244:
245: 246: 247: 248: 249: 250: 251:
252: function exists($share)
253: {
254: if (isset($this->_cache[$share])) {
255: return true;
256: }
257:
258: return $this->_datatree->exists($share);
259: }
260:
261: 262: 263: 264: 265: 266: 267: 268: 269: 270: 271: 272:
273: function listFolders($userid, $perm = Horde_Perms::SHOW, $parent = null, $allLevels = true)
274: {
275: if (is_null($parent)) {
276: $parent = DATATREE_ROOT;
277: }
278:
279: $key = serialize(array($userid, $perm, $parent, $allLevels));
280: if (empty($this->_listCache[$key])) {
281: $criteria = $this->_getShareCriteria($userid, $perm);
282: $sharelist = $this->_datatree->getByAttributes(
283: $criteria, $parent, $allLevels, 'id', 0, 0, 'name'
284: );
285: if (is_a($sharelist, 'PEAR_Error')) {
286: return $sharelist;
287: }
288: $this->_listCache[$key] = array_keys($sharelist);
289: }
290:
291: return $this->_listCache[$key];
292: }
293:
294: 295: 296: 297: 298: 299: 300: 301: 302: 303: 304: 305:
306: function getFolders($userid, $perm = Horde_Perms::SHOW, $parent = null, $allLevels = true)
307: {
308: $folderIds = $this->listFolders($userid, $perm, $parent, $allLevels);
309: if (!count($folderIds) || is_a($folderIds, 'PEAR_Error')) {
310: return $folderIds;
311: }
312:
313:
314: $shares = $this->getShares($folderIds);
315: if (is_a($shares, 'PEAR_Error')) {
316: return $shares;
317: }
318:
319: $this->_sortList = $shares;
320: uasort($shares, array($this, '_sortShares'));
321: $this->_sortList = null;
322:
323: try {
324: return Horde::callHook('share_list', array($userid, $perm, null, $shares));
325: } catch (Horde_Exception_HookNotSet $e) {
326: return $shares;
327: }
328: }
329:
330: 331: 332: 333: 334: 335: 336: 337: 338:
339: function newFolder($name, $properties = null)
340: {
341: if (empty($name)) {
342: $error = PEAR::raiseError(_("Folder names must be non-empty"));
343: return $error;
344: }
345:
346: $folder = new DataTreeObject_Folder($name);
347: $folder->setDataTree($this->_datatree);
348: $folder->setShareOb($this);
349: $folder->set('owner', $GLOBALS['registry']->getAuth());
350: $folder->set('name', isset($properties['name']) ? $properties['name'] : '');
351: return $folder;
352: }
353:
354: 355: 356: 357: 358: 359: 360: 361:
362: function getFolder($cid)
363: {
364: if (isset($this->_shareMap[$cid])) {
365: $share = $this->_cache[$this->_shareMap[$cid]];
366: } else {
367: $share = $this->_datatree->getObjectById($cid, 'DataTreeObject_Folder');
368: if (!is_a($share, 'PEAR_Error')) {
369: $share->setShareOb($this);
370: $name = $share->getName();
371: $this->_cache[$name] = $share;
372: $this->_shareMap[$cid] = $name;
373: }
374: }
375:
376: return $share;
377: }
378:
379: 380: 381: 382: 383: 384: 385:
386: function getBookmark($id)
387: {
388: $bookmark = $GLOBALS['trean_db']->queryRow('
389: SELECT bookmark_id, folder_id, bookmark_url, bookmark_title, bookmark_description,
390: bookmark_clicks, bookmark_rating
391: FROM trean_bookmarks
392: WHERE bookmark_id = ' . (int)$id, null, MDB2_FETCHMODE_ASSOC);
393: if (is_null($bookmark)) {
394: return PEAR::raiseError('not found');
395: } elseif (is_a($bookmark, 'PEAR_Error')) {
396: return $bookmark;
397: } else {
398: $bookmark = $this->resultSet(array($bookmark));
399: return array_pop($bookmark);
400: }
401: }
402:
403: 404: 405: 406: 407:
408: function addFolder($folder)
409: {
410: if (!is_a($folder, 'DataTreeObject_Folder')) {
411: return PEAR::raiseError('Folders must be DataTreeObject_Folder objects or extend that class.');
412: }
413:
414:
415: $perm = $GLOBALS['injector']->getInstance('Horde_Core_Perms')->newPermission($folder->getName());
416: $perm->addUserPermission($folder->get('owner'), Horde_Perms::SHOW, false);
417: $perm->addUserPermission($folder->get('owner'), Horde_Perms::READ, false);
418: $perm->addUserPermission($folder->get('owner'), Horde_Perms::EDIT, false);
419: $perm->addUserPermission($folder->get('owner'), Horde_Perms::DELETE, false);
420:
421: $folder->setPermission($perm, false);
422:
423: try {
424: $result = Horde::callHook('share_add', array($folder));
425: } catch (Horde_Exception_HookNotSet $e) {}
426:
427: $result = $this->_datatree->add($folder);
428: if (is_a($result, 'PEAR_Error')) {
429: return $result;
430: }
431:
432:
433: $id = $folder->getId();
434: $name = $folder->getName();
435: $this->_cache[$name] = $folder;
436: $this->_shareMap[$id] = $name;
437:
438:
439: $this->_listCache = array();
440: $this->_counts = array();
441:
442: return $result;
443: }
444:
445: 446: 447: 448: 449: 450: 451: 452:
453: function removeFolder($folder, $force = false)
454: {
455: if (!is_a($folder, 'DataTreeObject_Folder')) {
456: return PEAR::raiseError('Folders must be DataTreeObject_Folder objects or extend that class.');
457: }
458:
459: try {
460: $result = Horde::callHook('share_remove', array($folder));
461: } catch (Horde_Exception_HookNotSet $e) {}
462:
463: return $this->_datatree->remove($folder, $force);
464: }
465:
466: 467: 468: 469: 470:
471: function removeBookmark($bookmark)
472: {
473: 474:
475: if (!is_a($bookmark, 'Trean_Bookmark')) {
476: $b = $this->getBookmark($bookmark);
477: if (is_a($b, 'PEAR_Error')) {
478: return $b;
479: }
480: $bookmark = $b;
481: }
482:
483:
484: $folder = $this->getFolder($bookmark->folder);
485: if (!$folder->hasPermission($GLOBALS['registry']->getAuth(), Horde_Perms::DELETE)) {
486: return PEAR::raiseError('permission denied');
487: }
488:
489:
490:
491:
492: $GLOBALS['trean_db']->exec('DELETE FROM trean_bookmarks WHERE bookmark_id = ' . (int)$bookmark->id);
493:
494: return true;
495: }
496:
497: 498: 499: 500: 501: 502: 503:
504: function getId($name)
505: {
506: return $this->_datatree->getId($name);
507: }
508:
509: 510: 511:
512: function move($folder, $new_parent)
513: {
514: if (!is_a($folder, 'DataTreeObject_Folder')) {
515: return PEAR::raiseError('Folders must be DataTreeObject_Folder objects or extend that class.');
516: }
517: if (!is_a($new_parent, 'DataTreeObject_Folder')) {
518: return PEAR::raiseError('Folders must be DataTreeObject_Folder objects or extend that class.');
519: }
520: return $this->_datatree->move($folder, $new_parent);
521: }
522:
523: 524: 525: 526:
527: function resultSet($bookmarks)
528: {
529: if (is_null($bookmarks)) {
530: return array();
531: } elseif (is_a($bookmarks, 'PEAR_Error')) {
532: return $bookmarks;
533: }
534:
535: $objects = array();
536: foreach ($bookmarks as $bookmark) {
537: foreach ($bookmark as $key => $value)
538: if (!empty($value) && !is_numeric($value)) {
539: $cvBookmarks[$key] = Horde_String::convertCharset(
540: $value, $GLOBALS['conf']['sql']['charset'], 'UTF-8');
541: } else {
542: $cvBookmarks[$key] = $value;
543: }
544: $objects[] = new Trean_Bookmark($cvBookmarks);
545: }
546: return $objects;
547: }
548:
549: 550: 551: 552: 553: 554: 555: 556: 557:
558: function _sortShares($a, $b)
559: {
560: $aParts = explode(':', $a->getName());
561: $bParts = explode(':', $b->getName());
562:
563: $min = min(count($aParts), count($bParts));
564: $idA = '';
565: $idB = '';
566: for ($i = 0; $i < $min; $i++) {
567: if ($idA) {
568: $idA .= ':';
569: $idB .= ':';
570: }
571: $idA .= $aParts[$i];
572: $idB .= $bParts[$i];
573:
574: if ($idA != $idB) {
575: $curA = isset($this->_sortList[$idA]) ? $this->_sortList[$idA]->get('name') : '';
576: $curB = isset($this->_sortList[$idB]) ? $this->_sortList[$idB]->get('name') : '';
577: return strnatcasecmp($curA, $curB);
578: }
579: }
580:
581: return count($aParts) > count($bParts);
582: }
583:
584: 585: 586: 587: 588: 589: 590: 591:
592: function _getShareCriteria($userid, $perm = Horde_Perms::SHOW)
593: {
594: if (!empty($userid)) {
595: $criteria = array(
596: 'OR' => array(
597:
598: array(
599: 'AND' => array(
600: array('field' => 'name', 'op' => '=', 'test' => 'owner'),
601: array('field' => 'value', 'op' => '=', 'test' => $userid))),
602:
603:
604: array(
605: 'AND' => array(
606: array('field' => 'name', 'op' => '=', 'test' => 'perm_users'),
607: array('field' => 'key', 'op' => '=', 'test' => $userid),
608: array('field' => 'value', 'op' => '&', 'test' => $perm))),
609:
610:
611: array(
612: 'AND' => array(
613: array('field' => 'name', 'op' => '=', 'test' => 'perm_creator'),
614: array('field' => 'value', 'op' => '&', 'test' => $perm))),
615:
616:
617: array(
618: 'AND' => array(
619: array('field' => 'name', 'op' => '=', 'test' => 'perm_default'),
620: array('field' => 'value', 'op' => '&', 'test' => $perm)))));
621:
622:
623: $groups = $GLOBALS['injector']
624: ->getInstance('Horde_Group')
625: ->listGroups($userid);
626: if (is_array($groups) && count($groups)) {
627:
628: $criteria['OR'][] = array(
629: 'AND' => array(
630: array('field' => 'name', 'op' => '=', 'test' => 'perm_groups'),
631: array('field' => 'key', 'op' => 'IN', 'test' => array_keys($groups)),
632: array('field' => 'value', 'op' => '&', 'test' => $perm)));
633: }
634: } else {
635: $criteria = array(
636: 'AND' => array(
637: array('field' => 'name', 'op' => '=', 'test' => 'perm_guest'),
638: array('field' => 'value', 'op' => '&', 'test' => $perm)));
639: }
640:
641: return $criteria;
642: }
643:
644: }
645:
646: 647: 648: 649: 650: 651:
652: class DataTreeObject_Folder extends Horde_DataTreeObject {
653:
654: 655: 656: 657: 658: 659:
660: var $_shareOb;
661:
662: 663: 664: 665: 666: 667:
668: function DataTreeObject_Folder($id)
669: {
670: parent::__construct($id);
671: if (is_null($this->data)) {
672: $this->data = array();
673: }
674: }
675:
676: 677: 678: 679: 680:
681: function __sleep()
682: {
683: $properties = get_object_vars($this);
684: unset($properties['datatree'], $properties['_shareOb']);
685: $properties = array_keys($properties);
686: return $properties;
687: }
688:
689: 690: 691: 692: 693:
694: function setShareOb($shareOb)
695: {
696: $this->_shareOb = $shareOb;
697: }
698:
699: 700: 701: 702: 703: 704: 705: 706: 707:
708: function hasPermission($userid, $permission, $creator = null)
709: {
710: if ($userid == $this->get('owner')) {
711: return true;
712: }
713:
714: $perms = $GLOBALS['injector']->getInstance('Horde_Perms');
715: return $perms->hasPermission($this->getPermission(), $userid, $permission, $creator);
716: }
717:
718: 719: 720: 721: 722: 723: 724: 725:
726: function setPermission($perm, $update = true)
727: {
728: $this->data['perm'] = $perm->getData();
729: if ($update) {
730: return $this->save();
731: }
732: return true;
733: }
734:
735: 736: 737: 738: 739:
740: function getPermission()
741: {
742: $perm = new Horde_Perms_Permission($this->getName());
743: $perm->data = isset($this->data['perm']) ? $this->data['perm'] : array();
744:
745: return $perm;
746: }
747:
748: 749: 750: 751: 752: 753:
754: function inheritPermissions()
755: {
756: $c_list = $this->datatree->get(DATATREE_FORMAT_FLAT, $this->getName(), true);
757: if (is_a($c_list, 'PEAR_Error') || !$c_list) {
758:
759: return $c_list;
760: }
761: unset($c_list[$this->getName()]);
762:
763: $children = $this->_shareOb->getShares(array_keys($c_list));
764: if (is_a($children, 'PEAR_Error')) {
765: return $children;
766: }
767:
768: $perm = $this->getPermission();
769: foreach ($children as $child) {
770: $child->setPermission($perm);
771: }
772:
773: return true;
774: }
775:
776: 777: 778: 779: 780: 781: 782:
783: function set($attribute, $value, $update = false)
784: {
785: parent::set($attribute, $value);
786: if ($update) {
787: $this->save();
788: }
789: }
790:
791: 792: 793: 794: 795: 796: 797: 798: 799: 800:
801: function addBookmark($properties)
802: {
803: $properties['folder_id'] = $this->getId();
804: $bookmark = new Trean_Bookmark($properties);
805: return $bookmark->save();
806: }
807:
808: 809: 810: 811: 812: 813: 814: 815:
816: function addFolder($properties)
817: {
818: $folder = $this->_shareOb->newFolder($this->getName() . ':' . strval(new Horde_Support_Uuid()), $properties);
819: $this->_shareOb->addFolder($folder);
820: return $this->datatree->getId($folder);
821: }
822:
823: 824: 825:
826: function getParent()
827: {
828: $parent = $this->datatree->getParent($this->getName());
829: return ($parent == DATATREE_ROOT) ? null : $parent;
830: }
831:
832: 833: 834: 835: 836: 837:
838: function listBookmarks($sortby = 'title', $sortdir = 0, $from = 0, $count = 0)
839: {
840:
841: switch ($sortby) {
842: case 'rating':
843: case 'clicks':
844: break;
845:
846: default:
847: $sortby = 'title';
848: }
849:
850: $GLOBALS['trean_db']->setLimit($count, $from);
851: return Trean_Bookmarks::resultSet($GLOBALS['trean_db']->queryAll('
852: SELECT bookmark_id, folder_id, bookmark_url, bookmark_title, bookmark_description,
853: bookmark_clicks, bookmark_rating
854: FROM trean_bookmarks
855: WHERE folder_id = ' . (int)$this->getId() . '
856: ORDER BY bookmark_' . $sortby . ($sortdir ? ' DESC' : ''), null, MDB2_FETCHMODE_ASSOC));
857: }
858:
859: 860: 861: 862: 863: 864: 865: 866: 867: 868: 869: 870:
871: function _toAttributes($permsonly = false)
872: {
873:
874: $attributes = array();
875:
876: foreach ($this->data as $key => $value) {
877: if ($key == 'perm') {
878: foreach ($value as $type => $perms) {
879: if (is_array($perms)) {
880: foreach ($perms as $member => $perm) {
881: $attributes[] = array('name' => 'perm_' . $type,
882: 'key' => $member,
883: 'value' => $perm);
884: }
885: } else {
886: $attributes[] = array('name' => 'perm_' . $type,
887: 'key' => '',
888: 'value' => $perms);
889: }
890: }
891: } elseif (!$permsonly) {
892: $attributes[] = array('name' => $key,
893: 'key' => '',
894: 'value' => $value);
895: }
896: }
897:
898: return $attributes;
899: }
900:
901: 902: 903: 904: 905: 906: 907: 908: 909: 910: 911: 912:
913: function _fromAttributes($attributes, $permsonly = false)
914: {
915:
916: $this->data['perm'] = array();
917:
918: foreach ($attributes as $attr) {
919: if (substr($attr['name'], 0, 4) == 'perm') {
920: if (!empty($attr['key'])) {
921: $this->data['perm'][substr($attr['name'], 5)][$attr['key']] = $attr['value'];
922: } else {
923: $this->data['perm'][substr($attr['name'], 5)] = $attr['value'];
924: }
925: } elseif (!$permsonly) {
926: $this->data[$attr['name']] = $attr['value'];
927: }
928: }
929: }
930:
931: }
932:
933: 934: 935: 936:
937: class Trean_Bookmark {
938:
939: var $id = null;
940: var $url = null;
941: var $title = '';
942: var $description = '';
943: var $clicks = 0;
944: var $rating = 0;
945: var $http_status = null;
946: var $folder;
947: var $favicon;
948:
949: function Trean_Bookmark($bookmark = array())
950: {
951: if ($bookmark) {
952: $this->url = $bookmark['bookmark_url'];
953: $this->title = $bookmark['bookmark_title'];
954: $this->description = $bookmark['bookmark_description'];
955: $this->folder = $bookmark['folder_id'];
956:
957: if (!empty($bookmark['bookmark_id'])) {
958: $this->id = (int)$bookmark['bookmark_id'];
959: }
960: if (!empty($bookmark['bookmark_clicks'])) {
961: $this->clicks = (int)$bookmark['bookmark_clicks'];
962: }
963: if (!empty($bookmark['bookmark_rating'])) {
964: $this->rating = (int)$bookmark['bookmark_rating'];
965: }
966: if (!empty($bookmark['bookmark_http_status'])) {
967: $this->http_status = $bookmark['bookmark_http_status'];
968: }
969: }
970: }
971:
972: 973: 974:
975: function copyTo($folder)
976: {
977: if (!is_a($folder, 'DataTreeObject_Folder')) {
978: return PEAR::raiseError('Folders must be DataTreeObject_Folder objects or extend that class.');
979: }
980:
981: return $folder->addBookmark(array('bookmark_url' => $this->url,
982: 'bookmark_title' => $this->title,
983: 'bookmark_description' => $this->description));
984: }
985:
986: 987: 988:
989: function save()
990: {
991: if ($this->id) {
992:
993: $update = $GLOBALS['trean_db']->prepare('
994: UPDATE trean_bookmarks
995: SET folder_id = ?,
996: bookmark_url = ?,
997: bookmark_title = ?,
998: bookmark_description = ?,
999: bookmark_clicks = ?,
1000: bookmark_rating = ?
1001: WHERE bookmark_id = ?',
1002: array('integer', 'text', 'text', 'text', 'integer', 'integer', 'integer')
1003: );
1004: if (is_a($update, 'PEAR_Error')) {
1005: return $update;
1006: }
1007: $result = $update->execute(array($this->folder,
1008: Horde_String::convertCharset($this->url, 'UTF-8', $GLOBALS['conf']['sql']['charset']),
1009: Horde_String::convertCharset($this->title, 'UTF-8', $GLOBALS['conf']['sql']['charset']),
1010: Horde_String::convertCharset($this->description, 'UTF-8', $GLOBALS['conf']['sql']['charset']),
1011: $this->clicks,
1012: $this->rating,
1013: $this->id));
1014: if (is_a($result, 'PEAR_Error')) {
1015: Horde::logMessage($result, __FILE__, __LINE__, PEAR_LOG_ERR);
1016: }
1017: return $result;
1018: }
1019:
1020: if (!$this->folder || !strlen($this->url)) {
1021: return PEAR::raiseError('Incomplete bookmark');
1022: }
1023:
1024:
1025: $bookmark_id = $GLOBALS['trean_db']->nextId('trean_bookmarks');
1026: if (is_a($bookmark_id, 'PEAR_Error')) {
1027: Horde::logMessage($bookmark_id, __FILE__, __LINE__, PEAR_LOG_ERR);
1028: return $bookmark_id;
1029: }
1030:
1031: $insert = $GLOBALS['trean_db']->prepare('
1032: INSERT INTO trean_bookmarks
1033: (bookmark_id, folder_id, bookmark_url, bookmark_title, bookmark_description,
1034: bookmark_clicks, bookmark_rating)
1035: VALUES (?, ?, ?, ?, ?, ?, ?)',
1036: array('integer', 'integer', 'text', 'text', 'text', 'integer', 'integer')
1037: );
1038: if (is_a($insert, 'PEAR_Error')) {
1039: return $insert;
1040: }
1041:
1042: $result = $insert->execute(array($bookmark_id,
1043: $this->folder,
1044: Horde_String::convertCharset($this->url, 'UTF-8', $GLOBALS['conf']['sql']['charset']),
1045: Horde_String::convertCharset($this->title, 'UTF-8', $GLOBALS['conf']['sql']['charset']),
1046: Horde_String::convertCharset($this->description, 'UTF-8', $GLOBALS['conf']['sql']['charset']),
1047: $this->clicks,
1048: $this->rating,
1049: ));
1050: if (is_a($result, 'PEAR_Error')) {
1051: Horde::logMessage($result, __FILE__, __LINE__, PEAR_LOG_ERR);
1052: return $result;
1053: }
1054:
1055: $this->id = (int)$bookmark_id;
1056: return $this->id;
1057: }
1058:
1059: }
1060: