'newsletter/%s' ); $this->config = array_merge($config, $this->config); if (empty($this->config['tableenv'])) { $this->config['tableenv'] = self::TALBE_ENV_SUBSCRIBER; } $this->config['searchfields'] = array(); $this->config['usefilter'] = 1; $this->config['addcurrentuser'] = 'never'; switch ($this->config['tableenv']) { case self::TALBE_ENV_GENERICSOURCE: $this->config['table'] = WBDatasource_Newsletter::TABLE_NEWSLETTERGENERICSOURCE; $this->config['searchfields'] = array('title', 'brief'); $this->config['usefilter'] = 0; $this->config['translator'] = 'no'; break; case self::TALBE_ENV_TOPIC: $this->config['table'] = WBDatasource_Newsletter::TABLE_NEWSLETTERTOPIC; $this->config['searchfields'] = array('title', 'brief'); $this->config['usefilter'] = 0; // $this->config['translator'] = 'auto'; break; case self::TALBE_ENV_NEWSLETTERARTICLE: $this->config['table'] = WBDatasource_Newsletter::TABLE_NEWSLETTERARTICLE; $this->config['searchfields'] = array('title', 'brief'); $this->config['translator'] = 'no'; break; case self::TALBE_ENV_SUBSCRIBER: $this->config['table'] = WBDatasource_Newsletter::TABLE_SUBSCRIBER; $this->config['searchfields'] = array('forename', 'surname', 'company', 'position', 'note', 'emaillocal', 'emaildomain'); $this->config['translator'] = 'no'; break; default: case self::TALBE_ENV_NEWSLETTERISSUE: $this->config['table'] = WBDatasource_Newsletter::TABLE_NEWSLETTERISSUE; $this->config['searchfields'] = array('title', 'brief'); $this->config['translator'] = 'no'; break; } // tweak permissions if (!$this->isUserInGroup($this->config['requiredgroup'])) { $this->config['action'] = 'edit'; } // call parent's init return parent::init(); } /** * Run Component * * Display "normal" WBContent_TableEditor, call sub methods * * @return array */ public function run() { switch ($this->config['tableenv']) { case self::TALBE_ENV_SUBSCRIBER: return $this->runSubscriber(); break; case self::TALBE_ENV_NEWSLETTERISSUE: return $this->runNewsletterIssue(); break; } return parent::run(); } /** * Run Component: NewsletterIssue * * @return array */ private function runNewsletterIssue() { switch ($this->config['action']) { case 'display': case 'preview': case 'sendtest': break; default: return parent::run(); break; } $this->setupEnv(); $this->addConfigAsGlobalVars(); $this->initFilter(); $this->issue = WBClass::create('WBDatasource_Newsletter_Issue'); $this->issue->load($this->config['id']); $this->tmpl->addGlobalVars($this->issue->get()); WBParam::set('wb/cache/use', 0); if ('display' == $this->config['action']) { return $this->runNewsletterIssueDisplay(); } $this->nlMailer = WBClass::create('WBMail_Newsletter'); $this->nlMailer->setIssue($this->issue); $sub = $this->getDummySubscriberData($this->req->get('profile', 'use_email')); $sub['email'] = $this->req->get('email', $sub['email']); $this->nlMailer->setSubscriberData($sub); $this->nlMailer->prepare(); if ('sendtest' == $this->config['action']) { $this->runNewsletterIssueSendtest($sub); } return $this->runNewsletterIssuePreview(); } /** * Run Component: NewsletterIssue Send Test E-Mail * * @param array subscriber data with e-mail-address * @return array */ private function runNewsletterIssueSendtest($sub) { /** @var WBMailer */ $mail = WBClass::create('WBMailer'); $mail->setMimeMail($this->nlMailer->getMimeMail()); $this->tmpl->addGlobalVar('sendtest_rcpt', $sub['email']); $mail->addRcpt($sub['email']); $mail->send(); } /** * Run Component: NewsletterIssue Display * * @return array */ private function runNewsletterIssuePreview() { $this->loadTemplates('preview'); $this->tmpl->addGlobalVar('email_subject', $this->nlMailer->getSubject()); $this->tmpl->addGlobalVar('email_html', $this->nlMailer->getHtmlBody(true)); $this->tmpl->addGlobalVar('email_plain', $this->nlMailer->getPlainBody()); $body = $this->nlMailer->getHtmlBody(true); /* $header = array(); $body = $this->nlMailer->getMailBody($header); $this->tmpl->addGlobalVars($header, 'email_header_'); */ return $this->config; } /** * Get Subscriber Data By Profile * * Load dummy subscriber according to named profile * * @param string profile name * @return array */ private function getDummySubscriberData($profile) { $this->initSub(); if ('self' == $profile) { $this->sub->loadByUser($this->user->getId()); if ($this->sub->isOK()) { return $this->sub->get(true); } } if ('use_email' == $profile) { $uData = $this->user->getData(); $this->sub->loadByEmail($this->req->get('email', $uData['email'])); if ($this->sub->isOK()) { return $this->sub->get(true); } } else if (0 == strncmp('sub:', $profile, 4)) { $id = substr($profile, 4); $this->sub->loadById($id); if ($this->sub->isOK()) { return $this->sub->get(true); } } $sub = array( 'id' => '00000', 'obscure' => 'ENXY', 'emaillocal' => 'tommyatkins', 'emaildomain' => 'example.com', 'gender' => 'male', 'title' => '', 'forename' => 'Tommy', 'surname' => 'Atkins', 'lang' => 'en_GB', 'country' => 'en' ); $sub[$this->sub->getIdentifier()] = $sub['id']; switch ($profile) { case 'en_male': break; case 'en_female': $sub['obscure'] = 'ENXX'; $sub['gender'] = 'female'; $sub['emaillocal'] = 'aliceatkins'; $sub['forename'] = 'Alice'; $sub['surname'] = 'Violet'; break; case 'de_male': $sub['obscure'] = 'DEXY'; $sub['lang'] = 'de_DE'; $sub['country'] = 'de'; $sub['gender'] = 'male'; $sub['emaillocal'] = 'maxmustermann'; $sub['forename'] = 'Max'; $sub['surname'] = 'Mustermann'; break; case 'de_female': $sub['obscure'] = 'DEXX'; $sub['lang'] = 'de_DE'; $sub['country'] = 'de'; $sub['gender'] = 'female'; $sub['emaillocal'] = 'erikamusterfrau'; $sub['forename'] = 'Erika'; $sub['surname'] = 'Musterfrau'; break; default: break; } $sub['email'] = $sub['emaillocal'] . '@' . $sub['emaildomain']; $this->sub->loadByRaw($sub); return $this->sub->get(true); } /** * Run Component: NewsletterIssue Display * * @return array */ private function runNewsletterIssueDisplay() { $this->loadTemplates('display'); // tracking pixel $tpp = sprintf($this->config['trackingpixelpath'], $this->config['id']); $this->tmpl->addGlobalVar('trackingpixel_path', $tpp); $this->tmpl->addGlobalVar('trackingpixel_count', $this->issue->getTrackingPixelCount($tpp)); // URL count if ($this->tmpl->exists('page_list_entry')) { $list = array(); $pURL = $this->table->getIdentifier('url'); $tmp = $this->issue->get(); $date = $tmp['created']; if (!empty($tmp[$pURL])) { $list[] = array( $pURL => $tmp[$pURL] ); } $tmp = $this->issue->getArticle(); foreach ($tmp as $t) { if (empty($t[$pURL])) { continue; } $list[] = array( $pURL => $t[$pURL] ); } /** @var WBDictionary_URL */ $dict = WBClass::create('WBDictionary_URL'); foreach ($list as &$l) { $dict->load($l[$pURL]); $url = $dict->get(); $path = urldecode(substr($url['path'], 16)); $path = explode(' ', $path); $clause = array(); $clause[] = array( 'field' => 'created', 'relation' => 'ge', 'value' => $date ); $clause[] = array( 'field' => 'created', 'relation' => 'lt', 'value' => date('Y-m-d', strtotime($date) + 7 * 24 * 3600) ); $clause[] = array( 'field' => 'path', 'relation' => 'begins', 'value' => $path[0] ); $count = $this->table->count('pageview', null, null, $clause); $l['cnt'] = $count; $l['path'] = implode(' ', $path); } $this->tmpl->addGlobalVar('page_count', count($list)); $this->tmpl->addRows('page_list_entry', $list); } // link tracking if ($this->tmpl->exists('linktracking_list_entry')) { $list = $this->issue->getTracklink(); $this->tmpl->addGlobalVar('linktracking_count', count($list)); $this->tmpl->addRows('linktracking_list_entry', $list); } // most clicked pages if ($this->tmpl->exists('mostclicked_list_entry')) { $list = $this->issue->getMostClickedPages(); $this->tmpl->addGlobalVar('mostclicked_count', count($list)); $this->tmpl->addRows('mostclicked_list_entry', $list); } return $this->config; } /** * Run Component: Subscriber * * @return array */ private function runSubscriber() { $this->setupEnv(); $this->addConfigAsGlobalVars(); // $this->initFilter(); switch ($this->config['action']) { case 'setstatus': $this->updateStatus(); $this->config['action'] = 'list'; break; case 'export': $this->export(); $this->config['action'] = 'list'; break; case 'exportfiltered': $this->exportFiltered(); $this->config['action'] = 'list'; break; case 'import': $this->import(); $this->config['action'] = 'list'; break; } return parent::run(); } /** * Save Subscriber * * Actually use parent's method but add obscure code * * @param patForms $form * @param array $values */ public function onEditValid($form, $values) { switch ($this->config['tableenv']) { case self::TALBE_ENV_SUBSCRIBER: if ('__new' == $this->id) { $this->initSub(); $values[WBDatasource_Newsletter_Subscriber::OBSCURE_FIELD_NAME] = $this->sub->mkRandomCode(); } break; case self::TALBE_ENV_NEWSLETTERISSUE: break; } return parent::onEditValid($form, $values); } /** * Save Record * * Use parent's method to store record, but add optional source to subscriber * * @param string new * @param array $values * @return string $id */ protected function saveRecord($new, $values) { switch ($this->config['tableenv']) { case self::TALBE_ENV_SUBSCRIBER: break; case self::TALBE_ENV_NEWSLETTERISSUE: $this->injectTrackId4Issue($new, $values); return parent::saveRecord($new, $values); break; default: return parent::saveRecord($new, $values); break; } $e = $this->injectStatusTimestamp($values); $values['new'] = 0; $id = parent::saveRecord($new, $values); $xid = $this->req->get('genericsource-add', ''); if (empty($xid)) { return $id; } $this->initSub(); $this->sub->loadById($id); $this->sub->addSource('genericsource', $xid); return $id; } /** * Create TrackLink Id * * @param bool new * @param array newsletter issue values */ private function injectTrackId4Issue($new, &$values) { if (1 > $values['enabled']) { return; } $pTL = $this->table->getIdentifier(WBDatasource_Newsletter::TABLE_TRACKLINK); if (!empty($values[$pTL])) { return; } $save = array( 'title' => 'Newsletter ' . $values['title'], 'blurb' => $values['title'] ); $id = $this->table->save(WBDatasource_Newsletter::TABLE_TRACKLINK, '__new', $save); $values[$pTL] = $id; } /** * Set Status of Subscriber */ private function updateStatus() { if (self::TALBE_ENV_SUBSCRIBER != $this->config['tableenv']) { return; } $id = $this->req->get('id', ''); if (empty($id)) { return; } $status = $this->req->get('status', ''); if (empty($status)) { return; } $value = intval($this->req->get('value', -1)); if (0 > $value) { return; } if (0 < $value) { $value = 1; } $save = array( $status => $value ); $e = $this->injectStatusTimestamp($save); $this->table->save($this->config['table'], $id, $save); $eData = array( 'table' => $this->config['table'], 'id' => $id, 'new' => 0, 'save' => $save ); WBEvent::trigger('newsletter:manager:subscriber:status:' . $this->config['table'], 'Saved record in table', $eData); } /** * Add Status Changed Timestamps * * For a number of flags, add timestamp reccords * * @param array * @return string */ private function injectStatusTimestamp(&$save) { // get old record to see if something has changed $old = array(); if ('__new' != $this->id) { $old = $this->table->get($this->config['table'], $this->id); if (!empty($old)) { $old = $old[0]; } } // check for changes $event = ''; foreach ($save as $k => $v) { // check for changes if (isset($old[$k]) && $v == $old[$k]) { continue; } // add timestamp switch ($k) { case 'enabled': case 'checked': case 'approved': case 'blacklisted': if (0 < $v) { $save[$k . 'timestamp'] = gmdate('Y-m-d H:i:s'); $event = $k; } break; case 'subscribed': if (0 < $v) { $save['subscribedtimestamp'] = gmdate('Y-m-d H:i:s'); $event = 'subscribed'; } else { $save['unsubscribedtimestamp'] = gmdate('Y-m-d H:i:s'); $event = 'unsubscribed'; } default: break; } } return $event; } /** * Export Subscriber List According Filter * * Apply filter and export list * * */ private function exportFiltered() { if (self::TALBE_ENV_SUBSCRIBER != $this->config['tableenv']) { return; } $this->initFilter(); $prop = $this->exportPrepare(true); $prop->setSubject('Filtered newsletter subscriber'); $prop->setDescription('List of newsletter subscribers using filter'); $clause = $this->filter->getClause(); $options = $this->filter->getOptions(); $pager = $this->table->getPager('exportFiltered', $this->config['table'], null, $clause, $options); $this->exportPager($pager); } /** * Export Active Subcribers * * List only subscribers that are: * - checked * - approved * - enabled * - subscribed * - NOT blacklisted */ private function export() { if (self::TALBE_ENV_SUBSCRIBER != $this->config['tableenv']) { return; } $this->initFilter(); $prop = $this->exportPrepare(); $prop->setSubject('Current newsletter subscriber'); $prop->setDescription('List of active newsletter subscribers'); $clause = array(); $clause[] = array( 'field' => 'checked', 'value' => 1 ); $clause[] = array( 'field' => 'approved', 'value' => 1 ); $clause[] = array( 'field' => 'enabled', 'value' => 1 ); $clause[] = array( 'field' => 'subscribed', 'value' => 1 ); $clause[] = array( 'field' => 'blacklisted', 'value' => 0 ); $pager = $this->table->getPager('export', $this->config['table'], null, $clause); $this->exportPager($pager); } /** * Export All Items From Pager * * * @param WBDatasource_Pager */ private function exportPager($pager) { $info = $pager->browse(); for ($i = 0; $i < $info['pages']; ++$i) { $list = $pager->get(); $this->exportList($list); $pager->browse('__next'); } $this->fh->close(); $this->downloadFile($this->fh->realpath(), 'application/vnd.ms-excel', 'newsletterSubriber-' . gmdate('Ymd-His') . '.xls'); } /** * Prepare Spreadsheet * * Create file and mapping * * @return PhpOffice\PhpSpreadsheet\Document\Properties */ private function exportPrepare($withFlags = false) { $this->fh = WBClass::create('WBFile_Xls'); $this->fh->tempnam('subex'); $this->fh->open('w'); $prop = $this->fh->getProperties() ->setCreator('Wombat') ->setTitle('Newsletter Subscriber'); $this->fh->setActiveSheetIndex(0) ->setTitle('Abonnenten'); $map = array( //'company', //'__empty0', //'__empty1', //'country', 'lang', 'gender', 'salutation', 'title', 'forename', 'surname', 'email', 'obscureid' ); $pTop = $this->table->getIdentifier(WBDatasource_Newsletter::TABLE_NEWSLETTERTOPIC, true); $this->topicList = $this->table->get(WBDatasource_Newsletter::TABLE_NEWSLETTERTOPIC, null, null, null, array('limit' => 1000)); foreach ($this->topicList as $t) { $map[] = 'topic-' . $t[$pTop]; } if ($withFlags) { $map[] = 'approved'; $map[] = 'checked'; $map[] = 'enabled'; $map[] = 'subscribed'; $map[] = 'blacklisted'; } $map = array_flip($map); $this->fh->setMap($map); $data = array( //'company' => 'Name', //'__empty0' => 'Name-1', //'__empty1' => 'Name-2', //'country' => 'LKZ', 'lang' => 'Sprache', 'gender' => 'Geschlecht', 'salutation'=> 'Ansprache', 'title' => 'Titel', 'forename' => 'Vorname', 'surname' => 'Nachname', 'email' => 'E-Mail', 'obscureid' => 'ObscureId' ); foreach ($this->topicList as $t) { $data['topic-' . $t[$pTop]] = $t['title']; } if ($withFlags) { $data['approved'] = 'Double-Opt-In'; $data['checked'] = 'Geprüft'; $data['enabled'] = 'Freigegeben'; $data['subscribed'] = 'Abo'; $data['blacklisted'] = 'Blacklist'; } $this->fh->write($data); return $prop; } /** * Export List of Subscribers * * @param array $list */ private function exportList($list) { $pTop = $this->table->getIdentifier(WBDatasource_Newsletter::TABLE_NEWSLETTERTOPIC, true); $this->initSub(); foreach ($list as $l) { $this->sub->loadByRaw($l); $sub = $this->sub->get(true); foreach ($this->topicList as $t) { $sub['topic-' . $t[$pTop]] = 0; if (in_array($t[$pTop], $sub['newslettertopiclist'])) { $sub['topic-' . $t[$pTop]] = 1; } } $this->fh->write($sub); } } /** * Import Subscribers * * @todo not implemented, yet */ private function import() { } /** * Fetch List of Form Elements * * @param string name of the xml- and template-filename * @return array $elements */ protected function getFormElementList($name) { $list = parent::getFormElementList($name); // avoid duplicates if (isset($list['email'])) { $rule = array( 'name' => 'EmailDuplicate', 'params' => array( 'id' => '{NLSID}', 'table' => WBDatasource_Newsletter::TABLE_SUBSCRIBER ) ); if (!isset($list['email']['rule']) || !is_array($list['email']['rule'])) { $list['email']['rule'] = array(); } $list['email']['rule'][] = $rule; } return $list; } /** * location of form config * * Return sub directory where form element definitions are located * * @return string folder */ protected function getFormConfigDir() { return 'newsletter/manager/' . $this->config['tableenv']; } /** * Make Sure There is an Subscriber Object */ private function initSub() { if (empty($this->sub)) { $this->sub = WBClass::create('WBDatasource_Newsletter_Subscriber'); } } }