/**
  * Find the achievement that has to be reached by the user.
  *
  * <code>
  * $keys   = array(
  *    'user_id' => 1,
  *    'points_id' => 2
  * );
  * $points = new Gamification\User\Points\Points(\JFactory::getDbo());
  * $points->load($keys);
  *
  * $achievementSeeker = new Gamification\User\Achievement\AchievementPointsSeeker(\JFactory::getDbo());
  * $achievementSeeker->setUserPoints($points);
  *
  * $newAchievement = $achievementSeeker->find();
  * </code>
  *
  * @throws \RuntimeException
  *
  * @return null|BasicAchievement
  */
 public function find()
 {
     // Get basic achievements based on specific points.
     $options = array('points_id' => (int) $this->userPoints->getPointsId(), 'state' => (int) Constants::PUBLISHED);
     $achievements = new BasicAchievements($this->db);
     $achievements->load($options);
     $results = $achievements->toArray();
     /** @var array $results */
     $achievementData = array();
     for ($i = 0, $max = count($results); $i < $max; $i++) {
         // Get current item
         $current = array_key_exists($i, $results) ? $results[$i] : array();
         /** @var $current array */
         // Get next item
         $n = $i + 1;
         $next = array_key_exists($n, $results) ? $results[$n] : array();
         /** @var $next array */
         if (count($next) > 0) {
             // Check for coincidence with next item
             if ((int) $next['points_number'] === (int) $this->userPoints->getPointsNumber()) {
                 $achievementData = $next;
                 break;
             }
             // Check for coincidence with current item
             if ((int) $current['points_number'] <= (int) $this->userPoints->getPointsNumber() and (int) $next['points_number'] > (int) $this->userPoints->getPointsNumber()) {
                 $achievementData = $current;
                 break;
             }
         } else {
             // If there is not next item, we compare with last (current).
             if ((int) $current['points_number'] <= (int) $this->userPoints->getPointsNumber()) {
                 $achievementData = $current;
                 break;
             }
         }
     }
     // Create a achievement object.
     $achievement = null;
     if (count($achievementData) > 0) {
         $achievement = new BasicAchievement($this->db);
         $achievement->bind($achievementData);
     }
     return $achievement;
 }
 /**
  * Change user achievement to higher one.
  *
  * <code>
  * $context = "com_user.registration";
  *
  * $keys = array(
  *     "id" => 1,
  *     "group_id" => 2
  * );
  *
  * // Create user achievement object based.
  * $achievement  = new Gamification\Achievement\Achievement(\JFactory::getDbo());
  * $achievement->load($keys);
  *
  * $achievementManager = new Gamification\User\Achievement\AchievementManager(\JFactory::getDbo());
  * $achievementManager->setAchievement($achievement);
  *
  * if ($achievementManager->accomplish($context, $userId, $options)) {
  * // ...
  * }
  * </code>
  *
  * @param string $context
  * @param int $userId
  * @param array $options
  *
  * @throws \UnexpectedValueException
  * @throws \RuntimeException
  * @throws \InvalidArgumentException
  *
  * @return null|Achievement
  */
 public function accomplish($context, $userId, array $options = array())
 {
     if (!$this->achievement instanceof BasicAchievement) {
         throw new \UnexpectedValueException('It is missing user achievement object.');
     }
     // Check if this achievement already exists in user profile.
     $userProfile = new Profile($this->db);
     $achievementAccomplished = $userProfile->isAchievementAccomplished($this->achievement, $userId);
     if (!$achievementAccomplished) {
         $date = new \JDate();
         $data = array('user_id' => $userId, 'achievement_id' => $this->achievement->getId(), 'accomplished' => 1, 'accomplished_at' => $date->toSql());
         // Create user achievement.
         $userAchievement = new Achievement(\JFactory::getDbo());
         $userAchievement->bind($data);
         // Implement JObservableInterface: Pre-processing by observers
         $this->observers->update('onBeforeAccomplishAchievement', array($context, &$userAchievement, &$options));
         $userAchievement->store();
         // Implement JObservableInterface: Post-processing by observers
         $this->observers->update('onAfterAccomplishAchievement', array($context, &$userAchievement, &$options));
         return $userAchievement;
     }
     return null;
 }
 public function isAchievementAccomplished(Achievement $achievement, $userId = 0)
 {
     if (!$userId and $this->id > 0) {
         $userId = $this->id;
     }
     $query = $this->db->getQuery(true);
     $query->select('COUNT(*)')->from($this->db->quoteName('#__gfy_userachievements', 'a'))->where('a.achievement_id  = ' . (int) $achievement->getId())->where('a.user_id  = ' . (int) $userId);
     $this->db->setQuery($query, 0, 1);
     return (bool) $this->db->loadResult();
 }
 /**
  * Return the achievements as array with objects.
  *
  * <code>
  * $options = array(
  *     "ids" => array(1,2,3,4,5)
  * );
  *
  * $achievements   = new Gamification\Achievement\Achievements(\JFactory::getDbo());
  * $achievements->load($options);
  *
  * $achievements = $achievements->getAchievements();
  * </code>
  *
  * @return array
  */
 public function getAchievements()
 {
     $results = array();
     $i = 0;
     foreach ($this->items as $item) {
         $achievement = new Achievement($this->db);
         $achievement->bind($item);
         $results[$i] = $achievement;
         $i++;
     }
     return $results;
 }