* @license PHP License * @package WB */ /** * Load classes */ WBClass::load('WBDatasource_Newsletter'); /** * Wombat Newsletter System * * @version 1.5.0 * @package WB */ class WBDatasource_Newsletter_Subscriber extends WBDatasource_Newsletter { const OBSCURE_CODE_LENGTH = 4; const OBSCURE_FIELD_NAME = 'obscure'; /** * Current subscriber data * @var array */ private $sub = array(); /** * Current subscriber topics * @var array */ private $topic = array(); /** * Primary Key * @param string */ private $pSub = null; /** * Current User * @var WBUser */ private $user; /** * Receiver * @var WBDatasource_Newsletter_Receiver */ private $rcpt; /** * 2nd Constructor * * @param array */ protected function init($parameter = array()) { $this->pSub = $this->table->getIdentifier(WBDatasource_Newsletter::TABLE_SUBSCRIBER); } /** * Get Name Of Primary key * * @return string */ public function getIdentifier() { return $this->pSub; } /** * Inject User Object * * @param WBUser */ public function setUser($user) { $this->user = $user; } /** * Load Subscriber By E-Mail-Address * * Return subscriber's id on success, false otherwise * * @param string * @param string id of loaded subscriber or false */ public function loadByEmail($email) { // don't load twice if ($email == $this->sub['email']) { return $this->sub[$this->pSub]; } $this->sub = array(); $this->topic = array(); $email = trim($email); $email = explode('@', $email); if (2 != count($email)) { return ''; } $clause = array(); $clause[] = array( 'field' => 'emaillocal', 'value' => $email[0] ); $clause[] = array( 'field' => 'emaildomain', 'value' => $email[1] ); $list = $this->table->get(WBDatasource_Newsletter::TABLE_SUBSCRIBER, null, null, $clause); if (1 != count($list)) { return false; } return $this->loadByRaw($list[0]); } /** * Load Subscriber By Id * * Return subscriber's id on success, false otherwise * * @param string * @param string id of loaded subscriber or false */ public function loadById($id) { // don't load twice if ($id == $this->sub[$this->pSub]) { return $id; } $this->sub = array(); $this->topic = array(); $list = $this->table->get(WBDatasource_Newsletter::TABLE_SUBSCRIBER, $id); if (1 != count($list)) { return false; } return $this->loadByRaw($list[0]); } /** * Load Subscriber By User Id * * Return subscriber's id on success, false otherwise * * @param string $user * @return string */ public function loadByUser($uid = null) { // get user's id from parameter or user objsect if (empty($uid)) { if (empty($this->user)) { return false; } $uid = $this->user->getId(); if (empty($uid)) { return false; } } $clause = array(); $clause[] = array( 'field' => $this->table->getIdentifier('user'), 'value' => $uid ); $list = $this->table->get(WBDatasource_Newsletter::TABLE_SUBSCRIBER, null, null, $clause); if (1 != count($list)) { return false; } return $this->loadByRaw($list[0]); } /** * Load Subscriber By Obscure Id * * Use obscure id to load. Return subscriber's id on success, false otherwise * * @param string * @return string */ public function loadByObscureId($oid) { $o = substr($oid, 0, self::OBSCURE_CODE_LENGTH); $i = substr($oid, self::OBSCURE_CODE_LENGTH); if (!$this->loadById($i)) { return false; } if ($o == $this->sub[self::OBSCURE_FIELD_NAME]) { return $i; } $this->sub = array(); $this->topic = array(); return false; } /** * Load Subscriber By Raw Data * * Return subscriber's id on success, false otherwise * * @param array * @return string */ public function loadByRaw($data) { if (!isset($data[$this->pSub])) { return false; } $this->topic = array(); $this->sub = $data; $this->sub['obscureid'] = $this->sub[self::OBSCURE_FIELD_NAME] . $this->sub[$this->pSub]; return $this->sub[$this->pSub]; } /** * Was Subscriber Loaded Properly * * @return bool */ public function isOK() { if (empty($this->sub)) { return false; } return true; } private function getLanguage4Subscriber($sub) { $default = $this->config->get('subscriber/default/lang', 'en_GB'); if (empty($sub['lang'])) { $sub['lang'] = $default; } $available = $this->config->get('lang/available', array('en_GB')); if (!in_array($sub['lang'], $available)) { $sub['lang'] = $default; return $default; } return $sub['lang']; } private function getSalutation() { if (!$this->isOK()) { return ''; } if (empty($this->rcpt)) { $this->rcpt = WBClass::create('WBDatasource_Newsletter_Receiver'); } return $this->rcpt->getSalutation4SubscriberData($this->sub); } /** * Get Subscriber's Profile * * @param bool extend data * @return array */ public function get($extended = false) { $sub = $this->sub; $sub['newslettertopiclist'] = $this->getTopic(); if (!$extended) { return $sub; } $sub['salutation'] = $this->getSalutation(); return $sub; } /** * Get List of Subscriber's Topics * * Receive list of topic ids * @return array */ public function getTopic() { if (!$this->isOK()) { return array(); } if (!empty($this->topic)) { return $this->topic; } $this->topic = array(); $clause = array(); $clause[] = array( 'field' => $this->pSub, 'value' => $this->sub[$this->pSub] ); $list = $this->table->get(WBDatasource_Newsletter::TABLE_NEWSLETTERSUBSCRIBERTOPIC, null, null, $clause); $pTop = $this->table->getIdentifier(WBDatasource_Newsletter::TABLE_NEWSLETTERTOPIC); foreach ($list as $l) { $this->topic[] = $l[$pTop]; } return $this->topic; } /** * Set Subcriber's Topics * * @param array list of topics (ids) */ public function setTopic($list) { if (!$this->isOK()) { return; } // remove old topics $clause = array(); $clause[] = array( 'field' => $this->pSub, 'value' => $this->sub[$this->pSub] ); $this->table->delete(WBDatasource_Newsletter::TABLE_NEWSLETTERSUBSCRIBERTOPIC, null, null, $clause); // there are no topics if (empty($list)) { $this->topic = array(); return; } // save new topics $pTop = $this->table->getIdentifier(WBDatasource_Newsletter::TABLE_NEWSLETTERTOPIC); $save = array(); foreach ($list as $l) { $save[] = array( $this->pSub => $this->sub[$this->pSub], $pTop => $l ); } $this->table->save(WBDatasource_Newsletter::TABLE_NEWSLETTERSUBSCRIBERTOPIC, '__new', $save); $this->topic = $list; } /** * Get Subscriber's Id * * @return string */ public function getId() { if ($this->isOK()) { return $this->sub[$this->pSub]; } return ''; } /** * Get Subscriber's Obscure Id * * @return string */ public function getObscureId() { if ($this->isOK()) { return $this->sub['obscureid']; } return ''; } /** * Set Subscription Flag * * @param int 0 or 1 */ public function subscribe($sub = 1) { if (!$this->isOK()) { return false; } // normalize integer value $sub = intval($sub); $ts = 'subscribedtimestamp'; if (0 < $sub) { $sub = 1; } else { $ts = 'unsubscribedtimestamp'; $sub = 0; } if ($sub == $this->sub['subscribed']) { return true; } // update subscription $save = array( 'subscribed' => $sub, $ts => gmdate('Y-m-d H:i:s') ); // update internal buffer foreach ($save as $k => $v) { $this->sub[$k] = $v; } $this->table->save(WBDatasource_Newsletter::TABLE_SUBSCRIBER, $this->sub[$this->pSub], $save); WBEvent::trigger('newsletter:subscriber:subscription:' . $sub, 'Change newsletter subscriber subscription status', $this->sub); } /** * Remove Subscription Flag * */ public function unsubscribe() { $this->subscribe(0); } /** * Set Approved Flag * * Used for double opt in */ public function approve() { if (!$this->isOK()) { return false; } if (0 < $this->sub['approved']) { return; } // update flag $save = array( 'approved' => 1, 'approvedtimestamp' => gmdate('Y-m-d H:i:s') ); // update internal buffer foreach ($save as $k => $v) { $this->sub[$k] = $v; } $this->table->save(WBDatasource_Newsletter::TABLE_SUBSCRIBER, $this->sub[$this->pSub], $save); WBEvent::trigger('newsletter:subscriber:approved', 'Newsletter subscriber approved double-opt-in', $this->sub); } /** * Add or Update Subscriber in Database * * Return subscriber's id or false * * @todo find user by e-mail and merge with user table * @param array * @param string $eventSuffix * @return string */ public function add($data, $eventSuffix = 'default') { $this->sub = array(); if (empty($data['email'])) { if (empty($data['emailurlid'])) { return false; } // subscribe by emailurlid $dict = WBClass::create('WBDictionary_URL'); $dict->load($data['emailurlid']); $data['email'] = $dict->getWord(); } $email = explode('@', strtolower($data['email'])); $clause = array(); $clause[] = array( 'field' => 'emaillocal', 'value' => $email[0] ); $clause[] = array( 'field' => 'emaildomain', 'value' => $email[1] ); $old = $this->table->get(WBDatasource_Newsletter::TABLE_SUBSCRIBER, null, null, $clause); $save = array(); if (empty($old)) { $old = array(); $id = '__new'; $save = $this->config->get('subscriber/default', array()); $save[self::OBSCURE_FIELD_NAME] = $this->mkRandomCode(); $save['email'] = $data['email']; // add user data if ($this->user) { $data = array_merge($this->user->getData(), $data); $save[$this->table->getIdentifier('user')] = $this->user->getId(); } $save['lang'] = $this->getLanguage4Subscriber($save); } else { $old = $old[0]; $id = $this->loadByRaw($old); } $save['subscribedtimestamp'] = gmdate('Y-m-d H:i:s'); $this->mergeSavable($save, $data); if (empty($save)) { return $id; } $id = $this->table->save(WBDatasource_Newsletter::TABLE_SUBSCRIBER, $id, $save); $raw = array_merge($old, $save); $raw['id'] = $id; $raw[$this->pSub] = $id; $loaded = $this->loadByRaw($raw); WBClass::load('WBEvent'); WBEvent::trigger('newsletter:subscriber:added:' . $eventSuffix, 'Registered new newsletter subscriber', $this->sub); return $loaded; } /** * Add Source to Subscriber * * Store relation to other table for subscriber * * @param string $namespace * @param string $xid * @return bool true on success */ public function addSource($namespace, $xid) { if (!$this->isOK()) { return false; } // make sure namespace with same id exists only once $clause = array(); $clause[] = array( 'field' => $this->pSub, 'value' => $this->getId() ); $clause[] = array( 'field' => 'namespace', 'value' => $namespace ); $clause[] = array( 'field' => 'xid', 'value' => $xid ); $this->table->delete(WBDatasource_Newsletter::TABLE_SUBSCRIBERSOURCE, null, null, $clause); $rel = array( $this->pSub => $this->getId(), 'namespace' => $namespace, 'xid' => $xid ); $this->table->save(WBDatasource_Newsletter::TABLE_SUBSCRIBERSOURCE, '__new', $rel); return true; } /** * Update Subscriber's Profile * * If subscriber was imported, subscribedtimestamp may be still invalid. * If subcription status is subscribed, make subscribedtimestamp a valid date. * This verfifies subscription if someone changes her profile. * * @param array */ public function update($data) { if (!$this->isOK()) { return; } if (isset($data['newslettertopiclist'])) { $this->setTopic($data['newslettertopiclist']); } $save = array(); $this->mergeSavable($save, $data); // don't save empty data if (empty($save)) { return; } // set subscribed timestamp, if not set yet if (0 < $this->sub['subscribed'] && '1970-01-01 00:00:00' == $this->sub['subscribedtimestamp']) { $save['subscribedtimestamp'] = gmdate('Y-m-d H:i:s'); } // update internal buffer $this->table->save(WBDatasource_Newsletter::TABLE_SUBSCRIBER, $this->sub[$this->pSub], $save); $this->sub = array_merge($this->sub, $save); } /** * Merge Subscriber Data for Save * * Only save a predefined fields in newsletter subscriber table * * @param array $save * @param array $data to update */ private function mergeSavable(&$save, $data) { $keys = $this->config->get('subscriber/savable', array()); foreach ($keys as $k) { // select in data if (!isset($data[$k])) { continue; } // only changed data if (isset($this->sub[$k]) && $this->sub[$k] == $data[$k]) { continue; } $save[$k] = $data[$k]; } // two letter language code if (!empty($save['lang'])) { $save['lang'] = substr($save['lang'], 0, 2); } } /** * Generate Random String * * Make random string to be added as obscure code * @return string */ public function mkRandomCode() { $chars = range('a', 'z'); $last = count($chars) - 1; $rnd = ''; for ($i = 0; $i < self::OBSCURE_CODE_LENGTH; ++$i) { $rnd .= $chars[rand(0, $last)]; } return $rnd; } }