PageRenderTime 71ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/application/models/contacts/Contact.class.php

https://github.com/fb83/Project-Pier
PHP | 843 lines | 334 code | 93 blank | 416 comment | 58 complexity | 0ca5622914bcd61d59b375bd805f1cce MD5 | raw file
Possible License(s): AGPL-1.0, GPL-2.0, AGPL-3.0, LGPL-2.1, GPL-3.0
  1. <?php
  2. /**
  3. * Contact class
  4. *
  5. * @http://www.projectpier.org/
  6. */
  7. class Contact extends BaseContact {
  8. /**
  9. * Cached associated user
  10. *
  11. * @var User
  12. */
  13. private $user = null;
  14. /**
  15. * True if user is member of owner company. This value is read on first request and cached
  16. *
  17. * @var boolean
  18. */
  19. private $is_member_of_owner_company = null;
  20. /**
  21. * Cached is_administrator value. First time value is requested it will be checked and cached.
  22. * After that every request will return cached value
  23. *
  24. * @var boolean
  25. */
  26. private $is_administrator = null;
  27. /**
  28. * Cached is_account_owner value. Value is retrieved on first requests
  29. *
  30. * @var boolean
  31. */
  32. private $is_account_owner = null;
  33. /**
  34. * If true this object will not throw object not taggable exception and will make tag methods available
  35. *
  36. * @var boolean
  37. */
  38. protected $is_taggable = true;
  39. /**
  40. * Check if this contact is member of specific company
  41. *
  42. * @access public
  43. * @param Company $company
  44. * @return boolean
  45. */
  46. function isMemberOf(Company $company) {
  47. return $this->getCompanyId() == $company->getId();
  48. } // isMemberOf
  49. /**
  50. * Usually we check if user is member of owner company so this is the shortcut method
  51. *
  52. * @param void
  53. * @return boolean
  54. */
  55. function isMemberOfOwnerCompany() {
  56. if (is_null($this->is_member_of_owner_company)) {
  57. $this->is_member_of_owner_company = $this->isMemberOf(owner_company());
  58. }
  59. return $this->is_member_of_owner_company;
  60. } // isMemberOfOwnerCompany
  61. /**
  62. * Check if this user is part of specific project
  63. *
  64. * @param Project $project
  65. * @return boolean
  66. */
  67. function isProjectUser(Project $project) {
  68. if (!isset($this->is_project_user_cache[$project->getId()])) {
  69. $project_user = ProjectUsers::findById(array(
  70. 'project_id' => $project->getId(),
  71. 'user_id' => $this->getId())
  72. ); // findById
  73. $this->is_project_user_cache[$project->getId()] = $project_user instanceof ProjectUser;
  74. } // if
  75. return $this->is_project_user_cache[$project->getId()];
  76. } // isProjectUser
  77. /**
  78. * Check if this of specific company website. If must be member of that company and is_admin flag set to true
  79. *
  80. * @param void
  81. * @return boolean
  82. */
  83. function isAdministrator() {
  84. if ($this->getUserAccount()) {
  85. return $this->getUserAccount()->isAdministrator();
  86. }
  87. return false;
  88. } // isAdministrator
  89. /**
  90. * Account owner is user account that was created when company website is created
  91. *
  92. * @param void
  93. * @return boolean
  94. */
  95. function isAccountOwner() {
  96. if ($this->getUserAccount()) {
  97. return $this->getUserAccount()->isAccountOwner();
  98. }
  99. return false;
  100. } // isAccountOwner
  101. /**
  102. * Returns if contact is a favorite
  103. *
  104. * @param void
  105. * @return boolean
  106. */
  107. function isFavorite() {
  108. return $this->getIsFavorite();
  109. } // isFavorite
  110. /**
  111. * Returns true. Functions to accommodate tags on Contacts
  112. *
  113. * @param void
  114. * @return boolean
  115. */
  116. function isPrivate() {
  117. return false;
  118. } // isPrivate
  119. // ---------------------------------------------------
  120. // Retrieve
  121. // ---------------------------------------------------
  122. /**
  123. * Return owner company
  124. *
  125. * @access public
  126. * @param void
  127. * @return Company
  128. */
  129. function getCompany() {
  130. $company = Companies::findById($this->getCompanyId());
  131. if ($company) return $company;
  132. return new Company();
  133. } // getCompany
  134. /**
  135. * Return associated user account
  136. *
  137. * @param void
  138. * @return User
  139. */
  140. function getUserAccount() {
  141. if (is_null($this->user)) {
  142. $this->user = Users::findById($this->getUserId());
  143. } // if
  144. return $this->user;
  145. } // getUser
  146. /**
  147. * True if contact has an associated user account
  148. *
  149. * @param void
  150. * @return boolean
  151. */
  152. function hasUserAccount() {
  153. return ($this->getUserAccount() ? true : false);
  154. } // hasUserAccount
  155. /**
  156. * Return display name for this account. If there is no display name associated username will be used
  157. *
  158. * @access public
  159. * @param void
  160. * @return string
  161. */
  162. function getDisplayName() {
  163. $display = parent::getDisplayName();
  164. return trim($display) == '' ? $this->getUserAccount()->getUsername() : $display;
  165. } // getDisplayName
  166. /**
  167. * Returns true if we have title value set
  168. *
  169. * @access public
  170. * @param void
  171. * @return boolean
  172. */
  173. function hasTitle() {
  174. return trim($this->getTitle()) <> '';
  175. } // hasTitle
  176. // ---------------------------------------------------
  177. // IMs
  178. // ---------------------------------------------------
  179. /**
  180. * Return true if this contact have at least one IM address
  181. *
  182. * @access public
  183. * @param void
  184. * @return boolean
  185. */
  186. function hasImValue() {
  187. return ContactImValues::count('`contact_id` = ' . DB::escape($this->getId()));
  188. } // hasImValue
  189. /**
  190. * Return all IM values
  191. *
  192. * @access public
  193. * @param void
  194. * @return array
  195. */
  196. function getImValues() {
  197. return ContactImValues::getByContact($this);
  198. } // getImValues
  199. /**
  200. * Return value of specific IM. This function will return null if IM is not found
  201. *
  202. * @access public
  203. * @param ImType $im_type
  204. * @return string
  205. */
  206. function getImValue(ImType $im_type) {
  207. $im_value = ContactImValues::findById(array('contact_id' => $this->getId(), 'im_type_id' => $im_type->getId()));
  208. return $im_value instanceof ContactImValue && (trim($im_value->getValue()) <> '') ? $im_value->getValue() : null;
  209. } // getImValue
  210. /**
  211. * Return default IM value. If value was not found NULL is returned
  212. *
  213. * @access public
  214. * @param void
  215. * @return string
  216. */
  217. function getDefaultImValue() {
  218. $default_im_type = $this->getDefaultImType();
  219. return $this->getImValue($default_im_type);
  220. } // getDefaultImValue
  221. /**
  222. * Return default contact IM type. If there is no default contact IM type NULL is returned
  223. *
  224. * @access public
  225. * @param void
  226. * @return ImType
  227. */
  228. function getDefaultImType() {
  229. return ContactImValues::getDefaultContactImType($this);
  230. } // getDefaultImType
  231. /**
  232. * Clear all IM values
  233. *
  234. * @access public
  235. * @param void
  236. * @return boolean
  237. */
  238. function clearImValues() {
  239. return ContactImValues::instance()->clearByContact($this);
  240. } // clearImValues
  241. // ---------------------------------------------------
  242. // Avatars
  243. // ---------------------------------------------------
  244. /**
  245. * Set contact avatar from $source file
  246. *
  247. * @param string $source Source file
  248. * @param integer $max_width Max avatar width
  249. * @param integer $max_height Max avatar height
  250. * @param boolean $save Save contact object when done
  251. * @return string
  252. */
  253. function setAvatar($source, $max_width = 50, $max_height = 50, $save = true) {
  254. if (!is_readable($source)) {
  255. return false;
  256. }
  257. do {
  258. $temp_file = ROOT . '/cache/' . sha1(uniqid(rand(), true));
  259. } while (is_file($temp_file));
  260. try {
  261. Env::useLibrary('simplegd');
  262. $image = new SimpleGdImage($source);
  263. $thumb = $image->scale($max_width, $max_height, SimpleGdImage::BOUNDARY_DECREASE_ONLY, false);
  264. $thumb->saveAs($temp_file, IMAGETYPE_PNG);
  265. $public_filename = PublicFiles::addFile($temp_file, 'png');
  266. if ($public_filename) {
  267. $this->setAvatarFile($public_filename);
  268. if ($save) {
  269. $this->save();
  270. } // if
  271. } // if
  272. $result = true;
  273. } catch (Exception $e) {
  274. $result = false;
  275. } // try
  276. // Cleanup
  277. if (!$result && $public_filename) {
  278. PublicFiles::deleteFile($public_filename);
  279. } // if
  280. @unlink($temp_file);
  281. return $result;
  282. } // setAvatar
  283. /**
  284. * Delete avatar
  285. *
  286. * @param void
  287. * @return null
  288. */
  289. function deleteAvatar() {
  290. if ($this->hasAvatar()) {
  291. PublicFiles::deleteFile($this->getAvatarFile());
  292. $this->setAvatarFile('');
  293. } // if
  294. } // deleteAvatar
  295. /**
  296. * Return path to the avatar file. This function just generates the path, does not check if file really exists
  297. *
  298. * @access public
  299. * @param void
  300. * @return string
  301. */
  302. function getAvatarPath() {
  303. return PublicFiles::getFilePath($this->getAvatarFile());
  304. } // getAvatarPath
  305. /**
  306. * Return URL of avatar
  307. *
  308. * @access public
  309. * @param void
  310. * @return string
  311. */
  312. function getAvatarUrl() {
  313. if ($this->getUseGravatar()) return 'http://www.gravatar.com/avatar/' . md5( strtolower( trim( $this->getEmail() ))) . '?s=50';
  314. return $this->hasAvatar() ? PublicFiles::getFileUrl($this->getAvatarFile()) : get_image_url('avatar.gif');
  315. } // getAvatarUrl
  316. /**
  317. * Check if this contact has uploaded an avatar
  318. *
  319. * @access public
  320. * @param void
  321. * @return boolean
  322. */
  323. function hasAvatar() {
  324. return (trim($this->getAvatarFile()) <> '') && is_file($this->getAvatarPath());
  325. } // hasAvatar
  326. // ---------------------------------------------------
  327. // Permissions
  328. // ---------------------------------------------------
  329. /**
  330. * Can specific user add contact to specific company
  331. *
  332. * @access public
  333. * @param User $user
  334. * @param Company $to Can user add user to this company
  335. * @return boolean
  336. */
  337. function canAdd(User $user, Company $to = null) {
  338. if ($user->isAccountOwner()) {
  339. return true;
  340. } // if
  341. return $user->isAdministrator();
  342. } // canAdd
  343. /**
  344. * Check if specific user can update this contact
  345. *
  346. * @access public
  347. * @param User $user
  348. * @return boolean
  349. */
  350. function canEdit(User $user) {
  351. if ($this->hasUserAccount() && $user->getId() == $this->getUserId()) {
  352. return true; // own profile
  353. } // if
  354. if ($user->isAccountOwner()) {
  355. return true;
  356. } // if
  357. return $user->isAdministrator();
  358. } // canEdit
  359. /**
  360. * Check if specific user can delete specific contact
  361. *
  362. * @param User $user
  363. * @return boolean
  364. */
  365. function canDelete(User $user) {
  366. if ($this->isAccountOwner()) {
  367. return false; // can't delete accountowner
  368. } // if
  369. if ($this->getId() == $user->getId()) {
  370. return false; // can't delete self
  371. } // if
  372. return $user->isAdministrator();
  373. } // canDelete
  374. /**
  375. * Returns if this user can add a user account to that contact
  376. *
  377. * @param User $user
  378. * @return boolean
  379. */
  380. function canAddUserAccount(User $user) {
  381. if ($user->isAccountOwner()) {
  382. return true; // account owner can manage users
  383. } // if
  384. return $user->isAdministrator();
  385. } // canAddUserAccount
  386. /**
  387. * Returns if this user can edit the user account linked to that contact
  388. *
  389. * @param User $user
  390. * @return boolean
  391. */
  392. function canEditUserAccount(User $user) {
  393. if ($user->isAccountOwner()) {
  394. return true;
  395. } // if
  396. if ($this->getUserId() == $user->getId()) {
  397. return true;
  398. } // can edit your own user account
  399. return $user->isAdministrator();
  400. } // canEditUserAccount
  401. /**
  402. * Returns if this user can delete the user account linked to that contact
  403. *
  404. * @param User $user
  405. * @return boolean
  406. */
  407. function canDeleteUserAccount(User $user) {
  408. if ($this->isAccountOwner()) {
  409. return false; // can't delete accountowner
  410. } // if
  411. if ($this->getUserId() == $user->getId()) {
  412. return false;
  413. } // can not delete your own user account
  414. return $user->isAdministrator();
  415. } // canEditUserAccount
  416. /**
  417. * Check if specific user can update this profile
  418. *
  419. * @param User $user
  420. * @return boolean
  421. */
  422. function canUpdateProfile(User $user) {
  423. if ($this->hasUserAccount() && $this->getUserId() == $user->getId()) {
  424. return true;
  425. } // if
  426. if ($user->isAdministrator()) {
  427. return true;
  428. } // if
  429. return false;
  430. } // canUpdateProfile
  431. // ---------------------------------------------------
  432. // URLs
  433. // ---------------------------------------------------
  434. // /**
  435. // * Return view account URL of this user
  436. // *
  437. // * @access public
  438. // * @param void
  439. // * @return string
  440. // */
  441. // function getAccountUrl() {
  442. // return get_url('account', 'index');
  443. // } // getAccountUrl
  444. /**
  445. * Show contact card page
  446. *
  447. * @access public
  448. * @param void
  449. * @return null
  450. */
  451. function getCardUrl() {
  452. return get_url('contacts', 'card', $this->getId());
  453. } // getCardUrl
  454. /**
  455. * Return edit contact URL
  456. *
  457. * @access public
  458. * @param string $redirect_to URL where we need to redirect user when he updates contact
  459. * @return string
  460. */
  461. function getEditUrl($redirect_to = null) {
  462. $attributes = array('id' => $this->getId());
  463. if (trim($redirect_to) <> '') {
  464. $attributes['redirect_to'] = str_replace('&amp;', '&', trim($redirect_to));
  465. } // if
  466. return get_url('contacts', 'edit', $attributes);
  467. } // getEditUrl
  468. /**
  469. * Return edit contact URL
  470. *
  471. * @access public
  472. * @param string $redirect_to URL where we need to redirect user when he updates contact avatar
  473. * @return string
  474. */
  475. function getUpdateAvatarUrl($redirect_to = null) {
  476. $attributes = array('id' => $this->getId());
  477. if (trim($redirect_to) <> '') {
  478. $attributes['redirect_to'] = str_replace('&amp;', '&', trim($redirect_to));
  479. } // if
  480. return get_url('contacts', 'edit_avatar', $attributes);
  481. } // getEditUrl
  482. /**
  483. * Return delete contact URL
  484. *
  485. * @access public
  486. * @param void
  487. * @return string
  488. */
  489. function getDeleteUrl() {
  490. return get_url('contacts', 'delete', $this->getId());
  491. } // getDeleteUrl
  492. /**
  493. * Returns URL to attach a User account to that contact
  494. *
  495. * @param void
  496. * @return string
  497. */
  498. function getAddUserAccountUrl() {
  499. return get_url('contacts', 'add_user_account', $this->getId());
  500. } // getAddUserUrl
  501. /**
  502. * Returns URL to edit User account linked to that contact
  503. *
  504. * @param void
  505. * @return string
  506. */
  507. function getEditUserAccountUrl() {
  508. return get_url('contacts', 'edit_user_account', $this->getId());
  509. } // getEditUserAccountUrl
  510. /**
  511. * Returns URL to delete User account linked to that contact
  512. *
  513. * @param void
  514. * @return string
  515. */
  516. function getDeleteUserAccountUrl() {
  517. return get_url('contacts', 'delete_user_account', $this->getId());
  518. } // getDeleteUserAccountUrl
  519. /**
  520. * Return toggle favorite URL
  521. *
  522. * @param void
  523. * @return string
  524. */
  525. function getToggleFavoriteUrl($redirect_to = null) {
  526. $attributes = array('id' => $this->getId());
  527. if (trim($redirect_to) <> '') {
  528. $attributes['redirect_to'] = str_replace('&amp;', '&', trim($redirect_to));
  529. } // if
  530. return get_url('contacts', 'toggle_favorite', $attributes);
  531. } // getToggleFavoriteUrl
  532. /**
  533. * Reserve parking space URL
  534. *
  535. * @access public
  536. * @param void
  537. * @return null
  538. */
  539. function getReserveParkingSpaceUrl() {
  540. $url = trim(config_option('parking space reservation url', ''));
  541. if ($url != '') {
  542. $url .= '?license_plate=' . $this->getLicensePlate();
  543. }
  544. return $url;
  545. } // getReserveParkingSpaceUrl
  546. /**
  547. * Show map page
  548. *
  549. * @access public
  550. * @param void
  551. * @return null
  552. */
  553. function getShowMapUrl() {
  554. $location = urlencode($this->getLocationDetails());
  555. $map_url = config_option('map url', 'http://maps.google.com?q=$location');
  556. $map_url = str_replace('$location', $location, $map_url);
  557. return $map_url;
  558. } // getShowMapUrl
  559. /**
  560. * Show route page
  561. *
  562. * @access public
  563. * @param void
  564. * @return null
  565. */
  566. function getShowRouteUrl($contact) {
  567. $to = '';
  568. if ($contact instanceof Contact) {
  569. $to = urlencode($contact->getLocationDetails());
  570. }
  571. $route_url = config_option('route url', 'http://maps.google.com?saddr=$from&daddr=$to');
  572. $route_url = str_replace('$to', $to, $route_url);
  573. $from = urlencode($this->getLocationDetails());
  574. $route_url = str_replace('$from', $from, $route_url);
  575. return $route_url;
  576. } // getShowRouteUrl
  577. // ---------------------------------------------------
  578. // Tags
  579. // ---------------------------------------------------
  580. /**
  581. * Returns true if this project is taggable
  582. *
  583. * @param void
  584. * @return boolean
  585. */
  586. function isTaggable() {
  587. return $this->is_taggable;
  588. } // isTaggable
  589. /**
  590. * Return tags for this object
  591. *
  592. * @param void
  593. * @return array
  594. */
  595. function getTags() {
  596. if (plugin_active('tags')) {
  597. if (!$this->isTaggable()) {
  598. throw new Error('Object not taggable');
  599. }
  600. return Tags::getTagsByObject($this, get_class($this->manager()));
  601. }
  602. return array();
  603. } // getTags
  604. /**
  605. * Return tag names for this object
  606. *
  607. * @access public
  608. * @param void
  609. * @return array
  610. */
  611. function getTagNames() {
  612. if (plugin_active('tags')) {
  613. if (!$this->isTaggable()) {
  614. throw new Error('Object not taggable');
  615. } // if
  616. return Tags::getTagNamesByObject($this, get_class($this->manager()));
  617. }
  618. return array();
  619. } // getTagNames
  620. /**
  621. * Explode input string and set array of tags
  622. *
  623. * @param string $input
  624. * @return boolean
  625. */
  626. function setTagsFromCSV($input) {
  627. $tag_names = array();
  628. if (trim($input)) {
  629. $tag_names = explode(',', $input);
  630. foreach ($tag_names as $k => $v) {
  631. if (trim($v) <> '') {
  632. $tag_names[$k] = trim($v);
  633. } // if
  634. } // foreach
  635. } // if
  636. return $this->setTags($tag_names);
  637. } // setTagsFromCSV
  638. /**
  639. * Set object tags. This function accepts tags as params
  640. *
  641. * @access public
  642. * @param void
  643. * @return boolean
  644. */
  645. function setTags() {
  646. if (plugin_active('tags')) {
  647. if (!$this->isTaggable()) {
  648. throw new Error('Object not taggable');
  649. }
  650. $args = array_flat(func_get_args());
  651. return Tags::setObjectTags($args, $this, get_class($this->manager()), null);
  652. }
  653. return array();
  654. } // setTags
  655. /**
  656. * Clear object tags
  657. *
  658. * @access public
  659. * @param void
  660. * @return boolean
  661. */
  662. function clearTags() {
  663. if (plugin_active('tags')) {
  664. if (!$this->isTaggable()) {
  665. throw new Error('Object not taggable');
  666. }
  667. return Tags::clearObjectTags($this, get_class($this->manager()));
  668. }
  669. return array();
  670. } // clearTags
  671. // ---------------------------------------------------
  672. // System functions
  673. // ---------------------------------------------------
  674. /**
  675. * Validate data before save
  676. *
  677. * @access public
  678. * @param array $errors
  679. * @return void
  680. */
  681. function validate(&$errors) {
  682. // Validate display_name if present
  683. if (!$this->validatePresenceOf('display_name')) {
  684. $errors[] = lang('name value required');
  685. } // if
  686. // Company ID
  687. if (!$this->validatePresenceOf('company_id')) {
  688. $errors[] = lang('company value required');
  689. }
  690. } // validate
  691. /**
  692. * Delete this object
  693. *
  694. * @param void
  695. * @return boolean
  696. */
  697. function delete() {
  698. if ($this->isAccountOwner()) {
  699. return false;
  700. } // if
  701. if ($this->isTaggable()) {
  702. $this->clearTags();
  703. } // if
  704. // TODO check all things that need to be deleted
  705. // ticket subscriptions
  706. // message subscriptions
  707. // project-user association
  708. $this->deleteAvatar();
  709. $this->clearImValues();
  710. if ($this->hasUserAccount()) {
  711. ProjectUsers::clearByUser($this->getUserAccount());
  712. MessageSubscriptions::clearByUser($this->getUserAccount());
  713. $this->getUserAccount()->delete();
  714. } // if
  715. return parent::delete();
  716. } // delete
  717. // ---------------------------------------------------
  718. // ApplicationDataObject implementation
  719. // ---------------------------------------------------
  720. /**
  721. * Return object name
  722. *
  723. * @access public
  724. * @param void
  725. * @return string
  726. */
  727. function getObjectName() {
  728. return $this->getDisplayName();
  729. } // getObjectName
  730. /**
  731. * Return object type name
  732. *
  733. * @param void
  734. * @return string
  735. */
  736. function getObjectTypeName() {
  737. return lang('contact');
  738. } // getObjectTypeName
  739. /**
  740. * Return object URl
  741. *
  742. * @access public
  743. * @param void
  744. * @return string
  745. */
  746. function getObjectUrl() {
  747. return $this->getCardUrl();
  748. } // getObjectUrl
  749. } // Contact
  750. ?>