db->count(self::NOTIFICATIONS_TABLE, $conditions, $values); } /** * Get the list of unread notifications of a user * * @param int $userID The target user ID * @return array The list of notifications */ public function list_unread(int $userID) : array { //Perform a request on the server $conditions = "WHERE dest_user_id = ? AND seen = 0 ORDER BY id DESC"; $values = array($userID); //Perform the request $results = CS::get()->db->select(self::NOTIFICATIONS_TABLE, $conditions, $values); //Process the list of results $list = array(); foreach($results as $row) $list[] = $this->dbToNotification($row); //Return result return $list; } /** * Get the informations about a single notification * * @param int $notifID The target notification ID * @return Notification The target notification */ public function get_single(int $notifID) : Notification { //Perform database request $conditions = "WHERE id = ?"; $values = array($notifID); //Perform the request $result = CS::get()->db->select(self::NOTIFICATIONS_TABLE, $conditions, $values); //Check for error if(count($result) == 0) return new Notification(); //Return empty notification //Parse and return notification return $this->dbToNotification($result[0]); } /** * Push a new notification * * @param Notification $notification The notification to push * @return bool TRUE if the notification was pushed / FALSE else */ public function push(Notification $notification) : bool { //Check if the time of creation of the notification has to be set if(!$notification->has_time_create()) $notification->set_time_create(time()); //Determine the visibility level of the notification if($notification->get_on_elem_type() == Notification::POST){ //Fetch post information $info_post = components()->posts->get_single($notification->get_on_elem_id()); //Check for error if(!$info_post->isValid()) return false; //Update post informations if($info_post->get_kind_page() == Posts::PAGE_KIND_USER){ $notification->set_from_container_type(Notification::USER_PAGE); $notification->set_from_container_id($info_post->get_user_page_id()); } else if($info_post->get_kind_page() == Posts::PAGE_KIND_GROUP){ $notification->set_from_container_type(Notification::GROUP_PAGE); $notification->set_from_container_id($info_post->get_group_id()); } else throw new Exception("Unsupported page kind: ".$info_post->get_kind_page()); //Check if the notification is private or not //Private posts if($info_post->get_visibility_level() == Posts::VISIBILITY_USER){ //Push the notification only to the user, and only if it is not him if($notification->get_from_user_id() == $info_post->get_user_page_id()) return false; //Nothing to be done //Set the target user $notification->set_dest_user_id($info_post->get_user_page_id()); //Push the notification return $this->push_private($notification); } //For the posts on user pages else if($notification->get_from_container_type() == Notification::USER_PAGE) { //Get the list of friends of the user $friendslist = components()->friends->getList($notification->get_from_user_id()); //Generate the list of target users $target_users = array(); foreach($friendslist as $friend){ //Check if target user and page owner are friends if(!components()->friends->are_friend($friend->getFriendID(), $notification->get_from_container_id()) AND $friend->getFriendID() != $notification->get_from_container_id()) continue; //Check if the friend is following his friend if(!components()->friends->is_following($friend->getFriendID(), $notification->get_from_user_id())){ continue; } //Add the user to the list $target_users[] = $friend->getFriendID(); } //The notification can be publicy published return $this->push_public($notification, $target_users); } //For the posts on groups else if($notification->get_from_container_type() == Notification::GROUP_PAGE){ //Push to all the members of a group who follows it return $this->push_members_group($notification, $notification->get_from_container_id()); } //Unimplemented scenario else { throw new Exception("Notification scenarios not implemented!"); } } //Handles friendship request notifications else if($notification->get_on_elem_type() == Notification::FRIENDSHIP_REQUEST){ //Complete the notification $notification->set_from_container_id(0); $notification->set_from_container_type(""); //Push the notification in private way return $this->push_private($notification); } //Handles groups membership notifications else if($notification->get_on_elem_type() == Notification::GROUP_MEMBERSHIP){ //Complete the notification $notification->set_from_container_id(0); $notification->set_from_container_type(""); //Check whether the notification has to be pushed to a single user //or to all the moderators of the page if($notification->has_dest_user_id()) //Push the notification in private way (if it has a destination, //generally the target of the membership request) return $this->push_private($notification); else { //Push the notification to all the moderators of the group return $this->push_group_moderators($notification, $notification->get_on_elem_id()); } } //Unsupported element else { throw new Exception("The kind of notification ".$notification->get_on_elem_type()." is not currently supported !"); } } /** * Push a notification to all the members of a group following it * * @param Notification $notification The notification to push * @param int $groupID Target group ID * @return bool TRUE success / FALSE else */ private function push_members_group(Notification $notification, int $groupID) : bool { //Get the list of the members of the group that follows it $list = components()->groups->getListFollowers($groupID); //Process the list of followers $target_users = array(); foreach($list as $userID){ //If the current follower is the user creating the notification if($userID == $notification->get_from_user_id()) continue; $target_users[] = $userID; } //Push the notification return $this->push_public($notification, $target_users); } /** * Push a notification to all the moderators of a group * * @param Notification $notification The notification to push * @param int $groupID The ID of the target group * @return bool TRUE for a success / FALSE else */ private function push_group_moderators(Notification $notification, int $groupID) : bool { //Get the list of the moderators of the group $members = components()->groups->getListMembers($groupID); $moderators = array(); foreach($members as $member){ if($member->get_level() <= GroupMember::MODERATOR) $moderators[] = $member->get_userID(); } return $this->push_public($notification, $moderators); } /** * Push a notification to several users * * @param Notification $notification The notification to push * @param array $usersID The list of target users * @return bool FALSE for a failure */ private function push_public(Notification $notification, array $usersID) : bool { //Mark the notification as public $notification->set_event_visibility(Notification::EVENT_PUBLIC); //Process the list of userso foreach($usersID as $current_user){ //Set the current user id for the notification $notification->set_dest_user_id($current_user); //Check if a similar notification already exists or not if($this->similar_exists($notification)) continue; //A similar notification already exists //Create the notification $this->create($notification); } return true; } /** * Push a private notification * * Warning ! The target user for the notification must be already set !!! * * @param Notification $notification The notification to push * @return bool TRUE if the notification was created / FALSE else */ private function push_private(Notification $notification) : bool { //Mark the notification as private $notification->set_event_visibility(Notification::EVENT_PRIVATE); //Check if a similar notification already exists or not if($this->similar_exists($notification)) return false; //A similar notification already exists //Create the notification return $this->create($notification); } /** * Check if a notification similar to the given one exists or not * * @param Notification $notification The notification to compare * @return bool TRUE if a similar notification exists / FALSE else */ public function similar_exists(Notification $notification) : bool { //Prepare the request $tableName = self::NOTIFICATIONS_TABLE; $conditions = $this->noticationToDB($notification, false); //Make conditions $process_conditions = CS::get()->db->splitConditionsArray($conditions); $conditions = "WHERE ".$process_conditions[0]; $values = $process_conditions[1]; //Return the result return CS::get()->db->count($tableName, $conditions, $values) > 0; } /** * Create a notification * * @param Notification $notification The notification to create * @return bool TRUE for a success / FALSE else */ private function create(Notification $notification) : bool { //Generate notification datas $values = $this->noticationToDB($notification, TRUE); //Save the notification in the database return CS::get()->db->addLine(self::NOTIFICATIONS_TABLE, $values); } /** * Delete notifications * * @param Notification $notification The notification to delete * @return bool TRUE for a success / FALSE else */ public function delete(Notification $notification) : bool { //If the notification has an ID we delete a notification by its ID if($notification->has_id()){ //Delete a notification by its ID $conditions = "id = ?"; $values = array($notification->get_id()); } //Delete the notification else{ //Delete a specific notification $data = $this->noticationToDB($notification, FALSE); $array = CS::get()->db->splitConditionsArray($data); $conditions = $array[0]; $values = $array[1]; } //Delete the notification return CS::get()->db->deleteEntry(self::NOTIFICATIONS_TABLE, $conditions, $values); } /** * Delete all the notifications of a user * * @param int $userID The ID of the target user * @return bool TRUE for a success / FALSE for a failure */ public function delete_all_user(int $userID) : bool { //Perform the request $notif = new Notification(); $notif->set_dest_user_id($userID); return $this->delete($notif); } /** * Delete all the notifications related with a post * * @param int $postID The ID of the target post * @return bool TRUE for a success / FALSE else */ public function deleteAllRelatedWithPost(int $postID) : bool { $notification = new Notification(); $notification->set_on_elem_type(Notification::POST); $notification->set_on_elem_id($postID); return $this->delete($notification); } /** * Delete all the notifications related with a user * * @param int $userID The ID of the target user * @return bool TRUE for a success / FALSE else */ public function deleteAllRelatedWithUser(int $userID) : bool { //Delete all the notifications targeting the user if(!$this->delete_all_user($userID)) return FALSE; //Delete all the notifications created by the user $notif = new Notification(); $notif->set_from_user_id($userID); return $this->delete($notif); } /** * Delete all the notifications related with a group * * @param int $groupID The ID of the target group * @return bool TRUE for a success / FALSE else */ public function deleteAllRelatedWithGroup(int $groupID) : bool { //Groups membership notifications $notification = new Notification(); $notification->set_on_elem_type(Notification::GROUP_MEMBERSHIP); $notification->set_on_elem_id($groupID); if(!$this->delete($notification)) return FALSE; $notification->set_on_elem_type(Notification::GROUP_PAGE); if(!$this->delete($notification)) return FALSE; return TRUE; } /** * Convert a notification object into database array * * @param Notification $notification The notification to convert * @param bool $full_entry TRUE to process the entire notification, else only * the main informations will be processed * @return array The converted array */ private function noticationToDB(Notification $notification, bool $full_entry = TRUE) : array { $data = array(); if($notification->has_id()) $data['id'] = $notification->get_id(); if($notification->has_seen_state()) $data['seen'] = $notification->is_seen() ? 1 : 0; if($notification->has_from_user_id()) $data['from_user_id'] = $notification->get_from_user_id(); if($notification->has_dest_user_id()) $data['dest_user_id'] = $notification->get_dest_user_id(); if($notification->has_type()) $data['type'] = $notification->get_type(); if($notification->has_on_elem_id()) $data['on_elem_id'] = $notification->get_on_elem_id(); if($notification->has_on_elem_type()) $data['on_elem_type'] = $notification->get_on_elem_type(); //Specify complementary fields only if required if($full_entry){ $data['from_container_id'] = $notification->get_from_container_id(); $data['from_container_type'] = $notification->get_from_container_type(); $data['time_create'] = $notification->get_time_create(); $data['visibility'] = $notification->get_event_visibility(); } return $data; } /** * Convert a notification database entry into a Notification object * * @param array $row The database entry to process * @return Notification The generated notification */ private function dbToNotification(array $row) : Notification { $notif = new Notification(); //Parse database entry $notif->set_id($row['id']); $notif->set_seen($row['seen'] == 1); $notif->set_time_create($row['time_create']); $notif->set_from_user_id($row['from_user_id']); $notif->set_dest_user_id($row['dest_user_id']); $notif->set_on_elem_id($row['on_elem_id']); $notif->set_on_elem_type($row['on_elem_type']); $notif->set_type($row['type']); $notif->set_event_visibility($row['visibility']); $notif->set_from_container_id($row['from_container_id']); $notif->set_from_container_type($row['from_container_type']); return $notif; } } //Register component Components::register("notifications", new notificationComponent());