PageRenderTime 58ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 0ms

/application/models/project_milestones/ProjectMilestone.class.php

https://github.com/fb83/Project-Pier
PHP | 598 lines | 229 code | 57 blank | 312 comment | 48 complexity | 317fdddfc6d1ad050f1223a815eac187 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. * ProjectMilestone class
  4. * Generated on Sat, 04 Mar 2006 12:50:11 +0100 by DataObject generation tool
  5. *
  6. * @http://www.projectpier.org/
  7. */
  8. class ProjectMilestone extends BaseProjectMilestone {
  9. /**
  10. * This project object is taggable
  11. *
  12. * @var boolean
  13. */
  14. protected $is_taggable = true;
  15. /**
  16. * Message comments are searchable
  17. *
  18. * @var boolean
  19. */
  20. protected $is_searchable = true;
  21. /**
  22. * Array of searchable columns
  23. *
  24. * @var array
  25. */
  26. protected $searchable_columns = array('name', 'description');
  27. /**
  28. * Milestones are commentable
  29. *
  30. * @var boolean
  31. */
  32. protected $is_commentable = true;
  33. /**
  34. * Cached User object of person who completed this milestone
  35. *
  36. * @var User
  37. */
  38. private $completed_by;
  39. /**
  40. * Return if this milestone is completed
  41. *
  42. * @access public
  43. * @param void
  44. * @return boolean
  45. */
  46. function isCompleted() {
  47. if (is_null($this->getDueDate())) {
  48. return false;
  49. }
  50. return (boolean) $this->getCompletedOn();
  51. } // isCompleted
  52. /**
  53. * Check if this milestone is late
  54. *
  55. * @access public
  56. * @param void
  57. * @return null
  58. */
  59. function isLate() {
  60. if ($this->isCompleted()) {
  61. return false;
  62. }
  63. if (is_null($this->getDueDate())) {
  64. return true;
  65. }
  66. return !$this->isToday() && ($this->getDueDate()->getTimestamp() < time());
  67. } // isLate
  68. /**
  69. * Check if this milestone is today
  70. *
  71. * @access public
  72. * @param void
  73. * @return null
  74. */
  75. function isToday() {
  76. $now = DateTimeValueLib::now();
  77. $due = $this->getDueDate();
  78. // getDueDate and similar functions can return NULL
  79. if (!($due instanceof DateTimeValue)) {
  80. return false;
  81. }
  82. return $now->getDay() == $due->getDay() &&
  83. $now->getMonth() == $due->getMonth() &&
  84. $now->getYear() == $due->getYear();
  85. } // isToday
  86. /**
  87. * Check if this is upcoming milestone
  88. *
  89. * @access public
  90. * @param void
  91. * @return null
  92. */
  93. function isUpcoming() {
  94. return !$this->isCompleted() && !$this->isToday() && ($this->getDueDate()->getTimestamp() > time());
  95. } // isUpcoming
  96. /**
  97. * Return number of days that this milestone is late for
  98. *
  99. * @access public
  100. * @param void
  101. * @return integer
  102. */
  103. function getLateInDays() {
  104. $due_date_start = $this->getDueDate()->beginningOfDay();
  105. return floor(abs($due_date_start->getTimestamp() - DateTimeValueLib::now()->getTimestamp()) / 86400);
  106. } // getLateInDays
  107. /**
  108. * Return number of days that is left
  109. *
  110. * @access public
  111. * @param void
  112. * @return integer
  113. */
  114. function getLeftInDays() {
  115. $due_date_start = $this->getDueDate()->endOfDay();
  116. return floor(abs($due_date_start->getTimestamp() - DateTimeValueLib::now()->beginningOfDay()->getTimestamp()) / 86400);
  117. } // getLeftInDays
  118. /**
  119. * Return difference between specific datetime and due date time in seconds
  120. *
  121. * @access public
  122. * @param DateTime $diff_to
  123. * @return integer
  124. */
  125. private function getDueDateDiff(DateTimeValue $diff_to) {
  126. return $this->getDueDate()->getTimestamp() - $diff_to->getTimestamp();
  127. } // getDueDateDiff
  128. // ---------------------------------------------------
  129. // Related object
  130. // ---------------------------------------------------
  131. /**
  132. * Return project
  133. *
  134. * @access public
  135. * @param void
  136. * @return Project
  137. */
  138. function getProject() {
  139. return Projects::findById($this->getProjectId());
  140. } // getProject
  141. /**
  142. * Return all tasklists connected with this milestone
  143. *
  144. * @access public
  145. * @param void
  146. * @return array
  147. */
  148. function getTaskLists() {
  149. return ProjectTaskLists::findAll(array(
  150. 'conditions' => '`milestone_id` = ' . DB::escape($this->getId()),
  151. 'order' => 'created_on'
  152. )); // findAll
  153. } // getTaskLists
  154. /**
  155. * Returns true if there are task lists in this milestone
  156. *
  157. * @access public
  158. * @param void
  159. * @return boolean
  160. */
  161. function hasTaskLists() {
  162. return (boolean) ProjectTaskLists::count('`milestone_id` = ' . DB::escape($this->getId()));
  163. } // hasTaskLists
  164. /**
  165. * Return all messages related with this message
  166. *
  167. * @access public
  168. * @param void
  169. * @return array
  170. */
  171. function getMessages() {
  172. return ProjectMessages::findAll(array(
  173. 'conditions' => '`milestone_id` = ' . DB::escape($this->getId()),
  174. 'order' => 'created_on'
  175. )); // findAll
  176. } // getMessages
  177. /**
  178. * Returns true if there is messages in this milestone
  179. *
  180. * @access public
  181. * @param void
  182. * @return boolean
  183. */
  184. function hasMessages() {
  185. return (boolean) ProjectMessages::count('`milestone_id` = ' . DB::escape($this->getId()));
  186. } // hasMessages
  187. /**
  188. * Return all tickets related to this message
  189. *
  190. * @access public
  191. * @param void
  192. * @return array
  193. */
  194. function getTickets() {
  195. if (!plugin_active('tickets')) return array();
  196. return ProjectTickets::findAll(array(
  197. 'conditions' => '`milestone_id` = ' . DB::escape($this->getId()),
  198. 'order' => 'created_on'
  199. )); // findAll
  200. } // getTickets
  201. /**
  202. * Returns true if there are tickets in this milestone
  203. *
  204. * @access public
  205. * @param void
  206. * @return boolean
  207. */
  208. function hasTickets() {
  209. if (!plugin_active('tickets')) return false;
  210. return (boolean) ProjectTickets::count('`milestone_id` = ' . DB::escape($this->getId()));
  211. } // hasTickets
  212. /**
  213. * Return assigned to object. It can be User, Company or nobady (NULL)
  214. *
  215. * @access public
  216. * @param void
  217. * @return ApplicationDataObject
  218. */
  219. function getAssignedTo() {
  220. if ($this->getAssignedToUserId() > 0) {
  221. return $this->getAssignedToUser();
  222. } elseif ($this->getAssignedToCompanyId() > 0) {
  223. return $this->getAssignedToCompany();
  224. } else {
  225. return null;
  226. } // if
  227. } // getAssignedTo
  228. /**
  229. * Return responsible company
  230. *
  231. * @access public
  232. * @param void
  233. * @return Company
  234. */
  235. protected function getAssignedToCompany() {
  236. return Companies::findById($this->getAssignedToCompanyId());
  237. } // getAssignedToCompany
  238. /**
  239. * Return responsible user
  240. *
  241. * @access public
  242. * @param void
  243. * @return User
  244. */
  245. protected function getAssignedToUser() {
  246. return Users::findById($this->getAssignedToUserId());
  247. } // getAssignedToUser
  248. /**
  249. * Return User object of person who completed this milestone
  250. *
  251. * @param void
  252. * @return User
  253. */
  254. function getCompletedBy() {
  255. if (is_null($this->completed_by)) {
  256. $this->completed_by = Users::findById($this->getCompletedById());
  257. }
  258. return $this->completed_by;
  259. } // getCompletedBy
  260. // ---------------------------------------------------
  261. // Permissions
  262. // ---------------------------------------------------
  263. /**
  264. * Returns true if specific user has CAN_MANAGE_MILESTONES permission set to true
  265. *
  266. * @access public
  267. * @param User $user
  268. * @return boolean
  269. */
  270. function canManage(User $user) {
  271. return $user->getProjectPermission($this->getProject(), PermissionManager::CAN_MANAGE_MILESTONES);
  272. } // canManage
  273. /**
  274. * Returns true if $user can view this milestone
  275. *
  276. * @param User $user
  277. * @return boolean
  278. */
  279. function canView(User $user) {
  280. if (!$user->isProjectUser($this->getProject())) {
  281. return false;
  282. }
  283. if ($user->isAdministrator()) {
  284. return true;
  285. }
  286. if ($this->isPrivate() && !$user->isMemberOfOwnerCompany()) {
  287. return false;
  288. }
  289. return true;
  290. } // canView
  291. /**
  292. * Check if specific user can add new milestones to specific project
  293. *
  294. * @access public
  295. * @param User $user
  296. * @param Project $project
  297. * @return boolean
  298. */
  299. function canAdd(User $user, Project $project) {
  300. if ($user->getProjectPermission($project, PermissionManager::CAN_MANAGE_MILESTONES)) {
  301. return true;
  302. }
  303. if ($user->isAdministrator()) {
  304. return true;
  305. }
  306. return false;
  307. } // canAdd
  308. /**
  309. * Check if specific user can edit this milestone
  310. *
  311. * @access public
  312. * @param User $user
  313. * @return boolean
  314. */
  315. function canEdit(User $user) {
  316. if ($user->getProjectPermission($this->getProject(), PermissionManager::CAN_MANAGE_MILESTONES)) {
  317. return true;
  318. }
  319. if ($this->getCreatedById() == $user->getId()) {
  320. return true;
  321. }
  322. if ($user->isAdministrator()) {
  323. return true;
  324. }
  325. return false;
  326. } // canEdit
  327. /**
  328. * Can change status of this milestone (completed / open)
  329. *
  330. * @access public
  331. * @param User $user
  332. * @return boolean
  333. */
  334. function canChangeStatus(User $user) {
  335. if ($user->getProjectPermission($this->getProject(), PermissionManager::CAN_CHANGE_STATUS_MILESTONES)) {
  336. return true;
  337. }
  338. if ($this->getCreatedById() == $user->getId()) {
  339. return true;
  340. }
  341. if ($user->isAdministrator()) {
  342. return true;
  343. }
  344. // Additional check - is this milestone assigned to this user or its company
  345. if ($this->getAssignedTo() instanceof User) {
  346. if ($user->getId() == $this->getAssignedTo()->getObjectId()) {
  347. return true;
  348. }
  349. } elseif ($this->getAssignedTo() instanceof Company) {
  350. if ($user->getCompanyId() == $this->getAssignedTo()->getObjectId()) {
  351. return true;
  352. }
  353. } // if
  354. return false;
  355. } // canChangeStatus
  356. /**
  357. * Check if specific user can delete this milestone
  358. *
  359. * @access public
  360. * @param User $user
  361. * @return boolean
  362. */
  363. function canDelete(User $user) {
  364. return $this->canEdit($user);
  365. } // canDelete
  366. // ---------------------------------------------------
  367. // URL
  368. // ---------------------------------------------------
  369. function getViewUrl() {
  370. return get_url('milestone', 'view', array('id' => $this->getId(), 'active_project' => $this->getProjectId()));
  371. } // getViewUrl
  372. /**
  373. * Return edit milestone URL
  374. *
  375. * @access public
  376. * @param void
  377. * @return string
  378. */
  379. function getEditUrl() {
  380. return get_url('milestone', 'edit', array('id' => $this->getId(), 'active_project' => $this->getProjectId()));
  381. } // getEditUrl
  382. /**
  383. * Return delete milestone URL
  384. *
  385. * @access public
  386. * @param void
  387. * @return string
  388. */
  389. function getDeleteUrl() {
  390. return get_url('milestone', 'delete', array('id' => $this->getId(), 'active_project' => $this->getProjectId()));
  391. } // getDeleteUrl
  392. /**
  393. * Return complete milestone url
  394. *
  395. * @access public
  396. * @param void
  397. * @return string
  398. */
  399. function getCompleteUrl() {
  400. return get_url('milestone', 'complete', array('id' => $this->getId(), 'active_project' => $this->getProjectId()));
  401. } // getCompleteUrl
  402. /**
  403. * Return open milestone url
  404. *
  405. * @access public
  406. * @param void
  407. * @return string
  408. */
  409. function getOpenUrl() {
  410. return get_url('milestone', 'open', array('id' => $this->getId(), 'active_project' => $this->getProjectId()));
  411. } // getOpenUrl
  412. /**
  413. * Return add message URL
  414. *
  415. * @access public
  416. * @param void
  417. * @return string
  418. */
  419. function getAddMessageUrl() {
  420. return get_url('message', 'add', array('milestone_id' => $this->getId(), 'active_project' => $this->getProjectId()));
  421. } // getAddMessageUrl
  422. /**
  423. * Return add task list URL
  424. *
  425. * @access public
  426. * @param void
  427. * @return string
  428. */
  429. function getAddTaskListUrl() {
  430. return get_url('task', 'add_list', array('milestone_id' => $this->getId(), 'active_project' => $this->getProjectId()));
  431. } // getAddTaskListUrl
  432. /**
  433. * Return add ticket URL
  434. *
  435. * @access public
  436. * @param void
  437. * @return string
  438. */
  439. function getAddTicketUrl() {
  440. return get_url('ticket', 'add', array('milestone_id' => $this->getId(), 'active_project' => $this->getProjectId()));
  441. } // getAddTicketUrl
  442. // ---------------------------------------------------
  443. // System functions
  444. // ---------------------------------------------------
  445. /**
  446. * Validate before save
  447. *
  448. * @access public
  449. * @param array $errors
  450. * @return boolean
  451. */
  452. function validate(&$errors) {
  453. if (!$this->validatePresenceOf('name')) {
  454. $errors[] = lang('milestone name required');
  455. }
  456. if (!$this->validatePresenceOf('due_date')) {
  457. $errors[] = lang('milestone due date required');
  458. }
  459. } // validate
  460. /**
  461. * Delete this object and reset all relationship. This function will not delete any of related objec
  462. *
  463. * @access public
  464. * @param void
  465. * @return boolean
  466. */
  467. function delete() {
  468. try {
  469. DB::execute("UPDATE " . ProjectMessages::instance()->getTableName(true) . " SET `milestone_id` = '0' WHERE `milestone_id` = " . DB::escape($this->getId()));
  470. DB::execute("UPDATE " . ProjectTaskLists::instance()->getTableName(true) . " SET `milestone_id` = '0' WHERE `milestone_id` = " . DB::escape($this->getId()));
  471. return parent::delete();
  472. } catch(Exception $e) {
  473. throw $e;
  474. } // try
  475. } // delete
  476. // ---------------------------------------------------
  477. // ApplicationDataObject implementation
  478. // ---------------------------------------------------
  479. /**
  480. * Return object type name
  481. *
  482. * @param void
  483. * @return string
  484. */
  485. function getObjectTypeName() {
  486. return lang('milestone');
  487. } // getObjectTypeName
  488. /**
  489. * Return object URl
  490. *
  491. * @access public
  492. * @param void
  493. * @return string
  494. */
  495. function getObjectUrl() {
  496. return $this->getViewUrl();
  497. } // getObjectUrl
  498. /**
  499. * Returns a count of tickets in this milestone by state
  500. *
  501. * @access public
  502. * @param void
  503. * @return string
  504. */
  505. function hasTicketsByState($state) {
  506. if (!plugin_active('tickets')) return 0;
  507. if ($state == 'open') {
  508. $new = ProjectTickets::count('`milestone_id` = ' . DB::escape($this->getId()) . ' AND `state` = ' . DB::escape('new') . '');
  509. $open = ProjectTickets::count('`milestone_id` = ' . DB::escape($this->getId()) . ' AND `state` = ' . DB::escape('open') . '');
  510. return $new + $open;
  511. }
  512. else if ($state == 'in_progress') {
  513. return ProjectTickets::count('`milestone_id` = ' . DB::escape($this->getId()) . ' AND `state` = ' . DB::escape('pending') . '');
  514. }
  515. else if ($state == 'resolved') {
  516. return ProjectTickets::count('`milestone_id` = ' . DB::escape($this->getId()) . ' AND `state` = ' . DB::escape('closed') . '');
  517. }
  518. } // hasTicketsByState
  519. /**
  520. * Returns a total count of all tickets.
  521. *
  522. * @access public
  523. * @param void
  524. * @return string
  525. */
  526. function getTotalTicketCount() {
  527. if (!plugin_active('tickets')) return 0;
  528. return ProjectTickets::count('`milestone_id` = ' . DB::escape($this->getId()));
  529. } // getTotalTicketCount
  530. /**
  531. * Returns a percentage value of a certain ticket status.
  532. *
  533. * @access public
  534. * @param void
  535. * @return string
  536. */
  537. function getPercentageByTicketState($state) {
  538. return floor(($this->hasTicketsByState($state) / $this->getTotalTicketCount()) * 100);
  539. } // getPercentageByTicketState
  540. } // ProjectMilestone
  541. ?>