/app/model/class-ms-model-event.php

  1. <?php 
  2. /** 
  3. * @copyright Incsub (http://incsub.com/) 
  4. * 
  5. * @license http://opensource.org/licenses/GPL-2.0 GNU General Public License, version 2 (GPL-2.0) 
  6. * 
  7. * This program is free software; you can redistribute it and/or modify 
  8. * it under the terms of the GNU General Public License, version 2, as 
  9. * published by the Free Software Foundation. 
  10. * 
  11. * This program is distributed in the hope that it will be useful,  
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of 
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
  14. * GNU General Public License for more details. 
  15. * 
  16. * You should have received a copy of the GNU General Public License 
  17. * along with this program; if not, write to the Free Software 
  18. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,  
  19. * MA 02110-1301 USA 
  20. * 
  21. */ 
  22.  
  23. /** 
  24. * Event model. 
  25. * 
  26. * Persisted by parent class MS_Model_CustomPostType. 
  27. * 
  28. * @since 1.0.0 
  29. * 
  30. * @package Membership2 
  31. * @subpackage Model 
  32. */ 
  33. class MS_Model_Event extends MS_Model_CustomPostType { 
  34.  
  35. /** 
  36. * Model custom post type. 
  37. * 
  38. * Both static and class property are used to handle php 5.2 limitations. 
  39. * 
  40. * @since 1.0.0 
  41. * 
  42. * @var string 
  43. */ 
  44. protected static $POST_TYPE = 'ms_event'; 
  45.  
  46.  
  47. /** 
  48. * Event topic constants. 
  49. * 
  50. * @see $topic 
  51. * 
  52. * @since 1.0.0 
  53. * 
  54. * @var string 
  55. */ 
  56. const TOPIC_MEMBERSHIP = 'membership'; 
  57. const TOPIC_PAYMENT = 'payment'; 
  58. const TOPIC_USER = 'user'; 
  59. const TOPIC_WARNING = 'warning'; 
  60.  
  61. /** 
  62. * Event type constants. 
  63. * 
  64. * @since 1.0.0 
  65. * 
  66. * @var string 
  67. */ 
  68. const TYPE_UPDATED_INFO = 'updated_info'; 
  69. const TYPE_MS_SIGNED_UP = 'signed_up'; 
  70. const TYPE_MS_MOVED = 'moved'; 
  71. const TYPE_MS_EXPIRED = 'expired'; 
  72. const TYPE_MS_TRIAL_EXPIRED = 'trial_expired'; 
  73. const TYPE_MS_DROPPED = 'dropped'; 
  74. const TYPE_MS_RENEWED = 'renewed'; 
  75. const TYPE_MS_DEACTIVATED = 'deactivated'; 
  76. const TYPE_MS_CANCELED = 'canceled'; 
  77. const TYPE_MS_REGISTERED = 'registered'; 
  78. const TYPE_MS_BEFORE_FINISHES = 'before_finishes'; 
  79. const TYPE_MS_AFTER_FINISHES = 'after_finishes'; 
  80. const TYPE_MS_BEFORE_TRIAL_FINISHES = 'before_trial_finishes'; 
  81. const TYPE_MS_TRIAL_FINISHED = 'trial_finished'; 
  82. const TYPE_CREDIT_CARD_EXPIRE = 'credit_card_expire'; 
  83. const TYPE_PAID = 'paid'; 
  84. const TYPE_PAYMENT_FAILED = 'payment_failed'; 
  85. const TYPE_PAYMENT_PENDING = 'payment_pending'; 
  86. const TYPE_PAYMENT_DENIED = 'payment_denied'; 
  87. const TYPE_PAYMENT_BEFORE_DUE = 'payment_before_due'; 
  88. const TYPE_PAYMENT_AFTER_DUE = 'payment_after_made'; 
  89.  
  90. /** 
  91. * Event's membership ID. 
  92. * 
  93. * @since 1.0.0 
  94. * 
  95. * @var int 
  96. */ 
  97. protected $membership_id; 
  98.  
  99. /** 
  100. * Event's ms relationship ID. 
  101. * 
  102. * @since 1.0.0 
  103. * 
  104. * @var int 
  105. */ 
  106. protected $ms_relationship_id; 
  107.  
  108. /** 
  109. * Event topic. 
  110. * 
  111. * Events are grouped by topic. 
  112. * 
  113. * @since 1.0.0 
  114. * 
  115. * @var string 
  116. */ 
  117. protected $topic; 
  118.  
  119. /** 
  120. * Event type. 
  121. * 
  122. * @since 1.0.0 
  123. * 
  124. * @var string 
  125. */ 
  126. protected $type; 
  127.  
  128. /** 
  129. * Event date. 
  130. * 
  131. * @since 1.0.0 
  132. * 
  133. * @var string 
  134. */ 
  135. protected $date; 
  136.  
  137. /** 
  138. * Returns the post-type of the current object. 
  139. * 
  140. * @since 2.0.0 
  141. * @return string The post-type name. 
  142. */ 
  143. public static function get_post_type() { 
  144. return parent::_post_type( self::$POST_TYPE ); 
  145.  
  146. /** 
  147. * Get custom register post type args for this model. 
  148. * 
  149. * @since 1.0.0 
  150. */ 
  151. public static function get_register_post_type_args() { 
  152. $args = array( 
  153. 'label' => __( 'Membership2 Events', MS_TEXT_DOMAIN ),  
  154. ); 
  155.  
  156. return apply_filters( 
  157. 'ms_customposttype_register_args',  
  158. $args,  
  159. self::get_post_type() 
  160. ); 
  161.  
  162. /** 
  163. * Get Event types. 
  164. * 
  165. * @since 1.0.0 
  166. * 
  167. * @return array { 
  168. * array{ 
  169. * @type string $topic The topic name. 
  170. * @type string $desc The topic description. 
  171. * } 
  172. * } 
  173. */ 
  174. public static function get_event_types() { 
  175. $types = array( 
  176. /** 
  177. * User topic. 
  178. */ 
  179. self::TYPE_MS_REGISTERED => array( 
  180. 'topic' => self::TOPIC_USER,  
  181. 'desc' => __( 'Has registered.', MS_TEXT_DOMAIN ),  
  182. ),  
  183. self::TYPE_UPDATED_INFO => array( 
  184. 'topic' => self::TOPIC_USER,  
  185. 'desc' => __( 'Has updated billing information.', MS_TEXT_DOMAIN ),  
  186. ),  
  187. self::TYPE_CREDIT_CARD_EXPIRE => array( 
  188. 'topic' => self::TOPIC_USER,  
  189. 'desc' => __( "Member's credit card expire warning date.", MS_TEXT_DOMAIN ),  
  190. ),  
  191.  
  192. /** 
  193. * Membership topic. 
  194. */ 
  195. self::TYPE_MS_SIGNED_UP => array( 
  196. 'topic' => self::TOPIC_MEMBERSHIP,  
  197. 'desc' => __( 'Has signed up to membership %s.', MS_TEXT_DOMAIN ),  
  198. ),  
  199. self::TYPE_MS_MOVED => array( 
  200. 'topic' => self::TOPIC_MEMBERSHIP,  
  201. 'desc' => __( 'Has moved to membership %s.', MS_TEXT_DOMAIN ),  
  202. ),  
  203. self::TYPE_MS_EXPIRED => array( 
  204. 'topic' => self::TOPIC_MEMBERSHIP,  
  205. 'desc' => __( 'Membership %s has expired.', MS_TEXT_DOMAIN ),  
  206. ),  
  207. self::TYPE_MS_DROPPED => array( 
  208. 'topic' => self::TOPIC_MEMBERSHIP,  
  209. 'desc' => __( 'Membership %s dropped.', MS_TEXT_DOMAIN ),  
  210. ),  
  211. self::TYPE_MS_RENEWED => array( 
  212. 'topic' => self::TOPIC_MEMBERSHIP,  
  213. 'desc' => __( 'Membership %s renewed', MS_TEXT_DOMAIN ),  
  214. ),  
  215. self::TYPE_MS_DEACTIVATED => array( 
  216. 'topic' => self::TOPIC_MEMBERSHIP,  
  217. 'desc' => __( 'Membership %s deactivated', MS_TEXT_DOMAIN ),  
  218. ),  
  219. self::TYPE_MS_CANCELED => array( 
  220. 'topic' => self::TOPIC_MEMBERSHIP,  
  221. 'desc' => __( 'Membership %s cancelled.', MS_TEXT_DOMAIN ),  
  222. ),  
  223.  
  224. /** 
  225. * Warning topic. 
  226. */ 
  227. self::TYPE_MS_BEFORE_FINISHES => array( 
  228. 'topic' => self::TOPIC_WARNING,  
  229. 'desc' => __( 'Membership %s about to finish warning date.', MS_TEXT_DOMAIN ),  
  230. ),  
  231.  
  232. self::TYPE_MS_AFTER_FINISHES => array( 
  233. 'topic' => self::TOPIC_WARNING,  
  234. 'desc' => __( 'Membership %s finished warning date.', MS_TEXT_DOMAIN ),  
  235. ),  
  236. self::TYPE_MS_BEFORE_TRIAL_FINISHES => array( 
  237. 'topic' => self::TOPIC_WARNING,  
  238. 'desc' => __( 'Membership % s trial about to finish warning date.', MS_TEXT_DOMAIN ),  
  239. ),  
  240.  
  241. /** 
  242. * Payment topic. 
  243. */ 
  244. self::TYPE_PAID => array( 
  245. 'topic' => self::TOPIC_PAYMENT,  
  246. 'desc' => __( 'Invoice #%2$s for membership %1$s - Paid.', MS_TEXT_DOMAIN ),  
  247. ),  
  248. self::TYPE_PAYMENT_FAILED => array( 
  249. 'topic' => self::TOPIC_PAYMENT,  
  250. 'desc' => __( 'Invoice #%2$s for membership %1$s - Payment Failed.', MS_TEXT_DOMAIN ),  
  251. ),  
  252. self::TYPE_PAYMENT_PENDING => array( 
  253. 'topic' => self::TOPIC_PAYMENT,  
  254. 'desc' => __( 'Invoice #%2$s for membership %1$s - Payment Pending.', MS_TEXT_DOMAIN ),  
  255. ),  
  256. self::TYPE_PAYMENT_DENIED => array( 
  257. 'topic' => self::TOPIC_PAYMENT,  
  258. 'desc' => __( 'Invoice #%2$s for membership %1$s - Payment Denied.', MS_TEXT_DOMAIN ),  
  259. ),  
  260. self::TYPE_PAYMENT_BEFORE_DUE => array( 
  261. 'topic' => self::TOPIC_PAYMENT,  
  262. 'desc' => __( 'Invoice #%2$s before due date for membership %1$s warning.', MS_TEXT_DOMAIN ),  
  263. ),  
  264. self::TYPE_PAYMENT_AFTER_DUE => array( 
  265. 'topic' => self::TOPIC_PAYMENT,  
  266. 'desc' => __( 'Invoice #%2$s after due date for membership %1$s warning.', MS_TEXT_DOMAIN ),  
  267. ),  
  268. ); 
  269.  
  270. return apply_filters( 'ms_model_news_get_event_types', $types ); 
  271.  
  272. /** 
  273. * Get last event of specified type. 
  274. * 
  275. * @since 1.0.0 
  276. * 
  277. * @param MS_Model_Event The $event to search. 
  278. * @return null|MS_Model_Event The found event, or null. 
  279. */ 
  280. public static function get_last_event_of_type( $event ) { 
  281. $found = null; 
  282.  
  283. $args['posts_per_page'] = 1; 
  284. $args['meta_query']['type'] = array( 
  285. 'key' => 'type',  
  286. 'value' => $event->type,  
  287. ); 
  288. $args['meta_query']['user_id'] = array( 
  289. 'key' => 'user_id',  
  290. 'value' => $event->user_id,  
  291. ); 
  292.  
  293. if ( ! empty( $event->ms_relationship_id ) ) { 
  294. $args['meta_query']['ms_relationship_id'] = array( 
  295. 'key' => 'ms_relationship_id',  
  296. 'value' => $event->ms_relationship_id,  
  297. ); 
  298.  
  299. $events = self::get_events( apply_filters( 'ms_model_events_get_events_args', $args ) ); 
  300.  
  301. if ( ! empty( $events[0] ) ) { 
  302. $found = $events[0]; 
  303.  
  304. return apply_filters( 'ms_model_event_get_last_event_of_type', $found, $event ); 
  305.  
  306. /** 
  307. * Verify if is a valid event type 
  308. * 
  309. * @since 1.0.0 
  310. * 
  311. * @param string $type The event type to validate. 
  312. * @return boolean True if valid. 
  313. */ 
  314. public static function is_valid_type( $type ) { 
  315. $valid = array_key_exists( $type, self::get_event_types() ); 
  316.  
  317. return apply_filters( 'ms_model_event_is_valid_type', $valid, $type ); 
  318.  
  319. /** 
  320. * Get topic from event. 
  321. * 
  322. * @since 1.0.0 
  323. * 
  324. * @param string $type The event type. 
  325. * @return string the topic description. 
  326. */ 
  327. public static function get_topic( $type ) { 
  328. $topic = null; 
  329. $types = self::get_event_types(); 
  330.  
  331. if ( ! empty( $types[ $type ]['topic'] ) ) { 
  332. $topic = $types[ $type ]['topic']; 
  333.  
  334. return apply_filters( 'ms_model_event_get_topic', $topic, $type ); 
  335.  
  336. /** 
  337. * Get event description. 
  338. * 
  339. * @since 1.0.0 
  340. * 
  341. * @param string $type The event type. 
  342. * @return string the event description. 
  343. */ 
  344. public static function get_description( $type ) { 
  345. $desc = ''; 
  346.  
  347. $types = self::get_event_types(); 
  348. if ( ! empty( $types[ $type ]['desc'] ) ) { 
  349. $desc = $types[ $type ]['desc']; 
  350.  
  351. return apply_filters( 'ms_model_event_get_description', $desc, $type ); 
  352.  
  353. /** 
  354. * Get the total event count. 
  355. * For list table pagination. 
  356. * 
  357. * @since 1.0.0 
  358. * 
  359. * @param array $args The default query event args. 
  360. * @return int The total count. 
  361. */ 
  362. public static function get_event_count( $args = null ) { 
  363. MS_Factory::select_blog(); 
  364. $args = self::get_query_args( $args ); 
  365. $query = new WP_Query( $args ); 
  366. MS_Factory::revert_blog(); 
  367.  
  368. return apply_filters( 
  369. 'ms_model_event_get_event_count',  
  370. $query->found_posts,  
  371. $args 
  372. ); 
  373.  
  374. /** 
  375. * Get events. 
  376. * 
  377. * @since 1.0.0 
  378. * 
  379. * @param $args The query post args 
  380. * @see @link http://codex.wordpress.org/Class_Reference/WP_Query 
  381. * @return MS_Model_Event[] The events found. 
  382. */ 
  383. public static function get_events( $args = null ) { 
  384. MS_Factory::select_blog(); 
  385. $args = self::get_query_args( $args ); 
  386. $query = new WP_Query( $args ); 
  387. $items = $query->get_posts(); 
  388. $events = array(); 
  389. MS_Factory::revert_blog(); 
  390.  
  391. foreach ( $items as $item ) { 
  392. $events[] = MS_Factory::load( 'MS_Model_Event', $item ); 
  393.  
  394. return apply_filters( 'ms_model_event_get_events', $events, $args ); 
  395.  
  396. /** 
  397. * Get WP_Query object arguments. 
  398. * 
  399. * Default search arguments for this custom post_type. 
  400. * 
  401. * @since 1.0.0 
  402. * 
  403. * @param $args The query post args 
  404. * @see @link http://codex.wordpress.org/Class_Reference/WP_Query 
  405. * @return array $args The parsed args. 
  406. */ 
  407. public static function get_query_args( $args ) { 
  408. $defaults = array( 
  409. 'post_type' => self::get_post_type(),  
  410. 'posts_per_page' => 10,  
  411. 'fields' => 'ids',  
  412. 'post_status' => 'any',  
  413. 'order' => 'DESC',  
  414. ); 
  415.  
  416. if ( ! empty( $args['topic'] ) ) { 
  417. $args['meta_query']['topic'] = array( 
  418. 'key' => 'topic',  
  419. 'value' => $args['topic'],  
  420. ); 
  421. unset( $args['topic'] ); 
  422.  
  423. if ( ! empty( $args['membership_id'] ) ) { 
  424. $args['meta_query']['membership_id'] = array( 
  425. 'key' => 'membership_id',  
  426. 'value' => $args['membership_id'],  
  427. ); 
  428. unset( $args['membership_id'] ); 
  429.  
  430. if ( ! empty( $args['relationship_id'] ) ) { 
  431. $args['meta_query']['relationship_id'] = array( 
  432. 'key' => 'ms_relationship_id',  
  433. 'value' => $args['relationship_id'],  
  434. ); 
  435. unset( $args['membership_id'] ); 
  436.  
  437. $args = wp_parse_args( $args, $defaults ); 
  438.  
  439. return apply_filters( 'ms_model_event_get_query_args', $args ); 
  440.  
  441. /** 
  442. * Create and Save event. 
  443. * 
  444. * Default search arguments for this custom post_type. 
  445. * 
  446. * @since 1.0.0 
  447. * 
  448. * @param string $type The event type. 
  449. * @return mixed $data The additional data to create an event. 
  450. */ 
  451. public static function save_event( $type, $data ) { 
  452. $event = null; 
  453.  
  454. if ( self::is_valid_type( $type ) ) { 
  455. $event = MS_Factory::create( 'MS_Model_Event' ); 
  456. $event->type = $type; 
  457. $event->topic = self::get_topic( $type ); 
  458. $description = ''; 
  459.  
  460. switch ( $event->topic ) { 
  461. case self::TOPIC_PAYMENT: 
  462. case self::TOPIC_WARNING: 
  463. case self::TOPIC_MEMBERSHIP: 
  464. $subscription = $data; 
  465. if ( $subscription->id > 0 ) { 
  466. $membership = $subscription->get_membership(); 
  467. $member = MS_Factory::load( 
  468. 'MS_Model_Member',  
  469. $subscription->user_id 
  470. ); 
  471. $event->user_id = $subscription->user_id; 
  472. $event->membership_id = $subscription->membership_id; 
  473. $event->ms_relationship_id = $subscription->id; 
  474. $event->name = sprintf( 
  475. 'user: %s, membership: %s, type: %s',  
  476. $member->name,  
  477. $membership->name,  
  478. $type 
  479. ); 
  480.  
  481. if ( self::TOPIC_PAYMENT == $event->topic ) { 
  482. $invoice = $subscription->get_current_invoice( false ); 
  483. $description = sprintf( 
  484. self::get_description( $type ),  
  485. $membership->name,  
  486. $invoice->id 
  487. ); 
  488. } else { 
  489. $description = sprintf( 
  490. self::get_description( $type ),  
  491. $membership->name 
  492. ); 
  493. } else { 
  494. // The subscription has no ID. 
  495. // Possibly it was not saved yet... 
  496. break; 
  497.  
  498. case self::TOPIC_USER: 
  499. if ( $data instanceof MS_Model_Member ) { 
  500. $member = $data; 
  501. $event->user_id = $member->id; 
  502. $event->name = sprintf( 
  503. 'user: %s, type: %s',  
  504. $member->name,  
  505. $type 
  506. ); 
  507. } elseif ( $data instanceof MS_Model_Relationship ) { 
  508. $subscription = $data; 
  509. $membership = $subscription->get_membership(); 
  510. $member = MS_Factory::load( 
  511. 'MS_Model_Member',  
  512. $subscription->user_id 
  513. ); 
  514. $event->user_id = $subscription->user_id; 
  515. $event->membership_id = $subscription->membership_id; 
  516. $event->ms_relationship_id = $subscription->id; 
  517. $event->name = sprintf( 
  518. 'user: %s, membership: %s, type: %s',  
  519. $member->name,  
  520. $membership->name,  
  521. $type 
  522. ); 
  523. $description = self::get_description( $type ); 
  524. break; 
  525.  
  526. default: 
  527. MS_Helper_Debug::log( "Event topic not implemented: '$event->topic'" ); 
  528. break; 
  529.  
  530. $event->description = apply_filters( 'ms_model_event_description', $description, $type, $data ); 
  531. $event->date = MS_Helper_Period::current_date(); 
  532. $event = apply_filters( 'ms_model_news_record_user_signup_object', $event ); 
  533.  
  534. if ( ! self::is_duplicate( $event, $data ) ) { 
  535. $event->save(); 
  536.  
  537. // Hook to these actions to handle event notifications. e.g. auto communication. 
  538. do_action( "ms_model_event_$type", $event, $data ); 
  539. } else { 
  540. $event = null; 
  541.  
  542. return apply_filters( 
  543. 'ms_model_event_save_event',  
  544. $event,  
  545. $type,  
  546. $data 
  547. ); 
  548.  
  549.  
  550. /** 
  551. * Verify if a event was already created in the same day. 
  552. * 
  553. * @since 1.0.0 
  554. * 
  555. * @param MS_Model_Event $event The event to verify. 
  556. * @param mixed $data The additional data. 
  557. */ 
  558. public static function is_duplicate( $event, $data ) { 
  559. $is_duplicate = false; 
  560.  
  561. $check_events = apply_filters( 
  562. 'ms_model_event_is_duplicate_check_events',  
  563. array( 
  564. self::TYPE_MS_BEFORE_TRIAL_FINISHES,  
  565. self::TYPE_MS_BEFORE_FINISHES,  
  566. self::TYPE_MS_AFTER_FINISHES,  
  567. self::TYPE_CREDIT_CARD_EXPIRE,  
  568. self::TYPE_PAYMENT_BEFORE_DUE,  
  569. self::TYPE_PAYMENT_AFTER_DUE,  
  570. ); 
  571.  
  572. if ( in_array( $event->type, $check_events ) 
  573. && $last_event = self::get_last_event_of_type( $event ) 
  574. ) { 
  575. $event_date = gmdate( MS_Helper_Period::PERIOD_FORMAT, strtotime( $last_event->date ) ); 
  576. if ( $event_date === MS_Helper_Period::current_date() ) { 
  577. $is_duplicate = true; 
  578.  
  579. return apply_filters( 'ms_model_event_is_duplicate', $is_duplicate, $event, $data ); 
.