PageRenderTime 52ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/Sabre/CardDAV/Backend/PDO.php

http://github.com/evert/SabreDAV
PHP | 330 lines | 117 code | 64 blank | 149 comment | 1 complexity | 37806b320990b8589b08726715ecefa3 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. <?php
  2. /**
  3. * PDO CardDAV backend
  4. *
  5. * This CardDAV backend uses PDO to store addressbooks
  6. *
  7. * @package Sabre
  8. * @subpackage CardDAV
  9. * @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
  10. * @author Evert Pot (http://www.rooftopsolutions.nl/)
  11. * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
  12. */
  13. class Sabre_CardDAV_Backend_PDO extends Sabre_CardDAV_Backend_Abstract {
  14. /**
  15. * PDO connection
  16. *
  17. * @var PDO
  18. */
  19. protected $pdo;
  20. /**
  21. * The PDO table name used to store addressbooks
  22. */
  23. protected $addressBooksTableName;
  24. /**
  25. * The PDO table name used to store cards
  26. */
  27. protected $cardsTableName;
  28. /**
  29. * Sets up the object
  30. *
  31. * @param PDO $pdo
  32. * @param string $addressBooksTableName
  33. * @param string $cardsTableName
  34. */
  35. public function __construct(PDO $pdo, $addressBooksTableName = 'addressbooks', $cardsTableName = 'cards') {
  36. $this->pdo = $pdo;
  37. $this->addressBooksTableName = $addressBooksTableName;
  38. $this->cardsTableName = $cardsTableName;
  39. }
  40. /**
  41. * Returns the list of addressbooks for a specific user.
  42. *
  43. * @param string $principalUri
  44. * @return array
  45. */
  46. public function getAddressBooksForUser($principalUri) {
  47. $stmt = $this->pdo->prepare('SELECT id, uri, displayname, principaluri, description, ctag FROM '.$this->addressBooksTableName.' WHERE principaluri = ?');
  48. $stmt->execute(array($principalUri));
  49. $addressBooks = array();
  50. foreach($stmt->fetchAll() as $row) {
  51. $addressBooks[] = array(
  52. 'id' => $row['id'],
  53. 'uri' => $row['uri'],
  54. 'principaluri' => $row['principaluri'],
  55. '{DAV:}displayname' => $row['displayname'],
  56. '{' . Sabre_CardDAV_Plugin::NS_CARDDAV . '}addressbook-description' => $row['description'],
  57. '{http://calendarserver.org/ns/}getctag' => $row['ctag'],
  58. '{' . Sabre_CardDAV_Plugin::NS_CARDDAV . '}supported-address-data' =>
  59. new Sabre_CardDAV_Property_SupportedAddressData(),
  60. );
  61. }
  62. return $addressBooks;
  63. }
  64. /**
  65. * Updates an addressbook's properties
  66. *
  67. * See Sabre_DAV_IProperties for a description of the mutations array, as
  68. * well as the return value.
  69. *
  70. * @param mixed $addressBookId
  71. * @param array $mutations
  72. * @see Sabre_DAV_IProperties::updateProperties
  73. * @return bool|array
  74. */
  75. public function updateAddressBook($addressBookId, array $mutations) {
  76. $updates = array();
  77. foreach($mutations as $property=>$newValue) {
  78. switch($property) {
  79. case '{DAV:}displayname' :
  80. $updates['displayname'] = $newValue;
  81. break;
  82. case '{' . Sabre_CardDAV_Plugin::NS_CARDDAV . '}addressbook-description' :
  83. $updates['description'] = $newValue;
  84. break;
  85. default :
  86. // If any unsupported values were being updated, we must
  87. // let the entire request fail.
  88. return false;
  89. }
  90. }
  91. // No values are being updated?
  92. if (!$updates) {
  93. return false;
  94. }
  95. $query = 'UPDATE ' . $this->addressBooksTableName . ' SET ctag = ctag + 1 ';
  96. foreach($updates as $key=>$value) {
  97. $query.=', `' . $key . '` = :' . $key . ' ';
  98. }
  99. $query.=' WHERE id = :addressbookid';
  100. $stmt = $this->pdo->prepare($query);
  101. $updates['addressbookid'] = $addressBookId;
  102. $stmt->execute($updates);
  103. return true;
  104. }
  105. /**
  106. * Creates a new address book
  107. *
  108. * @param string $principalUri
  109. * @param string $url Just the 'basename' of the url.
  110. * @param array $properties
  111. * @return void
  112. */
  113. public function createAddressBook($principalUri, $url, array $properties) {
  114. $values = array(
  115. 'displayname' => null,
  116. 'description' => null,
  117. 'principaluri' => $principalUri,
  118. 'uri' => $url,
  119. );
  120. foreach($properties as $property=>$newValue) {
  121. switch($property) {
  122. case '{DAV:}displayname' :
  123. $values['displayname'] = $newValue;
  124. break;
  125. case '{' . Sabre_CardDAV_Plugin::NS_CARDDAV . '}addressbook-description' :
  126. $values['description'] = $newValue;
  127. break;
  128. default :
  129. throw new Sabre_DAV_Exception_BadRequest('Unknown property: ' . $property);
  130. }
  131. }
  132. $query = 'INSERT INTO ' . $this->addressBooksTableName . ' (uri, displayname, description, principaluri, ctag) VALUES (:uri, :displayname, :description, :principaluri, 1)';
  133. $stmt = $this->pdo->prepare($query);
  134. $stmt->execute($values);
  135. }
  136. /**
  137. * Deletes an entire addressbook and all its contents
  138. *
  139. * @param int $addressBookId
  140. * @return void
  141. */
  142. public function deleteAddressBook($addressBookId) {
  143. $stmt = $this->pdo->prepare('DELETE FROM ' . $this->cardsTableName . ' WHERE addressbookid = ?');
  144. $stmt->execute(array($addressBookId));
  145. $stmt = $this->pdo->prepare('DELETE FROM ' . $this->addressBooksTableName . ' WHERE id = ?');
  146. $stmt->execute(array($addressBookId));
  147. }
  148. /**
  149. * Returns all cards for a specific addressbook id.
  150. *
  151. * This method should return the following properties for each card:
  152. * * carddata - raw vcard data
  153. * * uri - Some unique url
  154. * * lastmodified - A unix timestamp
  155. *
  156. * It's recommended to also return the following properties:
  157. * * etag - A unique etag. This must change every time the card changes.
  158. * * size - The size of the card in bytes.
  159. *
  160. * If these last two properties are provided, less time will be spent
  161. * calculating them. If they are specified, you can also ommit carddata.
  162. * This may speed up certain requests, especially with large cards.
  163. *
  164. * @param mixed $addressbookId
  165. * @return array
  166. */
  167. public function getCards($addressbookId) {
  168. $stmt = $this->pdo->prepare('SELECT id, carddata, uri, lastmodified FROM ' . $this->cardsTableName . ' WHERE addressbookid = ?');
  169. $stmt->execute(array($addressbookId));
  170. return $stmt->fetchAll(PDO::FETCH_ASSOC);
  171. }
  172. /**
  173. * Returns a specfic card.
  174. *
  175. * The same set of properties must be returned as with getCards. The only
  176. * exception is that 'carddata' is absolutely required.
  177. *
  178. * @param mixed $addressBookId
  179. * @param string $cardUri
  180. * @return array
  181. */
  182. public function getCard($addressBookId, $cardUri) {
  183. $stmt = $this->pdo->prepare('SELECT id, carddata, uri, lastmodified FROM ' . $this->cardsTableName . ' WHERE addressbookid = ? AND uri = ? LIMIT 1');
  184. $stmt->execute(array($addressBookId, $cardUri));
  185. $result = $stmt->fetchAll(PDO::FETCH_ASSOC);
  186. return (count($result)>0?$result[0]:false);
  187. }
  188. /**
  189. * Creates a new card.
  190. *
  191. * The addressbook id will be passed as the first argument. This is the
  192. * same id as it is returned from the getAddressbooksForUser method.
  193. *
  194. * The cardUri is a base uri, and doesn't include the full path. The
  195. * cardData argument is the vcard body, and is passed as a string.
  196. *
  197. * It is possible to return an ETag from this method. This ETag is for the
  198. * newly created resource, and must be enclosed with double quotes (that
  199. * is, the string itself must contain the double quotes).
  200. *
  201. * You should only return the ETag if you store the carddata as-is. If a
  202. * subsequent GET request on the same card does not have the same body,
  203. * byte-by-byte and you did return an ETag here, clients tend to get
  204. * confused.
  205. *
  206. * If you don't return an ETag, you can just return null.
  207. *
  208. * @param mixed $addressBookId
  209. * @param string $cardUri
  210. * @param string $cardData
  211. * @return string|null
  212. */
  213. public function createCard($addressBookId, $cardUri, $cardData) {
  214. $stmt = $this->pdo->prepare('INSERT INTO ' . $this->cardsTableName . ' (carddata, uri, lastmodified, addressbookid) VALUES (?, ?, ?, ?)');
  215. $result = $stmt->execute(array($cardData, $cardUri, time(), $addressBookId));
  216. $stmt2 = $this->pdo->prepare('UPDATE ' . $this->addressBooksTableName . ' SET ctag = ctag + 1 WHERE id = ?');
  217. $stmt2->execute(array($addressBookId));
  218. return '"' . md5($cardData) . '"';
  219. }
  220. /**
  221. * Updates a card.
  222. *
  223. * The addressbook id will be passed as the first argument. This is the
  224. * same id as it is returned from the getAddressbooksForUser method.
  225. *
  226. * The cardUri is a base uri, and doesn't include the full path. The
  227. * cardData argument is the vcard body, and is passed as a string.
  228. *
  229. * It is possible to return an ETag from this method. This ETag should
  230. * match that of the updated resource, and must be enclosed with double
  231. * quotes (that is: the string itself must contain the actual quotes).
  232. *
  233. * You should only return the ETag if you store the carddata as-is. If a
  234. * subsequent GET request on the same card does not have the same body,
  235. * byte-by-byte and you did return an ETag here, clients tend to get
  236. * confused.
  237. *
  238. * If you don't return an ETag, you can just return null.
  239. *
  240. * @param mixed $addressBookId
  241. * @param string $cardUri
  242. * @param string $cardData
  243. * @return string|null
  244. */
  245. public function updateCard($addressBookId, $cardUri, $cardData) {
  246. $stmt = $this->pdo->prepare('UPDATE ' . $this->cardsTableName . ' SET carddata = ?, lastmodified = ? WHERE uri = ? AND addressbookid =?');
  247. $stmt->execute(array($cardData, time(), $cardUri, $addressBookId));
  248. $stmt2 = $this->pdo->prepare('UPDATE ' . $this->addressBooksTableName . ' SET ctag = ctag + 1 WHERE id = ?');
  249. $stmt2->execute(array($addressBookId));
  250. return '"' . md5($cardData) . '"';
  251. }
  252. /**
  253. * Deletes a card
  254. *
  255. * @param mixed $addressBookId
  256. * @param string $cardUri
  257. * @return bool
  258. */
  259. public function deleteCard($addressBookId, $cardUri) {
  260. $stmt = $this->pdo->prepare('DELETE FROM ' . $this->cardsTableName . ' WHERE addressbookid = ? AND uri = ?');
  261. $stmt->execute(array($addressBookId, $cardUri));
  262. $stmt2 = $this->pdo->prepare('UPDATE ' . $this->addressBooksTableName . ' SET ctag = ctag + 1 WHERE id = ?');
  263. $stmt2->execute(array($addressBookId));
  264. return $stmt->rowCount()===1;
  265. }
  266. }