/** * Load the datagrid */ private function loadDataGrid() { // create a new source-object $source = new SpoonDataGridSourceDB(FrontendModel::getDB(), array(FrontendMailmotorModel::QRY_DATAGRID_BROWSE_SENT, array('sent', FRONTEND_LANGUAGE))); // create datagrid $this->dataGrid = new SpoonDataGrid($source); $this->dataGrid->setCompileDirectory(FRONTEND_CACHE_PATH . '/compiled_templates'); // set hidden columns $this->dataGrid->setColumnsHidden(array('id', 'status')); // set headers values $headers['name'] = SpoonFilter::ucfirst(FL::lbl('Name')); $headers['send_on'] = SpoonFilter::ucfirst(FL::lbl('Sent')); // set headers $this->dataGrid->setHeaderLabels($headers); // sorting columns $this->dataGrid->setSortingColumns(array('name', 'send_on'), 'name'); $this->dataGrid->setSortParameter('desc'); // set colum URLs $this->dataGrid->setColumnURL('name', FrontendNavigation::getURLForBlock('mailmotor', 'detail') . '/[id]'); // set column functions $this->dataGrid->setColumnFunction(array('SpoonDate', 'getTimeAgo'), array('[send_on]'), 'send_on', true); // add styles $this->dataGrid->setColumnAttributes('name', array('class' => 'title')); // set paging limit $this->dataGrid->setPagingLimit(self::MAILINGS_PAGING_LIMIT); }
/** * Load the data, don't forget to validate the incoming data */ private function getData() { // validate incoming parameters if ($this->URL->getParameter(1) === null) { $this->redirect(FrontendNavigation::getURL(404)); } // fetch record $this->record = FrontendTagsModel::get($this->URL->getParameter(1)); // validate record if (empty($this->record)) { $this->redirect(FrontendNavigation::getURL(404)); } // fetch modules $this->modules = FrontendTagsModel::getModulesForTag($this->record['id']); // loop modules foreach ($this->modules as $module) { // set module class $class = 'Frontend' . SpoonFilter::toCamelCase($module) . 'Model'; // get the ids of the items linked to the tag $otherIds = (array) FrontendModel::getDB()->getColumn('SELECT other_id FROM modules_tags WHERE module = ? AND tag_id = ?', array($module, $this->record['id'])); // set module class $class = 'Frontend' . SpoonFilter::toCamelCase($module) . 'Model'; // get the items that are linked to the tags $items = (array) FrontendTagsModel::callFromInterface($module, $class, 'getForTags', $otherIds); // add into results array if (!empty($items)) { $this->results[] = array('name' => $module, 'label' => FL::lbl(SpoonFilter::ucfirst($module)), 'items' => $items); } } }
/** * Get all items in a category * * @return array * @param int $categoryId The id of the category. */ public static function getQuestions($categoryId) { return (array) FrontendModel::getDB()->getRecords('SELECT i.* FROM faq_questions AS i WHERE i.category_id = ? AND i.language = ? AND i.hidden = ? ORDER BY i.sequence', array((int) $categoryId, FRONTEND_LANGUAGE, 'N')); }
/** * Build the language files * * @return void * @param string $language The language to build the locale-file for. * @param string $application The application to build the locale-file for. */ public static function buildCache($language, $application) { // get db $db = FrontendModel::getDB(); // get types $types = $db->getEnumValues('locale', 'type'); // get locale for backend $locale = (array) $db->getRecords('SELECT type, module, name, value FROM locale WHERE language = ? AND application = ? ORDER BY type ASC, name ASC, module ASC', array((string) $language, (string) $application)); // start generating PHP $value = '<?php' . "\n"; $value .= '/**' . "\n"; $value .= ' *' . "\n"; $value .= ' * This file is generated by Fork CMS, it contains' . "\n"; $value .= ' * more information about the locale. Do NOT edit.' . "\n"; $value .= ' * ' . "\n"; $value .= ' * @author Fork CMS' . "\n"; $value .= ' * @generated ' . date('Y-m-d H:i:s') . "\n"; $value .= ' */' . "\n"; $value .= "\n"; // loop types foreach ($types as $type) { // default module $modules = array('core'); // continue output $value .= "\n"; $value .= '// init var' . "\n"; $value .= '$' . $type . ' = array();' . "\n"; $value .= '$' . $type . '[\'core\'] = array();' . "\n"; // loop locale foreach ($locale as $i => $item) { // types match if ($item['type'] == $type) { // new module if (!in_array($item['module'], $modules)) { $value .= '$' . $type . '[\'' . $item['module'] . '\'] = array();' . "\n"; $modules[] = $item['module']; } // parse if ($application == 'backend') { $value .= '$' . $type . '[\'' . $item['module'] . '\'][\'' . $item['name'] . '\'] = \'' . str_replace('\\"', '"', addslashes($item['value'])) . '\';' . "\n"; } else { $value .= '$' . $type . '[\'' . $item['name'] . '\'] = \'' . str_replace('\\"', '"', addslashes($item['value'])) . '\';' . "\n"; } // unset unset($locale[$i]); } } } // close php $value .= "\n"; $value .= '?>'; // store SpoonFile::setContent(constant(mb_strtoupper($application) . '_CACHE_PATH') . '/locale/' . $language . '.php', $value); }
/** * Get related "things" based on tags */ private function getRelated() { // loop tags foreach ($this->tags as $tag) { // fetch entries $items = (array) FrontendModel::getDB()->getRecords('SELECT mt.module, mt.other_id FROM modules_tags AS mt INNER JOIN tags AS t ON t.id = mt.tag_id WHERE t.language = ? AND t.tag = ?', array(FRONTEND_LANGUAGE, $tag)); // loop items foreach ($items as $item) { // loop existing items foreach ($this->related as $related) { // already exists if ($item == $related) { continue 2; } } // add to list of related items $this->related[] = $item; } } // loop entries foreach ($this->related as $id => $entry) { // loop excluded records foreach ($this->exclude as $exclude) { // check if this entry should be excluded if ($entry['module'] == $exclude['module'] && $entry['other_id'] == $exclude['other_id']) { unset($this->related[$id]); continue 2; } } // set module class $class = 'Frontend' . SpoonFilter::toCamelCase($entry['module']) . 'Model'; // get module record $this->related[$id] = FrontendTagsModel::callFromInterface($entry['module'], $class, 'getForTags', (array) array($entry['other_id'])); if ($this->related[$id]) { $this->related[$id] = array_pop($this->related[$id]); } // remove empty items if (empty($this->related[$id])) { unset($this->related[$id]); } } // only show 3 $this->related = array_splice($this->related, 0, 3); }
/** * Parse the search results for this module * * Note: a module's search function should always: * - accept an array of entry id's * - return only the entries that are allowed to be displayed, with their array's index being the entry's id * * @return array * @param array $ids The ids of the found results. */ public static function search(array $ids) { // get db $db = FrontendModel::getDB(); // define ids's to ignore $ignore = array(404); // get items $items = (array) $db->getRecords('SELECT p.id, p.title, m.url, p.revision_id AS text FROM pages AS p INNER JOIN meta AS m ON p.meta_id = m.id INNER JOIN pages_templates AS t ON p.template_id = t.id WHERE p.id IN (' . implode(', ', $ids) . ') AND p.id NOT IN (' . implode(', ', $ignore) . ') AND p.status = ? AND p.hidden = ? AND p.language = ?', array('active', 'N', FRONTEND_LANGUAGE), 'id'); // prepare items for search foreach ($items as &$item) { $item['text'] = implode(' ', (array) $db->getColumn('SELECT pb.html FROM pages_blocks AS pb WHERE pb.revision_id = ? AND pb.status = ?', array($item['text'], 'active'))); $item['full_url'] = FrontendNavigation::getURL($item['id']); } // return return $items; }
/** * Increase the number of views for this item * * @param int $id * @param bool $useful * @param mixed[optional] $previousFeedback * @return array */ public static function updateFeedback($id, $useful, $previousFeedback = null) { // feedback hasn't changed so don't update the counters if ($previousFeedback !== null && $useful == $previousFeedback) { return; } $db = FrontendModel::getDB(true); // update counter with current feedback (increase) if ($useful) { $db->execute('UPDATE faq_questions SET num_usefull_yes = num_usefull_yes + 1 WHERE id = ?', array((int) $id)); } else { $db->execute('UPDATE faq_questions SET num_usefull_no = num_usefull_no + 1 WHERE id = ?', array((int) $id)); } // update counter with previous feedback (decrease) if ($previousFeedback) { $db->execute('UPDATE faq_questions SET num_usefull_yes = num_usefull_yes - 1 WHERE id = ?', array((int) $id)); } elseif ($previousFeedback !== null) { $db->execute('UPDATE faq_questions SET num_usefull_no = num_usefull_no - 1 WHERE id = ?', array((int) $id)); } }
/** * Get all related items * * @param int $id The id of the item in the source-module. * @param int $module The source module. * @param int $otherModule The module wherein the related items should appear. * @param int[optional] $limit The maximum of related items to grab. * @return array */ public static function getRelatedItemsByTags($id, $module, $otherModule, $limit = 5) { return (array) FrontendModel::getDB()->getColumn('SELECT t2.other_id FROM modules_tags AS t INNER JOIN modules_tags AS t2 ON t.tag_id = t2.tag_id WHERE t.other_id = ? AND t.module = ? AND t2.module = ? AND (t2.module != t.module OR t2.other_id != t.other_id) GROUP BY t2.other_id ORDER BY COUNT(t2.tag_id) DESC LIMIT ?', array((int) $id, (string) $module, (string) $otherModule, (int) $limit)); }
/** * Get an item. * * @param string $id The id of the item to fetch. * @return array */ public static function get($id) { return (array) FrontendModel::getDB()->getRecord('SELECT i.* FROM content_blocks AS i WHERE i.id = ? AND i.status = ? AND i.hidden = ? AND i.language = ?', array((int) $id, 'active', 'N', FRONTEND_LANGUAGE)); }
/** * Logout a profile. * * @return void */ public static function logout() { // delete session records FrontendModel::getDB(true)->delete('profiles_sessions', 'session_id = ?', array(SpoonSession::getSessionId())); // set is_logged_in to false SpoonSession::set('frontend_profile_logged_in', false); // delete cookie SpoonCookie::delete('frontend_profile_secret_key'); }
/** * Load a user profile by id. * * @return void * @param int $id Profile id to load. */ private function loadProfile($id) { // get profile data $profileData = (array) FrontendModel::getDB()->getRecord('SELECT p.id, p.email, p.status, p.display_name, UNIX_TIMESTAMP(p.registered_on) AS registered_on FROM profiles AS p WHERE p.id = ?', (int) $id); // set properties $this->setId($profileData['id']); $this->setEmail($profileData['email']); $this->setStatus($profileData['status']); $this->setDisplayName($profileData['display_name']); $this->setRegisteredOn($profileData['registered_on']); // get the groups (only the ones we still have access to) $this->groups = (array) FrontendModel::getDB()->getPairs('SELECT pg.id, pg.name FROM profiles_groups AS pg INNER JOIN profiles_groups_rights AS pgr ON pg.id = pgr.group_id WHERE pgr.profile_id = :id AND (pgr.expires_on IS NULL OR pgr.expires_on >= NOW())', array(':id' => (int) $id)); }
/** * Unsubscribes an e-mail address from CampaignMonitor and our database * * @param string $email The e-mail address to unsubscribe. * @param string[optional] $groupId The id of the group to unsubscribe from. * @return bool */ public static function unsubscribe($email, $groupId = null) { // get objects $db = FrontendModel::getDB(true); $cm = self::getCM(); // set group ID $groupId = !empty($groupId) ? $groupId : FrontendMailmotorModel::getDefaultGroupID(); // get group CM ID $groupCMId = self::getCampaignMonitorID('list', $groupId); // group exists if (FrontendMailmotorModel::existsGroup($groupId)) { try { // unsubscribe the email from this group $cm->unsubscribe($email, $groupCMId); } catch (Exception $e) { // stop here if something went wrong with CM return false; } // set variables $subscriber['status'] = 'unsubscribed'; $subscriber['unsubscribed_on'] = FrontendModel::getUTCDate('Y-m-d H:i:s'); // unsubscribe the user $db->update('mailmotor_addresses_groups', $subscriber, 'email = ? AND group_id = ?', array($email, $groupId)); // user unsubscribed return true; } // user not unsubscribed return false; }
/** * Insert data fields. * * @param array $data The data to insert. * @return int */ public static function insertDataField(array $data) { return FrontendModel::getDB(true)->insert('forms_data_fields', $data); }
/** * Load the data for the given user * * @return void * @param int $userId The users id in the backend. */ public function loadUser($userId) { // redefine $userId = (int) $userId; // get database instance $db = FrontendModel::getDB(); // get user-data $userData = (array) $db->getRecord('SELECT u.id, u.email FROM users AS u WHERE u.id = ? LIMIT 1', array($userId)); // if there is no data we have to destroy this object, I know this isn't a realistic situation if (empty($userData)) { throw new FrontendException('The user (' . $userId . ') doesn\'t exist.'); } // set properties $this->setUserId($userData['id']); $this->setEmail($userData['email']); // get settings $settings = (array) $db->getPairs('SELECT us.name, us.value FROM users_settings AS us WHERE us.user_id = ?', array($userId)); // loop settings and store them in the object foreach ($settings as $key => $value) { $this->settings[$key] = unserialize($value); } }
/** * Get all items * * @return array */ public static function getAll() { return (array) FrontendModel::getDB()->getRecords('SELECT * FROM location WHERE language = ?', array(FRONTEND_LANGUAGE)); }
/** * Push a notification to Microsoft's notifications-server * * @param string $title The title for the tile to send. * @param string[optional] $count The count for the tile to send. * @param string[optional] $image The image for the tile to send. * @param string[optional] $backTitle The title for the tile backtround to send. * @param string[optional] $backText The text for the tile background to send. * @param string[optional] $backImage The image for the tile background to send. * @param string[optional] $tile The secondary tile to update. * @param string[optional] $uri The application uri to navigate to. */ public static function pushToMicrosoftApp($title, $count = null, $image = null, $backTitle = null, $backText = null, $backImage = null, $tile = null, $uri = null) { // get ForkAPI-keys $publicKey = FrontendModel::getModuleSetting('core', 'fork_api_public_key', ''); $privateKey = FrontendModel::getModuleSetting('core', 'fork_api_private_key', ''); // no keys, so stop here if ($publicKey == '' || $privateKey == '') { return; } // get all microsoft channel uri's $channelUris = (array) FrontendModel::getDB()->getColumn('SELECT s.value FROM users AS i INNER JOIN users_settings AS s WHERE i.active = ? AND i.deleted = ? AND s.name = ? AND s.value != ?', array('Y', 'N', 'microsoft_channel_uri', 'N;')); // no devices, so stop here if (empty($channelUris)) { return; } // init var $uris = array(); // loop devices foreach ($channelUris as $row) { // unserialize $row = unserialize($row); // loop and add foreach ($row as $item) { $uris[] = $item; } } // no channel uri's, so stop here if (empty($uris)) { return; } // require the class require_once PATH_LIBRARY . '/external/fork_api.php'; // create instance $forkAPI = new ForkAPI($publicKey, $privateKey); try { // push $forkAPI->microsoftPush($uris, $title, $count, $image, $backTitle, $backText, $backImage, $tile, $uri); } catch (Exception $e) { if (SPOON_DEBUG) { throw $e; } } }
/** * Update a profile. * * @param int $id The profile id. * @param array $values The values to update. * @return int */ public static function update($id, array $values) { return (int) FrontendModel::getDB(true)->update('profiles', $values, 'id = ?', (int) $id); }
/** * Send an email * * @return void * @param int $id The id of the mail to send. */ public static function send($id) { // redefine $id = (int) $id; // get db $db = FrontendModel::getDB(true); // get record $emailRecord = (array) $db->getRecord('SELECT * FROM emails AS e WHERE e.id = ?', array($id)); // mailer type $mailerType = FrontendModel::getModuleSetting('core', 'mailer_type', 'mail'); // create new SpoonEmail-instance $email = new SpoonEmail(); $email->setTemplateCompileDirectory(FRONTEND_CACHE_PATH . '/compiled_templates'); // send via SMTP if ($mailerType == 'smtp') { // get settings $SMTPServer = FrontendModel::getModuleSetting('core', 'smtp_server'); $SMTPPort = FrontendModel::getModuleSetting('core', 'smtp_port', 25); $SMTPUsername = FrontendModel::getModuleSetting('core', 'smtp_username'); $SMTPPassword = FrontendModel::getModuleSetting('core', 'smtp_password'); // set server and connect with SMTP $email->setSMTPConnection($SMTPServer, $SMTPPort, 10); // set authentication if needed if ($SMTPUsername !== null && $SMTPPassword !== null) { $email->setSMTPAuth($SMTPUsername, $SMTPPassword); } } // set some properties $email->setFrom($emailRecord['from_email'], $emailRecord['from_name']); $email->addRecipient($emailRecord['to_email'], $emailRecord['to_name']); $email->setReplyTo($emailRecord['reply_to_email']); $email->setSubject($emailRecord['subject']); $email->setHTMLContent($emailRecord['html']); $email->setCharset(SPOON_CHARSET); $email->setContentTransferEncoding('base64'); if ($emailRecord['plain_text'] != '') { $email->setPlainContent($emailRecord['plain_text']); } // attachments added if (isset($emailRecord['attachments']) && $emailRecord['attachments'] !== null) { // unserialize $attachments = (array) unserialize($emailRecord['attachments']); // add attachments to email foreach ($attachments as $attachment) { $email->addAttachment($attachment); } } // send the email if ($email->send()) { // remove the email $db->delete('emails', 'id = ?', array($id)); // trigger event FrontendModel::triggerEvent('core', 'after_email_sent', array('id' => $id)); } }
/** * Fetch all the settings for a specific map * * @param int $mapId * @return array */ public static function getMapSettings($mapId) { $mapSettings = (array) FrontendModel::getDB()->getPairs('SELECT s.name, s.value FROM location_settings AS s WHERE s.map_id = ?', array((int) $mapId)); foreach ($mapSettings as $key => $value) { $mapSettings[$key] = unserialize($value); } return $mapSettings; }
/** * Validate searches: check everything that has been marked as 'inactive', if should still be inactive */ public static function validateSearch() { // we'll iterate through the inactive search indices in little batches $offset = 0; $limit = 50; while (1) { // get the inactive indices $searchResults = (array) FrontendModel::getDB()->getRecords('SELECT module, other_id FROM search_index WHERE language = ? AND active = ? GROUP BY module, other_id LIMIT ?, ?', array(FRONTEND_LANGUAGE, 'N', $offset, $limit)); // none found? good news! if (!$searchResults) { return; } // prepare to send to modules $moduleResults = array(); // loop the resultset foreach ($searchResults as $searchResult) { $moduleResults[$searchResult['module']][] = $searchResult['other_id']; } // pass the results to the modules foreach ($moduleResults as $module => $otherIds) { // check if this module actually is prepared to handle searches (well it should, because else there shouldn't be any search indices) if (is_callable(array('Frontend' . SpoonFilter::ucfirst($module) . 'Model', 'search'))) { $moduleResults[$module] = call_user_func(array('Frontend' . SpoonFilter::ucfirst($module) . 'Model', 'search'), $otherIds); // update the ones that are allowed to be searched through self::statusIndex($module, array_keys($moduleResults[$module]), true); } } // didn't even get the amount of result we asked for? no need to ask again! if (count($searchResults) < $offset) { return; } $offset += $limit; } }
/** * Unsubscribes an e-mail address * * @param string $email The mail address to unsubscribe. * @param string[optional] $groupId The id of the group to unsubscribe from. * @return bool */ public static function unsubscribe($email, $groupId = null) { // get objects $db = FrontendModel::getDB(true); // set groupID $groupId = !empty($groupId) ? $groupId : self::getDefaultGroupID(); // unsubscribe the user in CM if (self::existsGroup($groupId)) { // set variables $subscriber['status'] = 'unsubscribed'; $subscriber['unsubscribed_on'] = FrontendModel::getUTCDate('Y-m-d H:i:s'); // unsubscribe the user $db->update('mailmotor_addresses_groups', $subscriber, 'email = ? AND group_id = ?', array($email, $groupId)); // user unsubscribed return true; } // user not unsubscribed return false; }
/** * Parse the search results for this module * * Note: a module's search function should always: * - accept an array of entry id's * - return only the entries that are allowed to be displayed, with their array's index being the entry's id * * * @return array * @param array $ids The ids of the found results. */ public static function search(array $ids) { // get items $items = (array) FrontendModel::getDB()->getRecords('SELECT i.id, i.title, i.introduction, i.text, m.url FROM blog_posts AS i INNER JOIN meta AS m ON i.meta_id = m.id WHERE i.status = ? AND i.hidden = ? AND i.language = ? AND i.publish_on <= ? AND i.id IN (' . implode(',', $ids) . ')', array('active', 'N', FRONTEND_LANGUAGE, date('Y-m-d H:i') . ':00'), 'id'); // prepare items for search foreach ($items as &$item) { $item['full_url'] = FrontendNavigation::getURLForBlock('blog', 'detail') . '/' . $item['url']; } // return return $items; }
/** * Push a notification to Apple's notifications-server * * @return void * @param mixed $alert The message/dictonary to send. * @param int[optional] $badge The number for the badge. * @param string[optional] $sound The sound that should be played. * @param array[optional] $extraDictionaries Extra dictionaries. */ public static function pushToAppleApp($alert, $badge = null, $sound = null, array $extraDictionaries = null) { // get ForkAPI-keys $publicKey = FrontendModel::getModuleSetting('core', 'fork_api_public_key', ''); $privateKey = FrontendModel::getModuleSetting('core', 'fork_api_private_key', ''); // validate keys if ($publicKey != '' && $privateKey != '') { // get all apple-device tokens $deviceTokens = (array) FrontendModel::getDB()->getColumn('SELECT s.value FROM users AS i INNER JOIN users_settings AS s WHERE i.active = ? AND i.deleted = ? AND s.name = ? AND s.value != ?', array('Y', 'N', 'apple_device_token', 'N;')); // any devices? if (!empty($deviceTokens)) { // init var $tokens = array(); // loop devices foreach ($deviceTokens as $row) { // unserialize $row = unserialize($row); // loop and add foreach ($row as $item) { $tokens[] = $item; } } // any tokens? if (!empty($tokens)) { // require the class require_once PATH_LIBRARY . '/external/fork_api.php'; // create instance $forkAPI = new ForkAPI($publicKey, $privateKey); try { // push $response = $forkAPI->applePush($tokens, $alert, $badge, $sound, $extraDictionaries); if (!empty($response)) { // get db $db = FrontendModel::getDB(true); // loop the failed keys and remove them foreach ($response as $deviceToken) { // get setting wherin the token is available $row = $db->getRecord('SELECT i.* FROM users_settings AS i WHERE i.name = ? AND i.value LIKE ?', array('apple_device_token', '%' . $deviceToken . '%')); // any rows? if (!empty($row)) { // reset data $data = unserialize($row['value']); // loop keys foreach ($data as $key => $token) { // match and unset if needed. if ($token == $deviceToken) { unset($data[$key]); } } // no more tokens left? if (empty($data)) { $db->delete('users_settings', 'user_id = ? AND name = ?', array($row['user_id'], $row['name'])); } else { $db->update('users_settings', array('value' => serialize($data)), 'user_id = ? AND name = ?', array($row['user_id'], $row['name'])); } } } } } catch (Exception $e) { if (SPOON_DEBUG) { throw $e; } } } } } }