v7‰PNG  IHDR Ÿ f Õ†C1 sRGB ®Îé gAMA ± üa pHYs à ÃÇo¨d GIDATx^íÜL”÷ð÷Yçªö("Bh_ò«®¸¢§q5kÖ*:þ0A­ºšÖ¥]VkJ¢M»¶f¸±8\k2íll£1]q®ÙÔ‚ÆT PK7\O""*Query/User/Condition/AffWithCommission.phpnu[title = ___('Has Affiliate Commission'); $this->op = array( 'any' => ___('Any'), 'paid' => ___('Paid (Included to Payout)'), 'not-paid' => ___('Not Paid') ); } public function setFromRequest(array $input) { $this->type = @$input[$this->getId()]['type']; if ($this->type) return true; } public function getId() { return 'aff-with-comm'; } public function renderElement(HTML_QuickForm2_Container $form) { $form->options[___('Misc')][$this->getId()] = $this->title; $g = $form->addGroup($this->getId()) ->setLabel($this->title) ->setAttribute('id', $this->getId()) ->setAttribute('class', 'searchField empty'); $g->addSelect('type') ->loadOptions($this->op); } public function isEmpty() { return !$this->type; } public function getDescription() { return ___('Has %s Affiliate Commission', $this->op[$this->type]); } function _getWhere(Am_Query $db) { $a = $db->getAlias(); switch ($this->type) { case 'any': $c = ''; break; case 'paid' : $c = 'AND payout_detail_id IS NOT NULL'; break; case 'not-paid' : $c = 'AND payout_detail_id IS NULL'; break; } return "EXISTS (SELECT * FROM ?_aff_commission WHERE aff_id=$a.user_id $c)"; } }PK7\#vMM"Form/Element/AffCommissionSize.phpnu[addElement('text', $data.'_c', array('size' => 5, )); $this->addStatic()->setContent(' '); $sel = $this->addElement('select', $data.'_t', array('size' => 1,), array('options' => array( '%' => '%', '$' => Am_Currency::getDefault(), ) )); } }PK7\7G$__Form/Signup/Aff.phpnu[ $b) { if (($b instanceof Am_Form_Brick_Product) || ($b instanceof Am_Form_Brick_Paysystem) || ($b instanceof Am_Form_Brick_Coupon)) unset($bricks[$k]); } return $bricks; } public function getDefaultBricks() { return array( new Am_Form_Brick_Name, new Am_Form_Brick_Email, new Am_Form_Brick_Login, new Am_Form_Brick_Password, new Am_Form_Brick_Address, new Am_Form_Brick_Agreement, new Am_Form_Brick_Payout ); } public function isHideBricks() { return true; } }PK7\TTForm/Brick.phpnu[values if ($this->labels && is_int(key($this->labels))) { $ll = array_values($this->labels); $this->labels = array_combine($ll, $ll); } if ($id !== null) $this->setId($id); if ($config !== null) $this->setConfigArray($config); if ($this->hideIfLoggedInPossible() == self::HIDE_ALWAYS) $this->hideIfLoggedIn = true; // format labels } /** * this function can be used to bind some special processing * to hooks */ public function init() { } function getClass() { return fromCamelCase(str_replace('Am_Form_Brick_', '', get_class($this)), '-'); } function getName() { if (!$this->name) $this->name = str_replace('Am_Form_Brick_', '', get_class($this)); return $this->name; } function getId() { if (!$this->id) { $this->id = $this->getClass(); if ($this->isMultiple()) $this->id .= '-0'; } return $this->id; } function setId($id) { $this->id = (string) $id; } function getConfigArray() { return $this->config; } function setConfigArray(array $config) { $this->config = $config; } function getConfig($k, $default = null) { return array_key_exists($k, $this->config) ? $this->config[$k] : $default; } function getStdLabels() { return $this->labels; } function getCustomLabels() { return $this->customLabels; } function setCustomLabels(array $labels) { $this->customLabels = $labels; } function ___($id) { $args = func_get_args(); $args[0] = array_key_exists($id, $this->customLabels) ? $this->customLabels[$id] : $this->labels[$id]; return call_user_func_array('___', $args); } function initConfigForm(Am_Form $form) { } /** @return bool true if initConfigForm is overriden */ function haveConfigForm() { $r = new ReflectionMethod(get_class($this), 'initConfigForm'); return $r->getDeclaringClass()->getName() != __CLASS__; } function setFromRecord(array $brickConfig) { if ($brickConfig['id']) $this->id = $brickConfig['id']; $this->setConfigArray(empty($brickConfig['config']) ? array() : $brickConfig['config']); if (isset($brickConfig[self::HIDE])) $this->hideIfLoggedIn = $brickConfig[self::HIDE]; if (isset($brickConfig['labels'])) $this->customLabels = $brickConfig['labels']; return $this; } /** @return array */ function getRecord() { $ret = array( 'id' => $this->getId(), 'class' => $this->getClass(), ); if ($this->hideIfLoggedIn) $ret[self::HIDE] = $this->hideIfLoggedIn; if ($this->config) $ret['config'] = $this->config; if ($this->customLabels) $ret['labels'] = $this->customLabels; return $ret; } function isAcceptableForForm(Am_Form_Bricked $form) { return true; } public function hideIfLoggedIn() { return $this->hideIfLoggedIn; } public function hideIfLoggedInPossible() { return $this->hideIfLoggedInPossible; } /** if user can add many instances of brick right in the editor */ public function isMultiple() { return false; } static function createAvailableBricks($className) { return new $className; } /** * @param array $brickConfig - must have keys: 'id', 'class', may have 'hide', 'config' * * @return Am_Form_Brick */ static function createFromRecord(array $brickConfig) { if (empty($brickConfig['class'])) throw new Am_Exception_InternalError("Error in " . __METHOD__ . " - cannot create record without [class]"); if (empty($brickConfig['id'])) throw new Am_Exception_InternalError("Error in " . __METHOD__ . " - cannot create record without [id]"); $className = 'Am_Form_Brick_' . ucfirst(toCamelCase($brickConfig['class'])); if (!class_exists($className, true)) { Am_Di::getInstance()->errorLogTable->log("Missing form brick: [$className] - not defined"); return; } $b = new $className($brickConfig['id'], empty($brickConfig['config']) ? array() : $brickConfig['config']); if (array_key_exists(self::HIDE, $brickConfig)) $b->hideIfLoggedIn = (bool) @$brickConfig[self::HIDE]; if (!empty($brickConfig['labels'])) $b->setCustomLabels($brickConfig['labels']); return $b; } static function getAvailableBricks(Am_Form_Bricked $form) { $ret = array(); foreach (get_declared_classes () as $className) { if (is_subclass_of($className, 'Am_Form_Brick')) { $class = new ReflectionClass($className); if ($class->isAbstract()) continue; $obj = call_user_func(array($className, 'createAvailableBricks'), $className); if (!is_array($obj)) { $obj = array($obj); } foreach ($obj as $k => $o) if (!$o->isAcceptableForForm($form)) unset($obj[$k]); $ret = array_merge($ret, $obj); } } return $ret; } } class Am_Form_Brick_Name extends Am_Form_Brick { const DISPLAY_BOTH = 0; const DISPLAY_FIRSTNAME = 1; const DISPLAY_LASTNAME = 2; const DISPLAY_BOTH_SINGLE_INPUT = 3; protected $labels = array( 'First & Last Name', 'First Name', 'Last Name', 'Please enter your First Name', 'Please enter your First & Last Name', 'Please enter your Last Name', ); protected $hideIfLoggedInPossible = self::HIDE_DESIRED; public function __construct($id = null, $config = null) { $this->name = ___('Name'); parent::__construct($id, $config); } public function insertBrick(HTML_QuickForm2_Container $form) { if ($this->getConfig('two_rows') && $this->getConfig('display') != self::DISPLAY_BOTH_SINGLE_INPUT) { if ($this->getConfig('display') != self::DISPLAY_LASTNAME) { $row1 = $form->addGroup('')->setLabel($this->___('First Name')); if (!$this->getConfig('not_required')) { $row1->addRule('required'); } } if ($this->getConfig('display') != self::DISPLAY_FIRSTNAME) { $row2 = $form->addGroup('')->setLabel($this->___('Last Name')); if (!$this->getConfig('not_required')) { $row2->addRule('required'); } } $len = 30; } else { $row1 = $form->addGroup('', array('id' => 'name-0'))->setLabel($this->___('First & Last Name')); if (!$this->getConfig('not_required')) { $row1->addRule('required'); } $row2 = $row1; $len = 10; } if (!$this->getConfig('display') || $this->getConfig('display') == self::DISPLAY_FIRSTNAME) { $name_f = $row1->addElement('text', 'name_f', array('size' => $len)); if (!$this->getConfig('not_required')) { $name_f->addRule('required', $this->___('Please enter your First Name')); } $name_f->addRule('regex', $this->___('Please enter your First Name'), '/^[^=:<>{}()"]+$/D'); if ($this->getConfig('ucfirst')) $name_f->addFilter(function($v){return ucfirst(strtolower($v));}); if ($this->getConfig('disabled')) $name_f->toggleFrozen(true); $row1->addElement('html')->setHtml(' '); } if (!$this->getConfig('display') || $this->getConfig('display') == self::DISPLAY_LASTNAME) { $name_l = $row2->addElement('text', 'name_l', array('size' => $len)); if (!$this->getConfig('not_required')) { $name_l->addRule('required', $this->___('Please enter your Last Name')); } $name_l->addRule('regex', $this->___('Please enter your Last Name'), '/^[^=:<>{}()"]+$/D'); if ($this->getConfig('ucfirst')) $name_l->addFilter(function($v){return ucfirst(strtolower($v));}); if ($this->getConfig('disabled')) $name_l->toggleFrozen(true); } if ($this->getConfig('display') == self::DISPLAY_BOTH_SINGLE_INPUT) { $name = $row1->addElement('name', '_name', array('size' => 30)); if (!$this->getConfig('not_required')) { $name->addRule('required', $this->___('Please enter your First & Last Name')); } $name->addRule('regex', $this->___('Please enter your First & Last Name'), '/^[^=:<>{}()"]+$/D'); $filter = function ($v) {return trim($v);}; if ($this->getConfig('ucfirst')) { $filter = function ($v) use ($filter) { return ucwords(strtolower(call_user_func($filter, $v))); }; } $form->addFilter(function($v) use ($filter) { if (isset($v['_name'])) { list($v['name_f'], $v['name_l']) = array_pad(array_map($filter, explode(' ', $v['_name'], 2)), 2, ''); unset($v['_name']); } return $v; }); if ($this->getConfig('disabled')) $name->toggleFrozen(true); } } public function initConfigForm(Am_Form $form) { $form->addSelect('display') ->setId('name-display') ->loadOptions(array( self::DISPLAY_BOTH => ___('both First and Last Name'), self::DISPLAY_FIRSTNAME => ___('only First Name'), self::DISPLAY_LASTNAME => ___('only Last Name'), self::DISPLAY_BOTH_SINGLE_INPUT => ___('both First and Last Name in Single Input') ))->setLabel(___('User must provide')); $form->addAdvCheckbox('two_rows') ->setId('name-two_rows') ->setLabel(___('Display in 2 rows')); $form->addAdvCheckbox('not_required')->setLabel(___('Do not require to fill in these fields')); $form->addAdvCheckbox('ucfirst')->setLabel(___('Make the first letters of first and last name Uppercase')); $form->addAdvCheckbox('disabled')->setLabel(___('Read-only')); $both = self::DISPLAY_BOTH; $form->addScript() ->setScript(<<name = ___('HTML text'); parent::__construct($id, $config); } public function initConfigForm(Am_Form $form) { $form->addSelect('position', array('class' => 'brick-html-position')) ->setLabel(___('Position for HTML')) ->loadOptions(array( '' => ___('Default'), 'header' => ___('Above Form (Header)'), 'footer' => ___('Below Form (Footer)'), )); $form->addTextarea('html', array('rows' => 15, 'class' => 'el-wide')) ->setLabel(___('HTML Code that will be displayed')); $form->addText('label', array('class' => 'el-wide', 'rel' => 'position-default'))->setLabel(___('Label')); $form->addAdvCheckbox('no_label', array('rel' => 'position-default'))->setLabel(___('Remove Label')); $form->addMagicSelect('lang') ->setLabel(___("Language\n" . 'Display this brick only for the following languages. ' . 'Keep it empty to display for any language.')) ->loadOptions($this->getLangaugeList()); $form->addScript() ->setScript(<<languagesListUser; $_list = array(); if ($enabled = $di->config->get('lang.enabled', array())) foreach ($enabled as $lang) if (!empty($avail[$lang])) $_list[$lang] = $avail[$lang]; return $_list; } public function getLanguage() { $_list = $this->getLangaugeList(); $_locale = key(Zend_Locale::getDefault()); if (!array_key_exists($_locale, $_list)) list($_locale) = explode('_', $_locale); return $_locale; } public function insertBrick(HTML_QuickForm2_Container $form) { $lang = $this->getConfig('lang'); if ($lang && !in_array($this->getLanguage(), $lang)) return; switch ($this->getConfig('position')) { case 'header' : $form->addProlog($this->getConfig('html')); break; case 'footer' : $form->addEpilog($this->getConfig('html')); break; default: $attrs = $data = array(); $data['content'] = $this->getConfig('html'); if ($this->getConfig('no_label')) { $attrs['class'] = 'no-label'; } else { $data['label'] = $this->getConfig('label'); } $form->addStatic('html' . (++self::$counter), $attrs, $data); } } public function isMultiple() { return true; } } class Am_Form_Brick_JavaScript extends Am_Form_Brick { public function initConfigForm(Am_Form $form) { $form->addTextarea('code', array('rows' => 15, 'class' => 'el-wide')) ->setLabel(___("JavaScript Code\n" . "it will be injected on signup form")); } public function insertBrick(HTML_QuickForm2_Container $form) { $form->addScript()->setScript($this->getConfig('code')); } public function isMultiple() { return true; } } class Am_Form_Brick_Email extends Am_Form_Brick { protected $labels = array( "Your E-Mail Address\na confirmation email will be sent to you at this address", 'Please enter valid Email', 'Confirm Your E-Mail Address', 'E-Mail Address and E-Mail Address Confirmation are different. Please reenter both', 'An account with the same email already exists.', 'Please %slogin%s to your existing account.%sIf you have not completed payment, you will be able to complete it after login' ); protected $hideIfLoggedInPossible = self::HIDE_ALWAYS; public function __construct($id = null, $config = null) { $this->name = ___('E-Mail'); parent::__construct($id, $config); } public function initConfigForm(Am_Form $form) { $form->addAdvCheckbox('validate')->setLabel(___('Validate E-Mail Address by sending e-mail message with code')); $form->addAdvCheckbox('confirm') ->setLabel(___("Confirm E-Mail Address\n" . 'second field will be displayed to enter email address twice')) ->setId('email-confirm'); $form->addAdvCheckbox('do_not_allow_copy_paste') ->setLabel(___('Does not allow to Copy&Paste to confirmation field')) ->setId('email-do_not_allow_copy_paste'); $form->addAdvCheckbox("disabled")->setLabel(___('Read-only')); $form->addScript() ->setScript(<<auth->getUserId(); if (!$user_id) $user_id = Am_Di::getInstance()->session->signup_member_id; if (!Am_Di::getInstance()->userTable->checkUniqEmail($email, $user_id)) return $this->___('An account with the same email already exists.') . '
' . $this->___('Please %slogin%s to your existing account.%sIf you have not completed payment, you will be able to complete it after login', '', '', '
'); return Am_Di::getInstance()->banTable->checkBan(array('email' => $email)); } public function insertBrick(HTML_QuickForm2_Container $form) { $email = $form->addText('email', array('size' => 30)) ->setLabel($this->___("Your E-Mail Address\na confirmation email will be sent to you at this address")); $email->addRule('required', $this->___('Please enter valid Email')) ->addRule('callback', $this->___('Please enter valid Email'), array('Am_Validate', 'email')); if ($this->getConfig('disabled')) $email->toggleFrozen(true); $redirect = isset($_GET['amember_redirect_url']) ? $_GET['amember_redirect_url'] : $_SERVER['REQUEST_URI']; $email->addRule('callback2', '--wrong email--', array($this, 'check')) ->addRule('remote', '--wrong email--', array( 'url' => Am_Di::getInstance()->url('ajax', array('do'=>'check_uniq_email','_url'=> Am_Di::getInstance()->url('login', array('amember_redirect_url'=>$redirect), false ) ), false ))); if ($this->getConfig('confirm', 0)) { $email0 = $form->addText('_email', array('size' => 30)) ->setLabel($this->___("Confirm Your E-Mail Address")) ->setId('email-confirm'); $email0->addRule('required'); $email0->addRule('eq', $this->___('E-Mail Address and E-Mail Address Confirmation are different. Please reenter both'), $email); if ($this->getConfig('do_not_allow_copy_paste')) { $form->addScript() ->setScript(' jQuery(function(){ var $ = jQuery; jQuery("#email-confirm").bind("paste", function() { return false; }) })'); } return array($email, $email0); } } } class Am_Form_Brick_Login extends Am_Form_Brick { protected $labels = array( "Choose a Username\nit must be %d or more characters in length\nmay only contain letters, numbers, and underscores", 'Please enter valid Username. It must contain at least %d characters', 'Username contains invalid characters - please use digits, letters or spaces', 'Username contains invalid characters - please use digits, letters, dash and underscore', 'Username %s is already taken. Please choose another username', ); protected $hideIfLoggedInPossible = self::HIDE_ALWAYS; public function __construct($id = null, $config = null) { $this->name = ___("Username"); parent::__construct($id, $config); } public function insertBrick(HTML_QuickForm2_Container $form) { $len = Am_Di::getInstance()->config->get('login_min_length', 6); $login = $form->addText('login', array('size' => 30, 'maxlength' => Am_Di::getInstance()->config->get('login_max_length', 64))) ->setLabel($this->___("Choose a Username\nit must be %d or more characters in length\nmay only contain letters, numbers, and underscores", $len)); $login->addRule('required', sprintf($this->___('Please enter valid Username. It must contain at least %d characters'), $len)) ->addRule('length', sprintf($this->___('Please enter valid Username. It must contain at least %d characters'), $len), array($len, Am_Di::getInstance()->config->get('login_max_length', 64))) ->addRule('regex', !Am_Di::getInstance()->config->get('login_disallow_spaces') ? $this->___('Username contains invalid characters - please use digits, letters or spaces') : $this->___('Username contains invalid characters - please use digits, letters, dash and underscore'), Am_Di::getInstance()->userTable->getLoginRegex()) ->addRule('callback2', "--wrong login--", array($this, 'check')) ->addRule('remote', '--wrong login--', array( 'url' => Am_Di::getInstance()->url('ajax', array('do'=>'check_uniq_login'), false), )); if (!Am_Di::getInstance()->config->get('login_dont_lowercase')) $login->addFilter('strtolower'); $this->form = $form; } public function check($login) { if (!Am_Di::getInstance()->userTable->checkUniqLogin($login, Am_Di::getInstance()->session->signup_member_id)) return sprintf($this->___('Username %s is already taken. Please choose another username'), Am_Html::escape($login)); return Am_Di::getInstance()->banTable->checkBan(array('login' => $login)); } public function isAcceptableForForm(Am_Form_Bricked $form) { return $form instanceof Am_Form_Signup; } } class Am_Form_Brick_NewLogin extends Am_Form_Brick { protected $labels = array( "Username\nyou can choose new username here or keep it unchanged.\nUsername must be %d or more characters in length and may\nonly contain small letters, numbers, and underscore", "Please enter valid Username. It must contain at least %d characters", "Username contains invalid characters - please use digits, letters or spaces", "Username contains invalid characters - please use digits, letters, dash and underscore", 'Username %s is already taken. Please choose another username', ); public function __construct($id = null, $config = null) { $this->name = ___('Change Username'); parent::__construct($id, $config); } public function insertBrick(HTML_QuickForm2_Container $form) { $len = Am_Di::getInstance()->config->get('login_min_length', 6); $login = $form->addText('login', array('size' => 30, 'maxlength' => Am_Di::getInstance()->config->get('login_max_length', 64))) ->setLabel(sprintf($this->___("Username\nyou can choose new username here or keep it unchanged.\nUsername must be %d or more characters in length and may\nonly contain small letters, numbers, and underscore"), $len) ); if ($this->getConfig('disabled')) $login->toggleFrozen(true); $login ->addRule('required') ->addRule('length', sprintf($this->___("Please enter valid Username. It must contain at least %d characters"), $len), array($len, Am_Di::getInstance()->config->get('login_max_length', 64))) ->addRule('regex', !Am_Di::getInstance()->config->get('login_disallow_spaces') ? $this->___("Username contains invalid characters - please use digits, letters or spaces") : $this->___("Username contains invalid characters - please use digits, letters, dash and underscore"), Am_Di::getInstance()->userTable->getLoginRegex()) ->addRule('callback2', $this->___('Username %s is already taken. Please choose another username'), array($this, 'checkNewUniqLogin')); } function checkNewUniqLogin($login) { $auth_user = Am_Di::getInstance()->auth->getUser(); if (strcasecmp($login, $auth_user->login) !== 0) if (!$auth_user->getTable()->checkUniqLogin($login, $auth_user->pk())) return sprintf($this->___('Username %s is already taken. Please choose another username'), Am_Html::escape($login)); } public function isAcceptableForForm(Am_Form_Bricked $form) { return $form instanceof Am_Form_Profile; } public function initConfigForm(Am_Form $form) { $form->addAdvCheckbox("disabled")->setLabel(___('Read-only')); } } class Am_Form_Brick_Password extends Am_Form_Brick { protected $labels = array( "Choose a Password\nmust be %d or more characters", 'Confirm Your Password', 'Please enter Password', 'Password must contain at least %d letters or digits', 'Password and Password Confirmation are different. Please reenter both', 'Password should contain at least 2 capital letters, 2 or more numbers and 2 or more special chars', ); protected $hideIfLoggedInPossible = self::HIDE_ALWAYS; public function __construct($id = null, $config = null) { $this->name = ___("Password"); parent::__construct($id, $config); } public function initConfigForm(Am_Form $form) { $form->addAdvCheckbox('do_not_confirm') ->setLabel(___("Does not Confirm Password\n" . 'second field will not be displayed to enter password twice')) ->setId('password-do_not_confirm'); $form->addAdvCheckbox('do_not_allow_copy_paste') ->setLabel(___('Does not allow to Copy&Paste to confirmation field')) ->setId('password-do_not_allow_copy_paste'); $form->addScript() ->setScript(<<config->get('pass_min_length', 6); $pass = $form->addPassword('pass', array('size' => 30, 'autocomplete'=>'off', 'maxlength' => Am_Di::getInstance()->config->get('pass_max_length', 64))) ->setLabel($this->___("Choose a Password\nmust be %d or more characters", $len)); $pass->addRule('required', $this->___('Please enter Password')); $pass->addRule('length', sprintf($this->___('Password must contain at least %d letters or digits'), $len), array($len, Am_Di::getInstance()->config->get('pass_max_length', 64))); if (Am_Di::getInstance()->config->get('require_strong_password')) { $pass->addRule('regex', $this->___('Password should contain at least 2 capital letters, 2 or more numbers and 2 or more special chars'), Am_Di::getInstance()->userTable->getStrongPasswordRegex()); } if (!$this->getConfig('do_not_confirm')) { $pass0 = $form->addPassword('_pass', array('size' => 30, 'autocomplete'=>'off')) ->setLabel($this->___('Confirm Your Password')) ->setId('pass-confirm'); $pass0->addRule('required'); $pass0->addRule('eq', $this->___('Password and Password Confirmation are different. Please reenter both'), $pass); if ($this->getConfig('do_not_allow_copy_paste')) { $form->addScript() ->setScript(' jQuery(function($){ jQuery("#pass-confirm").bind("paste", function() { return false; }) })'); } return array($pass, $pass0); } else { $pass->setAttribute('class', 'am-pass-reveal am-with-action'); } return $pass; } public function isAcceptableForForm(Am_Form_Bricked $form) { return $form instanceof Am_Form_Signup; } } class Am_Form_Brick_NewPassword extends Am_Form_Brick { protected $labels = array( "Password", "Change", "Your Current Password\nif you are changing password, please\n enter your current password for validation", "New Password\nyou can choose new password here or keep it unchanged\nmust be %d or more characters", 'Confirm New Password', 'Please enter Password', 'Password must contain at least %d letters or digits', 'Password and Password Confirmation are different. Please reenter both', 'Please enter your current password for validation', 'Current password entered incorrectly, please try again', 'Password should contain at least 2 capital letters, 2 or more numbers and 2 or more special chars', ); public function __construct($id = null, $config = null) { $this->name = ___('Change Password'); parent::__construct($id, $config); } public function initConfigForm(Am_Form $form) { $form->addAdvCheckbox('do_not_ask_current_pass') ->setLabel(___("Does not Ask Current Password\n" . 'user will not need to enter his current password to change it')); $form->addAdvCheckbox('do_not_confirm') ->setLabel(___("Does not Confirm Password\n" . 'second field will not be displayed to enter password twice')) ->setId('new-password-do_not_confirm'); $form->addAdvCheckbox('do_not_allow_copy_paste') ->setLabel(___('Does not allow to Copy&Paste to confirmation field')) ->setId('new-password-do_not_allow_copy_paste'); $form->addScript() ->setScript(<<___('Change')); $form->addHtml() ->setLabel($this->___('Password')) ->setHtml(<<$change CUT ); $len = Am_Di::getInstance()->config->get('pass_min_length', 6); if (!$this->getConfig('do_not_ask_current_pass')) { $oldPass = $form->addPassword('_oldpass', array('size' => 30, 'autocomplete'=>'off', 'class'=>'am-change-pass')) ->setLabel($this->___("Your Current Password\nif you are changing password, please\n enter your current password for validation")); $oldPass->addRule('callback2', 'wrong', array($this, 'validateOldPass')); } $pass = $form->addPassword('pass', array('size' => 30, 'autocomplete'=>'off', 'maxlength' => Am_Di::getInstance()->config->get('pass_max_length', 64), 'class'=>'am-change-pass')) ->setLabel($this->___("New Password\nyou can choose new password here or keep it unchanged\nmust be %d or more characters", $len)); $pass->addRule('length', sprintf($this->___('Password must contain at least %d letters or digits'), $len), array($len, Am_Di::getInstance()->config->get('pass_max_length', 64))); if (Am_Di::getInstance()->config->get('require_strong_password')) { $pass->addRule('regex', $this->___('Password should contain at least 2 capital letters, 2 or more numbers and 2 or more special chars'), Am_Di::getInstance()->userTable->getStrongPasswordRegex()); } if (!$this->getConfig('do_not_confirm')) { $pass0 = $form->addPassword('_pass', array('size' => 30, 'autocomplete'=>'off', 'class'=>'am-change-pass')) ->setLabel($this->___('Confirm New Password')) ->setId('pass-confirm'); $pass0->addRule('eq', $this->___('Password and Password Confirmation are different. Please reenter both'), $pass); if ($this->getConfig('do_not_allow_copy_paste')) { $form->addScript() ->setScript(' jQuery(function($){ jQuery("#pass-confirm").bind("paste", function() { return false; }) })'); } return array($pass, $pass0); } return $pass; } public function validateOldPass($vars, HTML_QuickForm2_Element_InputPassword $el) { $vars = $el->getContainer()->getValue(); if ($vars['pass'] != '') { if ($vars['_oldpass'] == '') return $this->___('Please enter your current password for validation'); $protector = new Am_Auth_BruteforceProtector( Am_Di::getInstance()->db, Am_Di::getInstance()->config->get('protect.php_include.bruteforce_count', 5), Am_Di::getInstance()->config->get('protect.php_include.bruteforce_delay', 120), Am_Auth_BruteforceProtector::TYPE_USER); if ($wait = $protector->loginAllowed($_SERVER['REMOTE_ADDR'])) { return ___('Please wait %d seconds before next attempt', $wait); } if (!Am_Di::getInstance()->user->checkPassword($vars['_oldpass'])) { $protector->reportFailure($_SERVER['REMOTE_ADDR']); return $this->___('Current password entered incorrectly, please try again'); } } } public function isAcceptableForForm(Am_Form_Bricked $form) { return $form instanceof Am_Form_Profile; } } class Am_Form_Brick_Address extends Am_Form_Brick { protected $labels = array( 'Address Information' => 'Address Information', 'Street' => 'Street', 'Street (Second Line)' => 'Street (Second Line)', 'City' => 'City', 'State' => 'State', 'ZIP Code' => 'ZIP Code', 'Country' => 'Country', ); public function __construct($id = null, $config = null) { $this->name = ___('Address Information'); if (empty($config['fields'])) { $config['fields'] = array( 'street' => 1, 'city' => 1, 'country' => 1, 'state' => 1, 'zip' => 1, ); } parent::__construct($id, $config); } public function insertBrick(HTML_QuickForm2_Container $form) { $fieldSet = $this->getConfig('hide_fieldset') ? $form : $form->addElement('fieldset', 'address', array('id' => 'row-address-0'))->setLabel($this->___('Address Information')); foreach ($this->getConfig('fields', array()) as $f => $required) { switch ($f) { case 'street' : $street = $fieldSet->addText('street', array('class' => 'el-wide'))->setLabel($this->___('Street')); if ($required) $street->addRule('required', ___('Please enter %s', $this->___('Street'))); break; case 'street2' : $street = $fieldSet->addText('street2', array('class' => 'el-wide'))->setLabel($this->___('Street (Second Line)')); if ($required) $street->addRule('required', ___('Please enter %s', $this->___('Street (Second Line)'))); break; case 'city' : $city = $fieldSet->addText('city', array('class' => 'el-wide'))->setLabel($this->___('City')); if ($required) $city->addRule('required', ___('Please enter %s', $this->___('City'))); break; case 'zip' : $zip = $fieldSet->addText('zip')->setLabel($this->___('ZIP Code')); if ($required) $zip->addRule('required', ___('Please enter %s', $this->___('ZIP Code'))); break; case 'country' : $country = $fieldSet->addSelect('country')->setLabel($this->___('Country')) ->setId('f_country') ->loadOptions(Am_Di::getInstance()->countryTable->getOptions(true)); if ($required) $country->addRule('required', ___('Please enter %s', $this->___('Country'))); break; case 'state' : $group = $fieldSet->addGroup()->setLabel($this->___('State')); $stateSelect = $group->addSelect('state') ->setId('f_state') ->loadOptions($stateOptions = Am_Di::getInstance()->stateTable->getOptions(@$_REQUEST['country'], true)); $stateText = $group->addText('state')->setId('t_state'); $disableObj = $stateOptions ? $stateText : $stateSelect; $disableObj->setAttribute('disabled', 'disabled')->setAttribute('style', 'display: none'); if ($required) $group->addRule('required', ___('Please enter %s', $this->___('State'))); break; } } if ($this->getConfig('country_default')) { $form->addDataSource(new HTML_QuickForm2_DataSource_Array(array( 'country' => $this->getConfig('country_default') ))); } } public function setConfigArray(array $config) { // Deal with old style Address required field. if (isset($config['required']) && $config['required'] && !array_key_exists('street_display', $config)) { foreach (array('zip', 'street', 'city', 'state', 'country') as $f) { $config[$f . '_display'] = 1; // Required } } unset($config['required']); if (isset($config['street_display'])) { //backwards compatability //prev it stored as fieldName_display = enum(-1, 0, 1) //-1 - do not display // 0 - display // 1 - display and required isset($config['fields']) || ($config['fields'] = array()); $farr = array('street', 'street2', 'city', 'zip', 'country', 'state'); foreach ($farr as $f) { if (-1 != ($val = @$config[$f . '_display'])) { $config['fields'][$f] = (int) $val; } unset($config[$f . '_display']); } } parent::setConfigArray($config); } public function initConfigForm(Am_Form $form) { $farr = array('street', 'street2', 'city', 'zip', 'country', 'state'); $fieldsVal = $this->getConfig('fields'); $fields = $form->addElement(new Am_Form_Element_AddressFields('fields')); $fields->setLabel(___('Fields To Display')); foreach ($farr as $f) { $attr = array( 'data-label' => ucfirst($f) . ' required', 'data-value' => !empty($fieldsVal[$f]), ); $fields->addOption(ucfirst($f), $f, $attr); } $fields->setJsOptions('{ sortable : true, getOptionName : function (name, option) { return name.replace(/\[\]$/, "") + "[" + option.value + "]"; }, getOptionValue : function (option) { return jQuery(option).data("value"); }, onOptionAdded : function (context, option) { if (jQuery(context).find("input[type=hidden]").val() == 1) { jQuery(context).find("input[type=checkbox]").prop("checked", "checked"); } } }'); $form->addSelect('country_default')->setLabel('Default Country')->loadOptions(Am_Di::getInstance()->countryTable->getOptions(true)); $form->addAdvCheckbox('hide_fieldset')->setLabel(___('Hide Brick Title')); } } class Am_Form_Brick_Phone extends Am_Form_Brick { protected $labels = array( 'Phone Number' => 'Phone Number', ); public function insertBrick(HTML_QuickForm2_Container $form) { $phone = $form->addText('phone')->setLabel($this->___('Phone Number')); if ($this->getConfig('required')) { $phone->addRule('required', ___('Please enter %s', $this->___('Phone Number'))); } } public function initConfigForm(Am_Form $form) { $form->addAdvCheckbox('required')->setLabel(___('Required')); } } class Am_Form_Brick_Product extends Am_Form_Brick { const DISPLAY_ALL = 0; const DISPLAY_CATEGORY = 1; const DISPLAY_PRODUCT = 2; const DISPLAY_BP = 3; const REQUIRE_DEFAULT = 0; const REQUIRE_ALWAYS = 1; const REQUIRE_NEVER = 2; const REQUIRE_ALTERNATE = 3; protected $labels = array( 'Membership Type', 'Please choose a membership type', 'Add Membership' ); protected $hideIfLoggedInPossible = self::HIDE_DONT; protected static $bricksAdded = 0; protected static $bricksWhichCanBeRequiredAdded = 0; protected static $bricksAlternateAdded = 0; public function __construct($id = null, $config = null) { $this->name = ___('Product'); parent::__construct($id, $config); } function shortRender(Product $p, BillingPlan $plan = null) { return $p->getTitle() . ' - ' . $plan->getTerms(); } function renderProduct(Product $p, BillingPlan $plan = null, $short = false) { return $p->defaultRender($plan, $short); } function getProducts() { $ret = array(); switch ($this->getConfig('type', 0)) { case self::DISPLAY_CATEGORY: $ret = Am_Di::getInstance()->productTable->getVisible($this->getConfig('groups', array())); break; case self::DISPLAY_PRODUCT: $ret = array(); $ids = $this->getConfig('products', array()); $arr = Am_Di::getInstance()->productTable->loadIds($ids); foreach ($ids as $id) { foreach ($arr as $p) if ($p->product_id == $id) { if ($p->is_disabled) continue; $ret[] = $p; } } break; case self::DISPLAY_BP: $ret = array(); $ids = array_map('intval', $this->getConfig('bps', array())); //strip bp $arr = Am_Di::getInstance()->productTable->loadIds($ids); foreach ($ids as $id) { foreach ($arr as $p) if ($p->product_id == $id) { if ($p->is_disabled) continue; $ret[] = $p; } } break; default: $ret = Am_Di::getInstance()->productTable->getVisible(null); } $event = new Am_Event(Am_Event::SIGNUP_FORM_GET_PRODUCTS); $event->setReturn($ret); Am_Di::getInstance()->hook->call($event); return $event->getReturn(); } function getBillingPlans($products) { switch ($this->getConfig('type', 0)) { case self::DISPLAY_BP: $map = array(); foreach ($products as $p) { $map[$p->pk()] = $p; } $res = array(); foreach ($this->getConfig('bps', array()) as $item) { list($p_id, $bp_id) = explode('-', $item); if (isset($map[$p_id])) { foreach ($map[$p_id]->getBillingPlans(true) as $bp) { if ($bp->pk() == $bp_id) $res[] = $bp; } } } break; case self::DISPLAY_ALL: case self::DISPLAY_CATEGORY: case self::DISPLAY_PRODUCT: default: $res = array(); foreach ($products as $product) { $res = array_merge($res, $product->getBillingPlans(true)); } } $e = new Am_Event(Am_Event::SIGNUP_FORM_GET_BILLING_PLANS); $e->setReturn($res); Am_Di::getInstance()->hook->call($e); return $e->getReturn(); } function getProductsFiltered() { $products = $this->getProducts(); if ($this->getConfig('display-type', 'hide') == 'display') return $products; $user = Am_Di::getInstance()->auth->getUser(); $haveActive = $haveExpired = array(); if (!is_null($user)) { $haveActive = $user->getActiveProductIds(); $haveExpired = $user->getExpiredProductIds(); } $ret = Am_Di::getInstance()->productTable ->filterProducts($products, $haveActive, $haveExpired, $this->getConfig('input-type') == 'checkbox' ? true : false); $event = new Am_Event(Am_Event::SIGNUP_FORM_GET_PRODUCTS_FILTERED); $event->setReturn($ret); Am_Di::getInstance()->hook->call($event); return $event->getReturn(); } public function insertProductOptions(HTML_QuickForm2_Container $form, $pid, array $productOptions, BillingPlan $plan) { foreach ($productOptions as $option) { $elName = 'productOption[' . $pid . '][0][' . $option->name . ']'; $isEmpty = empty($_POST['productOption'][$pid][0][$option->name]); /* @var $option ProductOption */ $el = null; switch ($option->type) { case 'text': $el = $form->addElement('text', $elName); if ($isEmpty) $el->setValue($option->getDefault()); break; case 'radio': $el = $form->addElement('advradio', $elName); $el->loadOptions($option->getSelectOptionsWithPrice($plan)); if ($isEmpty) $el->setValue($option->getDefault()); break; case 'select': $el = $form->addElement('select', $elName); $el->loadOptions($option->getSelectOptionsWithPrice($plan)); if ($isEmpty) $el->setValue($option->getDefault()); break; case 'multi_select': $el = $form->addElement('magicselect', $elName); $el->loadOptions($option->getSelectOptionsWithPrice($plan)); if ($isEmpty) $el->setValue($option->getDefaults()); break; case 'textarea': $el = $form->addElement('textarea', $elName, 'class=el-wide rows=5'); if ($isEmpty) $el->setValue($option->getDefault()); break; case 'checkbox': $opts = $option->getSelectOptionsWithPrice($plan); if ($opts) { $el = $form->addGroup($elName); $el->setSeparator("
"); foreach ($opts as $k => $v) { $chkbox = $el->addAdvCheckbox(null, array('value' => $k))->setContent(___($v)); if ($isEmpty && in_array($k, (array)$option->getDefaults())) $chkbox->setAttribute('checked', 'checked'); } $el->addHidden(null, array('value' => '')); $el->addFilter('array_filter'); } else { $el = $form->addElement('advcheckbox', $elName); } break; case 'date': $el = $form->addElement('date', $elName); break; } if ($el && $option->is_required) { // onblur client set to only validate option fields with javascript // else there is a problem with hidden fields as quickform2 does not skip validation for hidden $el->addRule('required', ___('This field is required'), null, HTML_QuickForm2_Rule::ONBLUR_CLIENT); } $el->setLabel(___($option->title)); } } public function insertBrick(HTML_QuickForm2_Container $form) { $product_paysys = Am_Di::getInstance()->config->get('product_paysystem'); $base_name = 'product_id_' . $form->getId(); $name = self::$bricksAdded ? $base_name . '_' . self::$bricksAdded : $base_name; $productOptions = array(); $products = $this->getProductsFiltered(); if (!$products) { if ($this->getConfig('require', self::REQUIRE_DEFAULT) == self::REQUIRE_NEVER) return; throw new Am_Exception_QuietError(___("There are no products available for purchase. Please come back later.")); } self::$bricksAdded++; if ($this->getConfig('require', self::REQUIRE_DEFAULT) != self::REQUIRE_NEVER) self::$bricksWhichCanBeRequiredAdded++; if ($this->getConfig('require', self::REQUIRE_DEFAULT) == self::REQUIRE_ALTERNATE) self::$bricksAlternateAdded++; $options = $shortOptions = $attrs = $dataOptions = array(); if ($this->getConfig('empty-option')) { $shortOptions[null] = $this->getConfig('empty-option-text', ___('Please select')); $options[null] = '' . $shortOptions[null] . ''; $attrs[null] = array(); $dataOptions[null] = array( 'value' => null, 'label' => $options[null], 'selected' => false, 'variable_qty' => false, 'qty' => 1,); } foreach ($this->getBillingPlans($products) as $plan) { $p = $plan->getProduct(); $pid = $p->product_id . '-' . $plan->plan_id; $options[$pid] = $this->renderProduct($p, $plan); $shortOptions[$pid] = $this->shortRender($p, $plan); $attrs[$pid] = array( 'data-first_price' => $plan->first_price, 'data-second_price' => $plan->second_price, 'data-paysys' => $product_paysys && $plan->paysys_id ); $dataOptions[$pid] = array( 'label' => $options[$pid], 'value' => $pid, 'variable_qty' => $plan->variable_qty, 'qty' => $plan->qty, 'selected' => false, ); $productOptions[$pid] = $p->getOptions(); $billingPlans[$pid] = $plan; } $inputType = $this->getConfig('input-type', 'advradio'); if (count($options) == 1) { if ($this->getConfig('hide_if_one')) $inputType = 'none'; elseif ($inputType != 'checkbox') $inputType = 'hidden'; } $oel = null; //outer element $productOptionsDontHide = false; switch ($inputType) { case 'none': list($pid, $label) = each($options); $oel = $el = $form->addHidden($name, $attrs[$pid]); $el->setValue($pid); $el->toggleFrozen(true); $productOptionsDontHide = true; // normally options display with js but not in this case! break; case 'checkbox': $data = array(); foreach ($this->getBillingPlans($products) as $plan) { $p = $plan->getProduct(); $data[$p->product_id . '-' . $plan->pk()] = array( 'data-first_price' => $plan->first_price, 'data-second_price' => $plan->second_price, 'data-paysys' => $product_paysys && $plan->paysys_id, 'options' => array( 'value' => $p->product_id . '-' . $plan->pk(), 'label' => $this->renderProduct($p, $plan), 'variable_qty' => $plan->variable_qty, 'qty' => $plan->qty, 'selected' => false, ), ); } if ($this->getConfig('display-popup')) { $search = ''; if ($this->getConfig('cat-filter')) { $all_cats = array(); foreach ($this->getBillingPlans($products) as $plan) { $p = $plan->getProduct(); $p_cats = $p->getCategoryTitles(); $all_cats = array_merge($all_cats, $p_cats); $data[$p->product_id . '-' . $plan->pk()]['rel'] = implode(', ', array_merge(array('All'), $p_cats)); } $exclude = array_map(function($el) {return $el->title;}, $_ = Am_Di::getInstance()->productCategoryTable->loadIds($this->getConfig('cat-filter-exclude', array()))); $all_cats = array_unique($all_cats); $all_cats = array_diff($all_cats, $exclude); sort($all_cats); array_unshift($all_cats, 'All'); foreach ($all_cats as $t) { $search[] = sprintf('%s', $t, $t); } $search = sprintf('
%s
', implode(' | ', $search)); } $oel = $gr = $form->addGroup(); $gr->addStatic() ->setContent(sprintf('
', $name)); $gr->addStatic() ->setContent(sprintf('', $name, $this->___('Membership Type'), $this->___('Add Membership'))); $gr->addStatic() ->setContent(sprintf(''); $form->addScript() ->setScript(<<'). append(' '). append(jQuery(this).parent().html().replace(//g, '')) ); }) jQuery('#' + name + '-list input[type=checkbox]').change(); } jQuery(function(){ jQuery('.am-brick-product-popup-cat').click(function(){ jQuery(this).parent().find('a').removeClass('am-brick-product-popup-cat-active'); jQuery(this).addClass('am-brick-product-popup-cat-active'); var \$q = jQuery(this).closest('.am-brick-product-popup').find('input[type=checkbox]'); \$q.closest('label').show(). next().show(); \$q.not('[rel*="' + jQuery(this).data('title') + '"]').closest('label').hide(). next().hide(); }) jQuery('#$name').click(function(){ jQuery('#$name-list').amPopup({ title : jQuery(this).data('title'), width : 450, onClose: function(){ propogateChanges('$name'); } }); return false; }) propogateChanges('$name'); }); CUT ); } else { $oel = $el = $form->addElement(new Am_Form_Element_SignupCheckboxGroup($name, $data, 'checkbox')); } break; case 'select': $oel = $el = $form->addSelect($name); foreach ($shortOptions as $pid => $label) $el->addOption($label, $pid, empty($attrs[$pid]) ? null : $attrs[$pid]); break; case 'hidden': case 'advradio': default: $data = array(); $first = 0; foreach ($options as $pid => $label) { $data[$pid] = $attrs[$pid]; $data[$pid]['options'] = $dataOptions[$pid]; if (!$first++ && Am_Di::getInstance()->request->isGet()) // pre-check first option $data[$pid]['options']['selected'] = true; } $oel = $el = $form->addElement(new Am_Form_Element_SignupCheckboxGroup($name, $data, $inputType == 'advradio' ? 'radio' : $inputType)); break; } $oel->setLabel($this->___('Membership Type')); if ($this->getConfig('no_label')) { $oel->setAttribute('class', 'no-label'); } switch ($this->getConfig('require', self::REQUIRE_DEFAULT)) { case self::REQUIRE_DEFAULT : if (self::$bricksWhichCanBeRequiredAdded == 1) $el->addRule('required', $this->___('Please choose a membership type')); break; case self::REQUIRE_ALWAYS : $el->addRule('required', $this->___('Please choose a membership type')); break; case self::REQUIRE_NEVER : break; case self::REQUIRE_ALTERNATE : if (self::$bricksAlternateAdded == 1) { $f = $form; while ($container = $f->getContainer()) $f = $container; $f->addRule('callback2', $this->___('Please choose a membership type'), array($this, 'formValidate')); } break; default: throw new Am_Exception_InternalError('Unknown require type [%s] for product brick', $this->getConfig('require', self::REQUIRE_DEFAULT)); } if (self::$bricksAdded == 1) { $script = <<addScript()->setScript($script); } if (($d = $this->getConfig('default')) && $inputType != 'none' && $inputType != 'hidden') { $form->addDataSource(new HTML_QuickForm2_DataSource_Array(array( $name => ($inputType == 'checkbox' || $inputType == 'advradio') ? array($d) : $d ))); } foreach ($productOptions as $pid => $productOptions) { if ($productOptions) { $fs = $form->addElement('fieldset', '', array( 'class' => 'am-product-options-' . $pid, 'style' => $productOptionsDontHide ? '' : 'display:none;')); $this->insertProductOptions($fs, $pid, $productOptions, $billingPlans[$pid]); } } } public function initConfigForm(Am_Form $form) { $radio = $form->addSelect('type') ->setLabel(___('What to Display')); $radio->loadOptions(array( self::DISPLAY_ALL => ___('Display All Products'), self::DISPLAY_CATEGORY => ___('Products from selected Categories'), self::DISPLAY_PRODUCT => ___('Only Products selected below'), self::DISPLAY_BP => ___('Only Billing Plans selected below') )); $groups = $form->addMagicSelect('groups', array('data-type' => self::DISPLAY_CATEGORY,))->setLabel(___('Product Gategories')); $groups->loadOptions(Am_Di::getInstance()->productCategoryTable->getAdminSelectOptions(array(ProductCategoryTable::COUNT => 1))); $products = $form->addSortableMagicSelect('products', array('data-type' => self::DISPLAY_PRODUCT,))->setLabel(___('Product(s) to display')); $products->loadOptions(Am_Di::getInstance()->productTable->getOptions(true)); $bpOptions = array(); foreach (Am_Di::getInstance()->productTable->getVisible() as $product) { /* @var $product Product */ foreach ($product->getBillingOptions() as $bp_id => $title) { $bpOptions[$product->pk() . '-' . $bp_id] = sprintf('%s (%s)', $product->title, $title); } } $bps = $form->addSortableMagicSelect('bps', array('data-type' => self::DISPLAY_BP,))->setLabel(___('Billing Plan(s) to display')); $bps->loadOptions($bpOptions); $form->addSelect('default') ->setLabel(___('Select by default')) ->loadOptions(array(''=>'') + $bpOptions); $inputType = $form->addSelect('input-type')->setLabel(___('Input Type')); $inputType->loadOptions(array( 'advradio' => ___('Radio-buttons (one product can be selected)'), 'select' => ___('Select-box (one product can be selected)'), 'checkbox' => ___('Checkboxes (multiple products can be selected)'), )); $form->addAdvCheckbox('display-popup') ->setlabel(___('Display Products in Popup')); $form->addAdvCheckbox('cat-filter') ->setlabel(___('Add Category Filter to Popup')); $form->addMagicSelect('cat-filter-exclude', array('class'=>'cat-filter-exclude')) ->setLabel(___('Exclude the following categories from Filter')) ->loadOptions(Am_Di::getInstance()->productCategoryTable->getOptions()); $form->addSelect('display-type')->setLabel(___('If product is not available because of require/disallow settings')) ->loadOptions(array( 'hide' => ___('Remove It From Signup Form'), 'display' => ___('Display It Anyway') )); $form->addCheckboxedGroup('empty-option') ->setLabel(___("Add an 'empty' option to select box\nto do not choose any products")) ->addText('empty-option-text'); $form->addAdvCheckbox('hide_if_one') ->setLabel(___("Hide Select\n" . 'if there is only one choice')); $form->addAdvRadio('require') ->setLabel(___('Require Behaviour')) ->loadOptions(array( self::REQUIRE_DEFAULT => sprintf('%s: %s', ___('Default'), ___('Make this Brick Required Only in Case There is not any Required Brick on Page Above It')), self::REQUIRE_ALWAYS => sprintf('%s: %s', ___('Always'), ___('Force User to Choose Some Product from this Brick')), self::REQUIRE_NEVER => sprintf('%s: %s', ___('Never'), ___('Products in this Brick is Optional (Not Required)')), self::REQUIRE_ALTERNATE => sprintf('%s: %s', ___('Alternate'), ___('User can Choose Product in any Brick of Such Type on Page but he Should Choose at least One Product still')))) ->setValue(self::REQUIRE_DEFAULT); $formId = $form->getId(); $script = <<addScript()->setScript($script); $form->addAdvCheckbox('no_label')->setLabel(___('Remove Label')); } public function formValidate(array $values) { foreach ($values as $k => $v) if (strpos($k, 'product_id') === 0) if (!empty($v)) return; return $this->___('Please choose a membership type'); } public function isAcceptableForForm(Am_Form_Bricked $form) { return $form instanceof Am_Form_Signup; } public function isMultiple() { return true; } } class Am_Form_Brick_Paysystem extends Am_Form_Brick { protected $labels = array( 'Payment System', 'Please choose a payment system', ); protected $hide_if_one = false; protected $hideIfLoggedInPossible = self::HIDE_DONT; public function __construct($id = null, $config = null) { $this->name = ___('Payment System'); parent::__construct($id, $config); } function renderPaysys(Am_Paysystem_Description $p) { return sprintf('%s %s', $p->getId(), ___($p->getTitle()), $p->getId(), ___($p->getDescription())); } public function getPaysystems() { $psList = Am_Di::getInstance()->paysystemList->getAllPublic(); $_psList = array(); foreach ($psList as $k => $ps) { $_psList[$ps->getId()] = $ps; } $psEnabled = $this->getConfig('paysystems', array_keys($_psList)); $event = new Am_Event(Am_Event::SIGNUP_FORM_GET_PAYSYSTEMS); $event->setReturn($psEnabled); Am_Di::getInstance()->hook->call($event); $psEnabled = $event->getReturn(); //we want same order of paysystems as in $psEnabled $ret = array(); foreach ($psEnabled as $psId) { if (isset($_psList[$psId])) $ret[] = $_psList[$psId]; } return $ret; } public function insertBrick(HTML_QuickForm2_Container $form) { $paysystems = $this->getPaysystems(); if ((count($paysystems) == 1) && $this->getConfig('hide_if_one')) { reset($paysystems); $form->addHidden('paysys_id')->setValue(current($paysystems)->getId())->toggleFrozen(true); return; } $psOptions = $psHide = $psIndex = array(); foreach ($paysystems as $ps) { $psOptions[$ps->getId()] = $this->renderPaysys($ps); $psIndex[$ps->getId()] = $ps; $psHide[$ps->getId()] = Am_Di::getInstance()->plugins_payment->loadGet($ps->getId())->hideBricks(); } $psHide = json_encode($psHide); if (count($paysystems) != 1) { $attrs = array('id' => 'paysys_id'); $el0 = $el = $form->addAdvRadio('paysys_id', array('id' => 'paysys_id'), array('intrinsic_validation' => false)); $first = 0; foreach ($psOptions as $k => $v) { $attrs = array( 'data-recurring' => json_encode((bool)$psIndex[$k]->isRecurring()) ); if (!$first++ && Am_Di::getInstance()->request->isGet()) $attrs['checked'] = 'checked'; $el->addOption($v, $k, $attrs); } } else { /** @todo display html here */ reset($psOptions); $el = $form->addStatic('_paysys_id', array('id' => 'paysys_id'))->setContent(current($psOptions)); $el->toggleFrozen(true); $el0 = $form->addHidden('paysys_id')->setValue(key($psOptions)); } $el0->addRule('required', $this->___('Please choose a payment system'), // the following is added to avoid client validation if select is hidden null, HTML_QuickForm2_Rule::SERVER); $el0->addFilter('filterId'); $el->setLabel($this->___('Payment System')); /** * hide payment system selection if: * - there are only free products in the form * - there are selected products, and all of them are free * - option product_psysytem is enabled and user choose product with assign payment system */ $form->addScript()->setScript(<<0) || (jQuery(this).data('second_price')>0)) count_paid++; else count_free++; if (jQuery(this).data('second_price')>0) count_recurring++; if (jQuery(this).data('paysys')) count_paysys++; else count_no_paysys++; }); jQuery(":checkbox[name^='product_id'], select[name^='product_id'] option, :radio[name^='product_id'], input[type=hidden][name^='product_id']").each(function(){ if ((jQuery(this).data('first_price')>0) || (jQuery(this).data('second_price')>0)) total_count_paid++; else total_count_free++; if (jQuery(this).data('paysys')) total_count_paysys++; else total_count_no_paysys++; }); if (count_recurring) { jQuery('[type=radio][name=paysys_id]').each(function(){ if (!$(this).data('recurring') && this.checked) { $("[name='paysys_id'][data-recurring=true]:first").prop('checked', true); } $(this).closest('label').toggle($(this).data('recurring')); }) } else { jQuery('[type=radio][name=paysys_id]').closest('label').show(); } if ( ((count_free && !count_paid) || (!total_count_paid && total_count_free) || (!total_count_no_paysys && total_count_paysys) || (count_paysys)) && (total_count_paid + total_count_free)>0) { // hide select jQuery("#row-paysys_id").hide().after(""); } else { // show select jQuery("#row-paysys_id").show(); jQuery(".hidden-paysys_id").remove(); } }).change(); window.psHiddenBricks = []; jQuery("input[name='paysys_id']").change(function(){ if (!this.checked) return; var val = jQuery(this).val(); var hideBricks = $psHide; jQuery.each(window.psHiddenBricks, function(k,v){ jQuery('#row-'+v+'-0').show(); }); window.psHiddenBricks = hideBricks[val]; if (window.psHiddenBricks) { jQuery.each(window.psHiddenBricks, function(k,v){ jQuery('#row-'+v+'-0').hide(); }); } }).change(); }); CUT ); } public function isAcceptableForForm(Am_Form_Bricked $form) { return $form instanceof Am_Form_Signup; } public function initConfigForm(Am_Form $form) { Am_Di::getInstance()->plugins_payment->loadEnabled(); $ps = $form->addSortableMagicSelect('paysystems') ->setLabel(___("Payment Options\n" . 'if none selected, all enabled will be displayed')) ->loadOptions(Am_Di::getInstance()->paysystemList->getOptionsPublic()); $form->addAdvCheckbox('hide_if_one') ->setLabel(___("Hide Select\n" . 'if there is only one choice')); } } class Am_Form_Brick_Recaptcha extends Am_Form_Brick { protected $name = 'reCAPTCHA'; protected $labels = array( 'Anti Spam', 'Anti Spam check failed' ); /** @var HTML_QuickForm2_Element_Static */ protected $static; public function initConfigForm(Am_Form $form) { $form->addSelect('theme') ->setLabel(___("reCAPTCHA Theme")) ->loadOptions(array('light' => 'light', 'dark' => 'dark')); $form->addSelect('size') ->setLabel(___("reCAPTCHA Size")) ->loadOptions(array('normal' => 'normal', 'compact' => 'compact')); } public function insertBrick(HTML_QuickForm2_Container $form) { $captcha = $form->addGroup() ->setLabel($this->___("Anti Spam")); $captcha->addRule('callback', $this->___('Anti Spam check failed'), array($this, 'validate')); $this->static = $captcha->addStatic('captcha')->setContent(Am_Di::getInstance()->recaptcha ->render($this->getConfig('theme'), $this->getConfig('size'))); } public static function createAvailableBricks($className) { return Am_Recaptcha::isConfigured() ? parent::createAvailableBricks($className) : array(); } public function validate() { $form = $this->static; while ($np = $form->getContainer()) $form = $np; foreach ($form->getDataSources() as $ds) { if ($resp = $ds->getValue('g-recaptcha-response')) break; } $status = false; if ($resp) $status = Am_Di::getInstance()->recaptcha->validate($resp); return $status; } } class Am_Form_Brick_Coupon extends Am_Form_Brick { protected $labels = array( 'Enter coupon code', 'No coupons found with such coupon code', 'Please enter coupon code' ); protected $hideIfLoggedInPossible = self::HIDE_DONT; public function __construct($id = null, $config = null) { $this->name = ___('Coupon'); parent::__construct($id, $config); } public function initConfigForm(Am_Form $form) { $form->addAdvCheckbox('required') ->setLabel(___('Required')); } public function insertBrick(HTML_QuickForm2_Container $form) { $coupon = $form->addText('coupon', array('size' => 15)) ->setLabel($this->___('Enter coupon code')); if ($this->getConfig('required')) { $coupon->addRule('required', $this->___('Please enter coupon code')); } $coupon->addRule('callback2', '--error--', array($this, 'validateCoupon')) ->addRule('remote', '--error--', array( 'url' => Am_Di::getInstance()->url('ajax', array('do'=>'check_coupon'), false), )); } function validateCoupon($value) { if ($value == "") return null; $coupon = htmlentities($value); $coupon = Am_Di::getInstance()->couponTable->findFirstByCode($coupon); $msg = $coupon ? $coupon->validate(Am_Di::getInstance()->auth->getUserId()) : $this->___('No coupons found with such coupon code'); return $msg === null ? null : $msg; } public function isAcceptableForForm(Am_Form_Bricked $form) { return $form instanceof Am_Form_Signup; } } class Am_Form_Brick_Field extends Am_Form_Brick { const TYPE_NORMAL = 'normal'; const TYPE_READONLY = 'disabled'; const TYPE_HIDDEN = 'hidden'; protected $field = null; static function createAvailableBricks($className) { $res = array(); foreach (Am_Di::getInstance()->userTable->customFields()->getAll() as $field) { if (strpos($field->name, 'aff_') === 0) continue; // Do not create bricks for fields started with _ if (strpos($field->name, '_') === 0) continue; $res[] = new self('field-' . $field->getName()); } return $res; } public function __construct($id = null, $config = null) { $fieldName = str_replace('field-', '', $id); $this->field = Am_Di::getInstance()->userTable->customFields()->get($fieldName); // to make it fault-tolerant when customfield is deleted if (!$this->field) $this->field = new Am_CustomFieldText($fieldName, $fieldName); $this->labels = array($this->field->title, $this->field->description); parent::__construct($id, $config); } function getName() { return $this->field->title; } function insertBrick(HTML_QuickForm2_Container $form) { if (!$this->getConfig('skip_access_check') && isset($this->field->from_config) && $this->field->from_config) { $hasAccess = Am_Di::getInstance()->auth->getUserId() ? Am_Di::getInstance()->resourceAccessTable->userHasAccess(Am_Di::getInstance()->auth->getUser(), amstrtoint($this->field->name), Am_CustomField::ACCESS_TYPE) : Am_Di::getInstance()->resourceAccessTable->guestHasAccess(amstrtoint($this->field->name), Am_CustomField::ACCESS_TYPE); if (!$hasAccess) return; } $this->field->title = $this->___($this->field->title); $this->field->description = $this->___($this->field->description); if ($this->getConfig('validate_custom')) { $this->field->validateFunc = $this->getConfig('validate_func'); } switch ($this->getConfig('display_type', self::TYPE_NORMAL)) { case self::TYPE_HIDDEN : $v = $this->getConfig('value'); $form->addHidden($this->field->getName()) ->setValue($v ? $v : @$this->field->default); break; case self::TYPE_READONLY : $el = $this->field->addToQF2($form); $el->toggleFrozen(true); break; case self::TYPE_NORMAL : $this->field->addToQF2($form); break; default: throw new Am_Exception_InternalError(sprintf('Unknown display type [%s] in %s::%s', $this->getConfig('display_type', self::TYPE_NORMAL), __CLASS__, __METHOD__)); } if ($this->getConfig('cond_enabled')) { $c_cond = $this->getConfig('cond_type') > 0 ? '==' : '!='; $c_field_val = json_encode($this->getConfig('cond_field_val')); $c_field_name = $this->getConfig('cond_field'); $name = $this->field->name; $form->addScript() ->setScript(<< 1 ? el.filter("[value='" + $c_field_val + "']").val() : el.val(); break; } val = val || 0; jQuery('[name=$name]').closest('.row').toggle(val $c_cond $c_field_val); }).change(); CUT ); } } function getFieldName() { return $this->field->name; } public function initConfigForm(Am_Form $form) { $id = $this->field->name . '-display-type'; $id_value = $this->field->name . '-value'; $form->addSelect('display_type') ->setLabel(___('Display Type')) ->setId($id) ->loadOptions(array( self::TYPE_NORMAL => ___('Normal'), self::TYPE_READONLY => ___('Read-only'), self::TYPE_HIDDEN => ___('Hidden') )); $form->addText('value', array( 'placeholder' => ___('Keep empty to use default value from field settings'), 'class' => 'el-wide' )) ->setId($id_value) ->setLabel(___("Default Value for this field\n" . 'hidden field will be populated with this value')); $type_hidden = self::TYPE_HIDDEN; $form->addScript() ->setScript(<<field->name . '-validate_custom'; $id_validate_func = $this->field->name . '-validate_func'; $form->addAdvCheckbox('validate_custom', array('id' => $id_validate_custom)) ->setLabel(___("Use Custom Validation Settings\n" . 'otherwise Validation settings from field definition is used')); $form->addMagicSelect('validate_func', array('id' => $id_validate_func)) ->setLabel(___('Validation')) ->loadOptions(array( 'required' => ___('Required Value'), 'integer' => ___('Integer Value'), 'numeric' => ___('Numeric Value'), 'email' => ___('E-Mail Address'), 'emails' => ___('List of E-Mail Address'), 'url' => ___('URL'), 'ip' => ___('IP Address') )); $form->addScript() ->setScript(<<addAdvCheckbox('skip_access_check') ->setLabel(___("Do not check Access Permissions\n" . "for this field on this form (show it without any conditions)")); list($fields, $allOp) = $this->getEnumFieldOptions($this->field->name); if ($fields) { $allOp = json_encode($allOp); $current_val = json_encode($this->getConfig('cond_field_val')); $gr = $form->addGroup(); $gr->setLabel(___('Conditional')); $gr->setSeparator(' '); $gr->addAdvCheckbox('cond_enabled'); $gr->addSelect('cond_type') ->loadOptions(array( '1' => ___('Show'), '-1' => ___('Hide') )); $l_if = ___('if'); $gr->addHtml() ->setHtml(" $l_if "); $gr->addSelect('cond_field') ->loadOptions($fields); $gr->addHtml() ->setHtml(' = '); $gr->addSelect('cond_field_val', null, array('intrinsic_validation' => false)) ->loadOptions(array()); $id = $form->getId(); $gr->addScript() ->setScript(<<').text(cOpt[k]).attr('value', k) ); } if (current_val != undefined) { $("#$id [name=cond_field_val]").val(current_val); current_val = undefined; } else { $("#$id [name=cond_field_val]").val($("#$id [name=cond_field_val] option:first").attr('value')); } }).change(); }); CUT ); } } function getEnumFieldOptions($myName) { $fields = array(); $options = array(); foreach (Am_Di::getInstance()->userTable->customFields()->getAll() as $fd) { if ($myName == $fd->name) continue; if (in_array($fd->type, array('radio', 'select', 'checkbox', 'single_checkbox'))) { $fields[$fd->name] = $fd->title; $options[$fd->name] = $fd->type == 'single_checkbox' ? array(1 => ___('Checked'), 0 => ___('Unchecked')) : $fd->options; } } return array($fields, $options); } public function setConfigArray(array $config) { //backwards compatiability if (isset($config['disabled'])) { $config['display_type'] = $config['disabled'] ? self::TYPE_READONLY : self::TYPE_NORMAL; unset($config['disabled']); } if (!isset($config['display_type'])) $config['display_type'] = self::TYPE_NORMAL; parent::setConfigArray($config); } } class Am_Form_Brick_Agreement extends Am_Form_Brick { protected $labels = array( 'User Agreement', 'I have read and agree to the Terms & Conditions', 'Please agree to User Agreement', ); public function __construct($id = null, $config = null) { $this->name = ___('User Agreement'); parent::__construct($id, $config); } public function insertBrick(HTML_QuickForm2_Container $form) { if (($form instanceof Am_Form_Signup_Aff) || ($form->getId() == 'aff')) { // little trick - if we are in affiliate form, replace word "User" to "Affiliate" $this->labels['User Agreement'] = ___('Affiliate Agreement'); $this->labels['Please agree to User Agreement'] = ___('Please agree to Affiliate Agreement'); } if ($this->getConfig('do_not_show_agreement_text')) { $conteiner = $form; } else { $conteiner = $form->addFieldset()->setId('fieldset-agreement')->setLabel($this->___('User Agreement')); $agreement = $conteiner->addStatic('_agreement', array('class' => 'no-label')); $agreement->setContent('
' . $this->getText() . '
'); } $data = array(); if ($this->getConfig('no_label')) { $data['content'] = $this->___('I have read and agree to the Terms & Conditions'); } $checkbox = $conteiner->addAdvCheckbox('i_agree', array(), $data); if (!$this->getConfig('no_label')) { $checkbox->setLabel($this->___('I have read and agree to the Terms & Conditions')); } $checkbox->addRule('required', $this->___('Please agree to User Agreement')); if ($this->getConfig('checked')) { $checkbox->setAttribute('checked'); } } public function getText() { return $this->getConfig('isHtml') ? $this->getConfig('text') : Am_Html::escape($this->getConfig('text')); } public function isAcceptableForForm(Am_Form_Bricked $form) { return $form instanceof Am_Form_Signup; } public function initConfigForm(Am_Form $form) { $form->addAdvCheckbox("do_not_show_agreement_text") ->setLabel(___("Does not show Agreement Text\n" . 'display only tick box')) ->setId('do-not-show-agreement-text'); $form->addAdvCheckbox("isHtml") ->setLabel(___('Is Html?')) ->setAttribute('rel', 'agreement-text'); $form->addTextarea("text", array('rows' => 20, 'class' => 'el-wide')) ->setLabel(___('Agreement text')) ->setAttribute('rel', 'agreement-text'); $form->addScript() ->setScript(<<addAdvCheckbox('no_label') ->setLabel(___("Hide Label")); $form->addAdvCheckbox('checked') ->setLabel(___("Checked by Default")); } } class Am_Form_Brick_PageSeparator extends Am_Form_Brick { protected $labels = array( 'title', 'back', 'next', ); protected $hideIfLoggedInPossible = self::HIDE_DONT; public function __construct($id = null, $config = null) { $this->name = ___('Form Page Break'); parent::__construct($id, $config); } public function insertBrick(HTML_QuickForm2_Container $form) { // nop; } public function isAcceptableForForm(Am_Form_Bricked $form) { return (bool)$form->isMultiPage(); } public function isMultiple() { return true; } } class Am_Form_Brick_UserGroup extends Am_Form_Brick { protected $hideIfLoggedInPossible = self::HIDE_DONT; public function init() { Am_Di::getInstance()->hook->add(Am_Event::SIGNUP_USER_ADDED, array($this, 'assignGroups')); Am_Di::getInstance()->hook->add(Am_Event::SIGNUP_USER_UPDATED, array($this, 'assignGroups')); } public function assignGroups(Am_Event $event) { /* @var $user User */ $user = $event->getUser(); $existing = $user->getGroups(); $new = $this->getConfig('groups', array()); $user->setGroups(array_unique(array_merge($existing, $new))); } public function __construct($id = null, $config = null) { $this->name = ___('Assign User Groups (HIDDEN)'); parent::__construct($id, $config); } public function isAcceptableForForm(Am_Form_Bricked $form) { return $form instanceof Am_Form_Signup; } public function initConfigForm(Am_Form $form) { $form->addMagicSelect('groups') ->loadOptions(Am_Di::getInstance()->userGroupTable->getSelectOptions()) ->setLabel(___('Add user to these groups')); } public function insertBrick(HTML_QuickForm2_Container $form) { // nothing to do. } } class Am_Form_Brick_ManualAccess extends Am_Form_Brick { protected $hideIfLoggedInPossible = self::HIDE_DONT; public function init() { Am_Di::getInstance()->hook->add(Am_Event::SIGNUP_USER_ADDED, array($this, 'addAccess')); } public function addAccess(Am_Event $event) { /* @var $user User */ $user = $event->getUser(); $product_ids = $this->getConfig('product_ids'); if (!$product_ids) return; foreach ($product_ids as $id) { $product = Am_Di::getInstance()->productTable->load($id, false); if (!$product) continue; //calucalet access dates $invoice = Am_Di::getInstance()->invoiceRecord; $invoice->setUser($user); $invoice->add($product); $begin_date = $product->calculateStartDate(Am_Di::getInstance()->sqlDate, $invoice); $p = new Am_Period($product->getBillingPlan()->first_period); $expire_date = $p->addTo($begin_date); $access = Am_Di::getInstance()->accessRecord; $access->setForInsert(array( 'user_id' => $user->pk(), 'product_id' => $product->pk(), 'begin_date' => $begin_date, 'expire_date' => $expire_date, 'qty' => 1 )); $access->insert(); Am_Di::getInstance()->emailTemplateTable->sendZeroAutoresponders($user, $access); } } public function __construct($id = null, $config = null) { $this->name = ___('Add Subscription Before Payment (HIDDEN)'); parent::__construct($id, $config); } public function isAcceptableForForm(Am_Form_Bricked $form) { return $form instanceof Am_Form_Signup; } public function initConfigForm(Am_Form $form) { $form->addMagicSelect('product_ids') ->loadOptions(Am_Di::getInstance()->productTable->getOptions()) ->setLabel(___( "Add Subscription to the following products\n" . "right after signup form has been submitted, " . "subscription will be added only for new users")); } public function insertBrick(HTML_QuickForm2_Container $form) { // nothing to do. } } class Am_Form_Brick_Fieldset extends Am_Form_Brick { protected $labels = array( 'Fieldset title' ); public function __construct($id = null, $config = null) { $this->name = ___('Fieldset'); parent::__construct($id, $config); } public function insertBrick(HTML_QuickForm2_Container $form) { $fieldSet = $form->addElement('fieldset', 'fieldset')->setLabel($this->___('Fieldset title')); } public function isMultiple() { return true; } } class Am_Form_Brick_RandomQuestions extends Am_Form_Brick { protected $labels = array( 'Please answer above question', 'Your answer is wrong' ); public function __construct($id = null, $config = null) { $this->name = ___('Random Questions'); parent::__construct($id, $config); } public function isMultiple() { return false; } public function insertBrick(HTML_QuickForm2_Container $form) { if (!$this->getConfig('questions')) return; $questions = array(); foreach (explode(PHP_EOL, $this->getConfig('questions')) as $line) { $line = explode('|', $line); $questions[] = array_shift($line); } $q_id = array_rand($questions); $question = $form->addText('question') ->setLabel($questions[$q_id] . "\n" . $this->___('Please answer above question')); $question->addRule('callback', $this->___('Your answer is wrong'), array($this, 'validate')); $form->addHidden('q_id')->setValue($q_id)->toggleFrozen(true); //setValue does not work right second time $_POST['q_id_sent'] = @$_POST['q_id']; $_POST['q_id'] = $q_id; } public function initConfigForm(Am_Form $form) { $form->addTextarea('questions', array('rows' => 10, 'class'=>'el-wide')) ->setLabel(___("Questions with possible answers\n" . "one question per line\n" . "question and answers should be\n" . "separated by pipe, for example\n" . "Question1?|Answer1|Answer2|Answer3\n" . "Question2?|Answer1|Answer2\n" . "register of answers does not matter")); } public function validate($answer) { if (!$answer) return false; $lines = explode(PHP_EOL, $this->getConfig('questions')); $line = $lines[(isset($_POST['q_id_sent']) ? $_POST['q_id_sent'] : $_POST['q_id'])]; $q_ = explode('|', strtolower(trim($line))); array_shift($q_); if (@in_array(strtolower($answer), $q_)) return true; else return false; } } class Am_Form_Brick_Unsubscribe extends Am_Form_Brick { protected $labels = array( 'Unsubscribe from all e-mail messages' ); public function init() { Am_Di::getInstance()->hook->add(Am_Event::PROFILE_USER_UPDATED, array($this, 'triggerEvent')); } public function insertBrick(HTML_QuickForm2_Container $form) { $form->addAdvCheckbox('unsubscribed') ->setLabel($this->___('Unsubscribe from all e-mail messages')); } public function isAcceptableForForm(Am_Form_Bricked $form) { return $form instanceof Am_Form_Profile; } public function triggerEvent(Am_Event $e) { $oldUser = $e->getOldUser(); $user = $e->getUser(); if ($oldUser->unsubscribed != $user->unsubscribed) { Am_Di::getInstance()->hook->call(Am_Event::USER_UNSUBSCRIBED_CHANGED, array('user'=>$user, 'unsubscribed' => $user->unsubscribed)); } } } class Am_Form_Brick_VatId extends Am_Form_Brick { protected $labels = array( 'VAT Settings are incorrect - no Vat Id configured', 'Invalid VAT Id, please try again', 'Cannot validate VAT Id, please try again', 'Invalid EU VAT Id format', 'EU VAT Id (optional)', 'Please enter EU VAT Id' ); public function initConfigForm(Am_Form $form) { $form->addAdvCheckbox('dont_validate')->setLabel(___('Disable online VAT Id Validation')); $form->addAdvCheckbox('required')->setLabel(___('Required')); } public function insertBrick(HTML_QuickForm2_Container $form) { $el = $form->addText('tax_id')->setLabel($this->___("EU VAT Id (optional)")) ->addFilter(function($value) { return str_replace(' ', '', $value); }) ->addRule('regex', $this->___('Invalid EU VAT Id format'), '/^[A-Za-z]{2}[a-zA-Z0-9\s]+$/'); if (!$this->getConfig('dont_validate')) $el->addRule('callback2', '-error-', array($this, 'validate')); if ($this->getConfig('required')) $el->addRule('required', $this->___("Please enter EU VAT Id")); } public function validate($id) { if (!$id) return; //skip validation in case of VAT was not supplied $plugins = Am_Di::getInstance()->plugins_tax->getAllEnabled(); $me = is_array($plugins) ? $plugins[0]->getConfig('my_id') : ""; if (!$me) return $this->___('VAT Settings are incorrect - no Vat Id configured'); // check if response is cached $cacheKey = 'vat_check_' . preg_replace('/[^A-Z0-9a-z_]/', '_', $me) . '_' . preg_replace('/[^A-Z0-9a-z_]/', '_', $id); if (($ret = Am_Di::getInstance()->cache->load($cacheKey)) !== false) return $ret === 1 ? null : $this->___('Invalid VAT Id, please try again'); if (!strlen($id)) return $this->___('Invalid VAT Id, please try again'); $req = new Am_HttpRequest('http://ec.europa.eu/taxation_customs/vies/vatResponse.html', Am_HttpRequest::METHOD_POST); $req->addPostParameter('action', 'check') ->addPostParameter('check', 'Verify') ->addPostParameter('memberStateCode', strtoupper(substr($id, 0, 2))) ->addPostParameter('number', substr($id, 2)) ->addPostParameter('requesterMemberStateCode', '') ->addPostParameter('traderName', '') ->addPostParameter('traderCompanyType', '') ->addPostParameter('traderStreet', '') ->addPostParameter('traderPostalCode', '') ->addPostParameter('traderCity', '') ->addPostParameter('requesterNumber', ''); try { $resp = $req->send(); $ok = strpos($resp->getBody(), 'invalidStyle') === false; Am_Di::getInstance()->cache->save($ok ? 1 : 0, $cacheKey); if (!$ok) return $this->___('Invalid VAT Id, please try again'); } catch (Exception $e) { Am_Di::getInstance()->errorLogTable->log($e); return $this->___("Cannot validate VAT Id, please try again"); } } } class Am_Form_Brick_InvoiceSummary extends Am_Form_Brick { protected $hideIfLoggedInPossible = self::HIDE_DONT; public function __construct($id = null, $config = null) { $this->name = ___('Invoice Summary'); parent::__construct($id, $config); } public function initConfigForm(Am_Form $form) { $form->addSelect('position', array('class' => 'invoice-summary-position')) ->loadOptions(array( 'above' => ___('Above Form'), 'below' => ___('Below Form'), 'brick' => ___('Brick Position'), 'custom' => ___('Custom Element') ))->setLabel('Position'); $form->addText('selector', array('placeholder' => '#invoice-summary')) ->setLabel(___('CSS Selector for conteiner')); $form->addScript() ->setScript(<<getConfig('position', 'above')) { case 'above' : $form->addProlog('
'); break; case 'below' : $form->addEpilog('
'); break; case 'brick' : $form->addHtml(null, array('class'=>'row-wide')) ->setHtml('
'); break; default: $selector = $this->getConfig('selector', '#invoice-summary') ?: '#invoice-summary'; } $url = Am_Di::getInstance()->url('ajax/invoice-summary',null,false); $form->addScript() ->setScript(<<setHeader('Cache-Control', 'maxage=3600') ->setHeader('Pragma', 'no-cache') ->setHeader('Content-type', 'text/csv') ->setHeader('Content-Disposition', 'attachment; filename=' . $filename); foreach ($rows as & $r) { if (is_array($r)) { $out = ""; foreach ($r as $s) $out .= ( $out ? $delimiter : "") . amEscapeCsv($s, $delimiter); $out .= "\r\n"; $r = $out; } } $response->appendBody(implode("", $rows)); } abstract function export(AffPayout $payout, Am_Query $details, Am_Mvc_Response $response); static function static_addFields() { $fieldsManager = Am_Di::getInstance()->userTable->customFields(); foreach (self::getEnabled() as $o) $o->addFields($fieldsManager); } /** @return Am_Aff_PayoutMethod[] */ static function getEnabled() { if (!self::$enabled) foreach (Am_Di::getInstance()->config->get('aff.payout_methods', array()) as $methodName) { $className = __CLASS__ . '_' . ucfirst($methodName); if (!class_exists($className)) continue; $o = new $className; self::$enabled[$o->getId()] = $o; } return self::$enabled; } static function getAvailableOptions() { $ret = array(); foreach (get_declared_classes () as $className) if (strpos($className, __CLASS__ . '_') === 0) { $o = new $className; $ret[$o->getId()] = $o->getTitle(); } $event = new Am_Event(Bootstrap_Aff::AFF_GET_PAYOUT_OPTIONS); $event->setReturn($ret); Am_Di::getInstance()->hook->call($event); return $event->getReturn(); } static function getEnabledOptions() { $ret = array(); foreach (self::getEnabled() as $o) $ret[$o->getId()] = $o->getTitle(); return $ret; } } class Am_Aff_PayoutMethod_Paypal extends Am_Aff_PayoutMethod { public function export(AffPayout $payout, Am_Query $details, Am_Mvc_Response $response) { $q = $details->query(); while ($d = $payout->getDi()->db->fetchRow($q)) { $d = $payout->getDi()->affPayoutDetailTable->createRecord($d); /* @var $d AffPayoutDetail */ $aff = $d->getAff(); $rows[] = array( $aff->data()->get('aff_paypal_email'), moneyRound($d->amount), Am_Currency::getDefault(), $aff->user_id, "Affiliate commission to " . amDate($payout->thresehold_date), ); } $this->sendCsv("paypal-commission-" . $payout->payout_id . ".csv", $rows, $response); } public function addFields(Am_CustomFieldsManager $m) { $m->add(new Am_CustomFieldText('aff_paypal_email', ___('Affiliate Payout - Paypal E-Mail address'), ___('for affiliate commission payouts')))->size = 40; } } class Am_Aff_PayoutMethod_Webmoney extends Am_Aff_PayoutMethod { public function export(AffPayout $payout, Am_Query $details, Am_Mvc_Response $response) { $q = $details->query(); while ($d = $payout->getDi()->db->fetchRow($q)) { $d = $payout->getDi()->affPayoutDetailTable->createRecord($d); /* @var $d AffPayoutDetail */ $aff = $d->getAff(); $rows[] = array( $aff->data()->get('aff_webmoney_purse'), moneyRound($d->amount), Am_Currency::getDefault(), $aff->user_id, "Affiliate commission to " . amDate($payout->thresehold_date), ); } $this->sendCsv("webmoney-commission-" . $payout->payout_id . ".csv", $rows, $response); } public function addFields(Am_CustomFieldsManager $m) { $m->add(new Am_CustomFieldText('aff_webmoney_purse', ___('Affiliate Payout - WM purse'), ___('for affiliate commission payouts')))->size = 40; } } class Am_Aff_PayoutMethod_Check extends Am_Aff_PayoutMethod { public function getTitle() { return ___("Offline Check"); } public function export(AffPayout $payout, Am_Query $details, Am_Mvc_Response $response) { $q = $details->query(); $rows = array(array( ___("Check Payable To"), ___("Street"), ___("City"), ___("State"), ___("Country"), ___("ZIP"), ___("Amount"), ___("Currency"), ___("Comment"), ___("Username"), )); while ($d = $payout->getDi()->db->fetchRow($q)) { $d = $payout->getDi()->affPayoutDetailTable->createRecord($d); /* @var $d AffPayoutDetail */ $aff = $d->getAff(); $rows[] = array( $aff->data()->get('aff_check_payable_to'), $aff->data()->get('aff_check_street'), $aff->data()->get('aff_check_city'), $aff->data()->get('aff_check_state'), $aff->data()->get('aff_check_country'), $aff->data()->get('aff_check_zip'), moneyRound($d->amount), Am_Currency::getDefault(), ___("Affiliate commission to %s", amDate($payout->thresehold_date)), $aff->login, ); } $this->sendCsv("check-commission-" . $payout->payout_id . ".csv", $rows, $response); } public function addFields(Am_CustomFieldsManager $m) { $m->add(new Am_CustomFieldText('aff_check_payable_to', ___('Affiliate Check - Payable To')))->size = 40; $m->add(new Am_CustomFieldText('aff_check_street', ___('Affiliate Check - Street Address')))->size = 40; $m->add(new Am_CustomFieldText('aff_check_city', ___('Affiliate Check - City')))->size = 40; $m->add(new Am_CustomFieldText('aff_check_country', ___('Affiliate Check - Country'))); $m->add(new Am_CustomFieldText('aff_check_state', ___('Affiliate Check - State'))); $m->add(new Am_CustomFieldText('aff_check_zip', ___('Affiliate Check - ZIP Code')))->size = 10; } } class Am_Aff_PayoutMethod_Bacs extends Am_Aff_PayoutMethod { public function getTitle() { return ___("BACS"); } public function export(AffPayout $payout, Am_Query $details, Am_Mvc_Response $response) { $q = $details->query(); $rows = array(array( ___("Bank name"), ___("Account holder name"), ___("Account number"), ___("Sort code"), ___("Amount"), ___("Currency"), ___("Comment"), ___("Username"), )); while ($d = $payout->getDi()->db->fetchRow($q)) { $d = $payout->getDi()->affPayoutDetailTable->createRecord($d); /* @var $d AffPayoutDetail */ $aff = $d->getAff(); $rows[] = array( $aff->data()->get('aff_bacs_bank_name'), $aff->data()->get('aff_bacs_account_holder_name'), $aff->data()->get('aff_bacs_caccount_number'), $aff->data()->get('aff_bacs_sort_code'), moneyRound($d->amount), Am_Currency::getDefault(), ___("Affiliate commission to %s", amDate($payout->thresehold_date)), $aff->login, ); } $this->sendCsv("check-commission-" . $payout->payout_id . ".csv", $rows, $response); } public function addFields(Am_CustomFieldsManager $m) { $m->add(new Am_CustomFieldText('aff_bacs_bank_name', ___('Affiliate BACS - Bank name'))); $m->add(new Am_CustomFieldText('aff_bacs_account_holder_name', ___('Affiliate BACS - Account holder name'))); $m->add(new Am_CustomFieldText('aff_bacs_caccount_number', ___('Affiliate BACS - Account number'))); $m->add(new Am_CustomFieldText('aff_bacs_sort_code', ___('Affiliate BACS - Sort code'))); } } class Am_Aff_PayoutMethod_Moneybookers extends Am_Aff_PayoutMethod { public function getTitle() { return 'Skrill'; } public function export(AffPayout $payout, Am_Query $details, Am_Mvc_Response $response) { $q = $details->query(); $rows = array(array( ___("Skrill E-Mail"), ___("Amount"), ___("Currency"), ___("Comment"), ___("Username"), )); while ($d = $payout->getDi()->db->fetchRow($q)) { $d = $payout->getDi()->affPayoutDetailTable->createRecord($d); /* @var $d AffPayoutDetail */ $aff = $d->getAff(); $rows[] = array( $aff->data()->get('aff_moneybookers_email'), moneyRound($d->amount), Am_Currency::getDefault(), ___("Affiliate commission to %s", amDate($payout->thresehold_date)), $aff->login, ); } $this->sendCsv("check-commission-" . $payout->payout_id . ".csv", $rows, $response); } public function addFields(Am_CustomFieldsManager $m) { $m->add(new Am_CustomFieldText('aff_moneybookers_email', ___('Affiliate Payout - Skrill Account ID')))->size = 40; } } class Am_Aff_PayoutMethod_Propay extends Am_Aff_PayoutMethod { public function export(AffPayout $payout, Am_Query $details, Am_Mvc_Response $response) { $q = $details->query(); while ($d = $payout->getDi()->db->fetchRow($q)) { $d = $payout->getDi()->affPayoutDetailTable->createRecord($d); /* @var $d AffPayoutDetail */ $aff = $d->getAff(); $rows[] = array( $aff->data()->get('aff_propay_email'), moneyRound($d->amount), Am_Currency::getDefault(), $aff->user_id, ___("Affiliate commission to %s", amDate($payout->thresehold_date)), ); } $this->sendCsv("propay-commission-" . $payout->payout_id . ".csv", $rows, $response); } public function addFields(Am_CustomFieldsManager $m) { $m->add(new Am_CustomFieldText('aff_propay_email', ___('Affiliate Payout - Propay E-Mail address'), ___('for affiliate commission payouts')))->size = 40; } } class Am_Aff_PayoutMethod_Okpay extends Am_Aff_PayoutMethod { public function export(AffPayout $payout, Am_Query $details, Am_Mvc_Response $response) { $q = $details->query(); while ($d = $payout->getDi()->db->fetchRow($q)) { $d = $payout->getDi()->affPayoutDetailTable->createRecord($d); /* @var $d AffPayoutDetail */ $aff = $d->getAff(); $rows[] = array( $aff->data()->get('aff_okpay_wallet'), moneyRound($d->amount), Am_Currency::getDefault(), $aff->user_id, ___("Affiliate commission to %s", amDate($payout->thresehold_date)), ); } $this->sendCsv("okpay-commission-" . $payout->payout_id . ".csv", $rows, $response); } public function addFields(Am_CustomFieldsManager $m) { $m->add(new Am_CustomFieldText('aff_okpay_wallet', ___('Affiliate Payout - Okpay Wallet ID'), ___('for affiliate commission payouts')))->size = 40; } } class Am_Aff_PayoutMethod_Pagseguro extends Am_Aff_PayoutMethod { public function export(AffPayout $payout, Am_Query $details, Am_Mvc_Response $response) { $q = $details->query(); while ($d = $payout->getDi()->db->fetchRow($q)) { $d = $payout->getDi()->affPayoutDetailTable->createRecord($d); /* @var $d AffPayoutDetail */ $aff = $d->getAff(); $rows[] = array( $aff->data()->get('aff_pagseguro_email'), moneyRound($d->amount), Am_Currency::getDefault(), $aff->user_id, ___("Affiliate commission to %s", amDate($payout->thresehold_date)), ); } $this->sendCsv("pagseguro-commission-" . $payout->payout_id . ".csv", $rows, $response); } public function addFields(Am_CustomFieldsManager $m) { $m->add(new Am_CustomFieldText('aff_pagseguro_email', ___('Affiliate Payout - Pagseguro E-Mail address'), ___('for affiliate commission payouts')))->size = 40; } } class Am_Aff_PayoutMethod_Bitcoin extends Am_Aff_PayoutMethod { public function export(AffPayout $payout, Am_Query $details, Am_Mvc_Response $response) { $q = $details->query(); while ($d = $payout->getDi()->db->fetchRow($q)) { $d = $payout->getDi()->affPayoutDetailTable->createRecord($d); /* @var $d AffPayoutDetail */ $aff = $d->getAff(); $rows[] = array( $aff->data()->get('aff_bitcoin_wallet'), moneyRound($d->amount), Am_Currency::getDefault(), $aff->user_id, "Affiliate commission to " . amDate($payout->thresehold_date), ); } $this->sendCsv("bitcoint-commission-" . $payout->payout_id . ".csv", $rows, $response); } public function addFields(Am_CustomFieldsManager $m) { $m->add(new Am_CustomFieldText('aff_bitcoin_wallet', ___('Affiliate Payout - Bitcoin Wallet'), ___('for affiliate commission payouts')))->size = 40; } } /** * https://chexxinc.com */ class Am_Aff_PayoutMethod_Chexx extends Am_Aff_PayoutMethod { public function getTitle() { return ___("Chexx"); } public function export(AffPayout $payout, Am_Query $details, Am_Mvc_Response $response) { $q = $details->query(); $rows = array(array( ___("Payment Routing Number"), ___("Payment Type"), ___("Amount"), ___("Currency Code"), ___("Account Name"), ___("IBAN"), ___("BIC"), ___("Reference"), ___("Description"), )); while ($d = $payout->getDi()->db->fetchRow($q)) { $d = $payout->getDi()->affPayoutDetailTable->createRecord($d); /* @var $d AffPayoutDetail */ $aff = $d->getAff(); $rows[] = array( $aff->data()->get('aff_chexx_routing_number'), 'sepa_credit', moneyRound($d->amount), Am_Currency::getDefault(), $aff->data()->get('aff_chexx_account_holder_name'), $aff->data()->get('aff_chexx_iban'), $aff->data()->get('aff_chexx_bic'), $aff->login, ___("Affiliate commission up to %s", amDate($payout->thresehold_date)), ); } $this->sendCsv("chexx-commission-" . $payout->payout_id . ".csv", $rows, $response); } public function addFields(Am_CustomFieldsManager $m) { $m->add(new Am_CustomFieldText('aff_chexx_routing_number', ___('Affiliate Chexx - Payment Routing Number'))); $m->add(new Am_CustomFieldText('aff_chexx_account_holder_name', ___('Affiliate Chexx - Account Holder Name'))); $m->add(new Am_CustomFieldText('aff_chexx_iban', ___('Affiliate Chexx - IBAN'))); $m->add(new Am_CustomFieldText('aff_chexx_bic', ___('Affiliate Chexx - BIC'))); } }PK7\qGrid/Action/Aff/Void.phpnu[title = ___("Void"); $this->attributes['data-confirm'] = ___("Do you really want to void commission?"); parent::__construct($id, $title); } function run() { $form = new Am_Form_Admin('form-vomm-void'); $form->setAttribute('name', 'void'); $comm = $this->grid->getRecord(); $form->addText('amount', array('size' => 6)) ->setlabel(___('Void Amount')); foreach ($this->grid->getVariablesList() as $k) { $form->addHidden($this->grid->getId() . '_' . $k)->setValue($this->grid->getRequest()->get($k, "")); } $g = $form->addGroup(); $g->setSeparator(' '); $g->addSubmit('_save', array('value' => ___("Void"))); $g->addStatic() ->setContent(sprintf('%s', $this->grid->getBackUrl(), ___('Cancel'))); $form->setDataSources(array( $this->grid->getCompleteRequest(), new HTML_QuickForm2_DataSource_Array(array('amount' => $comm->amount)))); if ($form->isSubmitted() && $form->validate()) { $values = $form->getValue(); $this->void($values['amount']); $this->grid->redirectBack(); } else { echo $this->renderTitle(); echo $form; } } public function void($amount) { $record = $this->grid->getRecord(); if(!$record->is_voided) { Am_Di::getInstance()->affCommissionTable->void($record, sqlTime('now'), $amount); } $this->log(); $this->grid->redirectBack(); } public function isAvailable($record) { return (!$record->is_voided && ($record->record_type == AffCommission::COMMISSION)); } }PKx\IOW W Form/Page.phpnu[record = $record; $this->fields = $fields; $this->pageNum = $pageNum; $this->pageTitle = $pageTitle; $this->pageDesc = $pageDesc; $this->lastPage = $lastPage; $this->savedData = $savedData; } public function getTitle() { return $this->record->title; } protected function populateForm() { $default = array(); foreach ($this->fields as $field) { $default = $default + $field->insertField($this->form); } if ($this->pageTitle) { $this->form->addProlog(<<{$this->pageTitle}

{$this->pageDesc}

CUT ); } if (!$this->form->isSubmitted()) { $this->form->setDataSources(array(new HTML_QuickForm2_DataSource_Array($default))); } if (!$this->form->isSubmitted() && $this->savedData) { $ds = $this->form->getDataSources(); array_unshift($ds, new HTML_QuickForm2_DataSource_Array($this->savedData)); $this->form->setDataSources($ds); } $group = $this->form->addGroup(null, 'id="buttons"'); $group->setSeparator(' '); if ($this->pageNum > 0) { $url = $this->getController()->getParentController()->getRequest()->getRequestUri(); $url = preg_replace('/\?.*/', '', $url); $link = Am_Html::escape($url) . '?' . Am_Html::escape($this->getButtonName('back')) . '=1'; $group->addHtml('back')->setHtml("Back"); } if ($this->lastPage) { $group->addSubmit($this->getButtonName('complete'), array('value' => 'Complete')); $group->addSubmit($this->getButtonName('next'), array('value' => 'Save', 'style'=>'float:right')); } else { $group->addSubmit($this->getButtonName('next'), array('value' => 'Next')); $group->addSubmit($this->getButtonName('save'), array('value' => 'Save', 'style'=>'float:right')); } $this->setDefaultAction('next', REL_ROOT_URL.'/application/default/views/public/img/empty.gif'); } public function setDefaultAction($actionName, $imageSrc = '') { parent::setDefaultAction($actionName, $imageSrc); $image = $this->form->getElementById('_qf_default'); if (!$image) return; $image->setAttribute('style', 'display: none;'); } }PKx\ o:Form/Element/Grid.phpnu[ $v) { if ($k == 'rows') continue; if ($k > $vars['rows']-1) unset($vars[$k]); } return $vars; } public function render(HTML_QuickForm2_Renderer $renderer) { $data = $this->getData(); $grid_rows = $data['grid_rows']; $name = $this->getName(); if (!$this->frozen) { $this->addHtml('js') ->setHtml(<<+ Add Item CUT ); } else { $this->addHtml('js') ->setHtml(<< jQuery(function(){ jQuery('#{$name}-table tr').slice(parseInt($('#{$name}-rows').val())+1).hide(); }); CUT ); } $renderer->startGroup($this); foreach ($this as $element) { $element->render($renderer); } $this->renderClientRules($renderer->getJavascriptBuilder()); $renderer->finishGroup($this); return $renderer; } }PKx\aBBForm/Controller/Action/Save.phpnu[storeValues(); $page->getController()->getParentController()->process($page->getController()->getValue(), $name, $page); } }PKx\{CGG#Form/Controller/Action/Complete.phpnu[storeValues(); $page->getController()->getParentController()->complete($page->getController()->getValue(), $name, $page); } }PKx\>Y@ @ Pdf/Cell.phpnu[ 0, self::RIGHT => 0, self::BOTTOM => 0, self::LEFT => 0 ); public function __construct($content) { $this->content = $content; } public function setStyle($styles) { $this->styles = $styles; } public function setWidth($width) { $this->width = $width; } public function setPadding($top=0, $right=0, $bottom=0, $left=0) { $this->padding = array( self::TOP => $top, self::RIGHT => $right, self::BOTTOM => $bottom, self::LEFT => $left ); } public function getPadding($side) { return $this->padding[$side]; } public function getWidth() { return $this->width; } public function render(Am_Pdf_Page_Decorator $page, $x, $y) { if ($font = $this->getProperty('font')) { $fontTmp = $page->getFont(); $fontSizeTmp = $page->getFontSize(); $page->setFont($font['face'], $font['size']); } $lineHeight = $page->getFont()->getLineHeight()/100; $lineBegin = $y - $this->getPadding(self::TOP) - $lineHeight; $width = $this->getWidth() - $this->getPadding(self::LEFT) - $this->getPadding(self::RIGHT); switch ($this->getProperty('align', Am_Pdf_Page_Decorator::ALIGN_LEFT)) { case Am_Pdf_Page_Decorator::ALIGN_LEFT : $lineEnd = $page->drawTextWithFixedWidth($this->content, $x + 1 + $this->getPadding(self::LEFT), $lineBegin, $width); break; case Am_Pdf_Page_Decorator::ALIGN_RIGHT : $lineEnd = $page->drawTextWithFixedWidth($this->content, $x + $this->getWidth() - 1 - $this->getPadding(self::RIGHT), $lineBegin, $width, 'UTF-8', Am_Pdf_Page_Decorator::ALIGN_RIGHT); break; } $rowHeight = $lineBegin - $lineEnd; if ($font) { $page->setFont($fontTmp, $fontSizeTmp); } $shape = $this->getProperty('shape', array( 'type' => Zend_Pdf_Page::SHAPE_DRAW_STROKE, 'color' => new Zend_Pdf_Color_Html('#cccccc') )); return array( 'x' => $x, 'y' => $y, 'width' => $this->getWidth(), 'height' => $rowHeight + $this->getPadding(self::BOTTOM) + $this->getPadding(self::TOP), 'shape' => $shape); } protected function getProperty($propName, $default = null) { if (isset($this->styles[$propName])) { return $this->styles[$propName]; } else { return $default; } } }PKx\CA[xGrid/Action/FormPdf.phpnu[form = $form = $this->grid->getRecord(); $this->dForm = $this->grid->getDi()->formTable->load($this->form->form_id); $this->user = $this->grid->getDi()->userTable->load($form->user_id); $padd = 20; $left = $padd; $right = Am_Pdf_Page_Decorator::PAGE_A4_WIDTH - $padd; $pdf = new Zend_Pdf(); $pdf->pages[0] = $pdf->newPage(Zend_Pdf_Page::SIZE_A4); $page = new Am_Pdf_Page_Decorator($pdf->pages[0]); $page->setFont(Zend_Pdf_Font::fontWithName(Zend_Pdf_Font::FONT_HELVETICA), 10); $pointer = Am_Pdf_Page_Decorator::PAGE_A4_HEIGHT; $this->renderHeader($page, $padd, $pointer); $that = $this; $table = new Am_Pdf_Table(function ($page, & $y) use ($pdf, $padd, $that) { $pdf->pages[] = $_ = $pdf->newPage(Zend_Pdf_Page::SIZE_A4); $p = new Am_Pdf_Page_Decorator($_); $p->setFont($page->getFont(), $page->getFontSize()); $pointer = Am_Pdf_Page_Decorator::PAGE_A4_HEIGHT; $that->renderHeader($p, $padd, $pointer); $y = $pointer; return $p; }); $table->setMargin(0, $padd, $padd, $padd); $data = $form->getData(false); foreach ($this->dForm->getFields(false) as $field) { if ($field->type == 'page-separator') { $table->addRow($field->title); } elseif($field->type == 'grid') { $table->addRow($field->title); foreach ($field->toPdf($data[$field->pk()]) as $row) { $table->addRow($row); } } else { $table->addRow($field->title, isset($data[$field->pk()]) ? $field->toPdf($data[$field->pk()]) : ''); } } $page->drawTable($table, 0, $pointer); $pCount = count($pdf->pages); $pIndex = 1; foreach ($pdf->pages as $p) { $pointer = Am_Pdf_Page_Decorator::PAGE_A4_HEIGHT; $pd = new Am_Pdf_Page_Decorator($p); $pd->nl($pointer); $pd->nl($pointer); $pd->drawText(sprintf('Page %d/%d', $pIndex++, $pCount), Am_Pdf_Page_Decorator::PAGE_A4_WIDTH - $padd, $pointer, 'UTF-8', Am_Pdf_Page_Decorator::ALIGN_RIGHT); } $helper = new Am_Mvc_Controller_Action_Helper_SendFile(); $helper->sendData($pdf->render(), 'application/pdf', sprintf('%s-%s.pdf', $this->dForm->title, sqlDate('now'))); } function renderHeader($page, $padd, & $pointer) { $page->nl($pointer); $page->nl($pointer); $this->renderLogo($page, $pointer); $page->setFont(Zend_Pdf_Font::fontWithName(Zend_Pdf_Font::FONT_HELVETICA_BOLD), 10); $page->drawText(sprintf('%s: %s, %s', $this->dForm->title, $this->user->getName(), amDatetime('now')), ceil(Am_Pdf_Page_Decorator::PAGE_A4_WIDTH/2), $pointer, 'UTF-8', Am_Pdf_Page_Decorator::ALIGN_CENTER); $page->setFont(Zend_Pdf_Font::fontWithName(Zend_Pdf_Font::FONT_HELVETICA), 10); $page->nl($pointer); } function renderLogo($page, &$pointer) { $logo_id = $this->grid->getDi()->config->get('form.logo_id'); $padd = 20; $yi = $pointer; if ($logo_id && ($upload = $this->grid->getDi()->uploadTable->load($logo_id, false))) { if (file_exists($upload->getFullPath())) { $image = null; switch ($upload->getType()) { case 'image/png' : $image = new Zend_Pdf_Resource_Image_Png($upload->getFullPath()); break; case 'image/jpeg' : $image = new Zend_Pdf_Resource_Image_Jpeg($upload->getFullPath()); break; case 'image/tiff' : $image = new Zend_Pdf_Resource_Image_Tiff($upload->getFullPath()); break; } if ($image) { $gh = 100; $gw = 200; $h = $image->getPixelHeight(); $w = $image->getPixelWidth(); $nh = $gh; $nw = ceil($w * $gh / $h); if ($nw > $gw) { $nw = $gw; $nh = ceil($h * $gw / $w); } $pos = ceil(Am_Pdf_Page_Decorator::PAGE_A4_WIDTH/2) - ceil($nw/2); $page->drawImage($image, $pos, $pointer - $nh, $pos + $nw, $pointer); $yi = $pointer - $nh; } } $page->nl($yi); $page->nl($yi); } $pointer = $yi; } }PKx\l3 Grid/Action/FormCopy.phpnu[getForm(); if ($form->isSubmitted() && $form->validate()) { $form_copy_id = $this->grid->getCompleteRequest()->getParam('form_copy_id'); $f = $this->grid->getRecord(); $r = $this->grid->getDi()->formCopyTable->load($form_copy_id); $nf = $this->grid->getDi()->formUserRecord; $nf->user_id = $f->user_id; $nf->form_id = $r->to_id; $nf->dattm = sqlTime('now'); $nf->status = 'pending'; $nf->save(); $old = array(); foreach (json_decode($r->field_map, true) as $oldf_id => $newf_id) { if (!$newf_id) continue; $old[] = $oldf_id; $case[] = "WHEN $oldf_id THEN $newf_id"; } if ($old) { $case = sprintf("CASE field_id %s END", implode("\n", $case)); $this->grid->getDi()->db->query(<<pk()}, $case,{$nf->form_id}, {$nf->user_id}, data, data_blob FROM ?_form_data WHERE form_user_id = {$f->pk()} AND field_id IN (?a); CUT , $old); } $this->grid->redirectBack(); } echo $this->renderTitle(); echo $form; } public function getForm() { $formUser = $this->grid->getRecord(); $options = $this->grid->getDi()->db->selectCol(<<form_id); $form = new Am_Form_Admin('form-data-copy', array('target' => '_top')); $form->setAction($this->grid->makeUrl(null)); $form->addElement('select', 'form_copy_id') ->setLabel(___('Target')) ->loadOptions($options); $form->addSaveButton(___('Copy')); foreach ($this->grid->getVariablesList() as $k) { if ($val = $this->grid->getRequest()->get($k)) { $form->addHidden($this->grid->getId() .'_'. $k)->setValue($val); } } return $form; } }PK|\NShoppingCart.phpnu[invoice = $invoice; } function addItem($product, $qty = 1, $options = array()) { $this->invoice->add($product, $qty, $options); } function deleteItem($product) { if ($item = $this->getInvoice()->findItem('product', $product->pk())) $this->getInvoice()->deleteItem($item); } /** @return Invoice */ function getInvoice() { return $this->invoice; } /** * @return array of InvoiceItem */ function getItems() { return $this->invoice->getItems(); } /** * @return Am_Currency */ function getCurrency($amount) { return $this->invoice->getCurrency($amount); } function hasItem($product) { foreach($this->getItems() as $item) { if ($item->item_id == $product->pk()) return true; } return false; } function getItem($product) { foreach($this->getItems() as $item) { if ($item->item_id == $product->pk()) return $item; } return null; } function getText() { $items = $this->invoice->getItems(); if (!$this->invoice->getItems()) return ___('You have no items in shopping cart'); $c = count($items); return ___('You have %d items in shopping cart', $c); } /** * @param string $code * @return null|string null if ok, or error message */ function setCouponCode($code) { $this->invoice->setCouponCode($code); $errors = $this->invoice->validateCoupon(); if($errors) $this->invoice->setCouponCode (null); return $errors; } function getCouponCode() { $coupon = $this->invoice->getCoupon(); if ($coupon) return $coupon->code; } function setUser(User $user) { $this->invoice->setUser($user); } function calculate() { $this->invoice->calculate(); } function clear() { $this->invoice = null; } }PK|\+Form/Signup/Cart.phpnu[ $brick) { if (in_array($brick->getClass(), array('product', 'paysystem', 'coupon'))) unset($ret[$k]); } return $ret; } public function isHideBricks() { return false; } } PK\@JReport/Standard.phpnu[title = ___('Income Report - payments minus refunds'); $this->description = ""; } // we have a VERY complex query here, so we will run it directly // without using Am_Query // Simulate FULL OUTER JOIN - not implemened in MYSQL // Usually it is better to avoid it! protected function runQuery() { $expra = $this->quantity->getSqlExpr('p.dattm'); $exprb = $this->quantity->getSqlExpr('r.dattm'); $this->stmt = $this->getDi()->db->queryResultOnly(" SELECT point, SUM(amt) as amt FROM ( SELECT $expra AS point, ROUND(IFNULL(SUM(p.amount/p.base_currency_multi),0),2) AS amt FROM ?_invoice_payment p WHERE p.dattm BETWEEN ? AND ? GROUP BY $expra UNION ALL SELECT $exprb AS point, ROUND(SUM(-ABS(r.amount)/r.base_currency_multi),2) AS amt FROM ?_invoice_refund r WHERE r.dattm BETWEEN ? AND ? GROUP BY $exprb ) AS t GROUP BY point ", $this->start, $this->stop, $this->start, $this->stop ); } function getLines() { return array(new Am_Report_Line("amt", ___('Payments Amount') . ', ' . Am_Currency::getDefault(), null, array('Am_Currency', 'render'))); } } class Am_Report_Tax extends Am_Report_Date { public function __construct() { $this->title = ___('Tax Report'); } public function getPointField() { return 'p.dattm'; } /** @return Am_Query */ public function getQuery() { $q = new Am_Query($this->getDi()->invoicePaymentTable, 'p'); $q->clearFields(); $q->addField('ROUND(SUM(tax/base_currency_multi), 2)', 'tax'); return $q; } function getLines() { return array(new Am_Report_Line('tax', ___('Tax Amount') . ', ' . Am_Currency::getDefault(), null, array('Am_Currency', 'render'))); } } class Am_Report_TaxCountry extends Am_Report_Date { public function __construct() { $this->title = ___('Tax by Customer Country'); } public function getPointField() { return 'p.dattm'; } /** @return Am_Query */ public function getQuery() { $q = new Am_Query($this->getDi()->invoicePaymentTable, 'p'); $q->clearFields(); $q->leftJoin('?_user', 'u', 'p.user_id=u.user_id'); foreach ($this->getCountries() as $country) { $q->addField("ROUND(SUM(IF(country='$country', tax/base_currency_multi, 0)), 2)", 'tax_' . $country); } return $q; } function getLines() { $ret = array(); $country_name = $this->getDi()->countryTable->getOptions(); foreach ($this->getCountries() as $country) { $ret[] = new Am_Report_Line('tax_' . $country, sprintf('%s (%s), %s', $country_name[$country], $country, Am_Currency::getDefault()), null, array('Am_Currency', 'render')); } return $ret; } function getCountries() { return $this->getDi()->db->selectCol('SELECT DISTINCT country FROM ?_user WHERE country<>?', ''); } } class Am_Report_PaymentVsRefund extends Am_Report_Date { public function __construct() { $this->title = ___('Payments vs Refunds'); $this->description = ""; } // we have a VERY complex query here, so we will run it directly // without using Am_Query // Simulate FULL OUTER JOIN - not implemened in MYSQL // Usually it is better to avoid it! protected function runQuery() { $expra = $this->quantity->getSqlExpr('p.dattm'); $exprb = $this->quantity->getSqlExpr('r.dattm'); $this->stmt = $this->getDi()->db->queryResultOnly(" SELECT point, SUM(pmt) as pmt, SUM(rfd) as rfd, SUM(pmt-rfd) AS amt FROM ( SELECT $expra AS point, ROUND(IFNULL(SUM(p.amount/p.base_currency_multi),0),2) AS pmt, 0 AS rfd FROM ?_invoice_payment p WHERE p.dattm BETWEEN ? AND ? GROUP BY $expra UNION ALL SELECT $exprb AS point, 0 AS pmt, ROUND(SUM(ABS(r.amount)/r.base_currency_multi),2) AS rfd FROM ?_invoice_refund r WHERE r.dattm BETWEEN ? AND ? GROUP BY $exprb ) AS t GROUP BY point ", $this->start, $this->stop, $this->start, $this->stop ); } function getLines() { return array( new Am_Report_Line("amt", ___('Income') . ', ' . Am_Currency::getDefault(), null, array('Am_Currency', 'render')), new Am_Report_Line("pmt", ___('Payment') . ', ' . Am_Currency::getDefault(), '#488f37', array('Am_Currency', 'render')), new Am_Report_Line("rfd", ___('Refund') . ', ' . Am_Currency::getDefault(), '#BA2727', array('Am_Currency', 'render')), ); } } class Am_Report_Paysystems extends Am_Report_Date { public function __construct() { $this->title = ___('Payments by payment system breakdown'); $this->description = ""; } public function getPointField() { return 'p.dattm'; } /** @return Am_Query */ public function getQuery() { $q = new Am_Query($this->getDi()->invoicePaymentTable, 'p'); $q->clearFields(); foreach ($this->getPaysystems() as $k => $ps) { $ps = $q->escape($ps); $q ->addField("ROUND(SUM(IF(p.paysys_id=$ps, p.amount/p.base_currency_multi, 0)),2)\n", 'amt_' . $k); } return $q; } function getPaysystems() { static $cache; if (!$cache) $cache = $this->getDi()->db->selectCol("SELECT DISTINCT paysys_id FROM ?_invoice_payment"); return $cache; } function getLines() { $ret = array(); foreach ($this->getPaysystems() as $k => $ps) { $ret[] = new Am_Report_Line('amt_' . $k, ucfirst($ps), null, array('Am_Currency', 'render')); } return $ret; } } class Am_Report_RefundRate extends Am_Report_Date { public function __construct() { $this->title = ___('Refunds Rate'); $this->description = ""; } public function getPointField() { return 'p.dattm'; } /** @return Am_Query */ public function getQuery() { $q = new Am_Query($this->getDi()->invoicePaymentTable, 'p'); $q->clearFields(); $q->addField("ROUND(100 * SUM(p.refund_amount/p.base_currency_multi)/SUM(p.amount/p.base_currency_multi),2)", 'rate'); return $q; } function getLines() { return array(new Am_Report_Line('rate', ___('Rate'), null, function($v) {return sprintf("%0.2f%%", $v);})); } public function getOutput(Am_Report_Result $result) { return array( new Am_Report_Graph_Bar($result), new Am_Report_Table($result, false) ); } } class Am_Report_RefundPaysystems extends Am_Report_Date { public function __construct() { $this->title = ___('Refunds by payment system breakdown'); $this->description = ""; } public function getPointField() { return 'p.dattm'; } /** @return Am_Query */ public function getQuery() { $q = new Am_Query($this->getDi()->invoiceRefundTable, 'p'); $q->clearFields(); foreach ($this->getPaysystems() as $k => $ps) { $ps = $q->escape($ps); $q ->addField("ROUND(SUM(IF(p.paysys_id=$ps, p.amount/p.base_currency_multi, 0)),2)\n", 'amt_' . $k); } return $q; } function getPaysystems() { static $cache; if (!$cache) $cache = $this->getDi()->db->selectCol("SELECT DISTINCT paysys_id FROM ?_invoice_refund"); return $cache; } function getLines() { $ret = array(); foreach ($this->getPaysystems() as $k => $ps) { $ret[] = new Am_Report_Line('amt_' . $k, ucfirst($ps), null, array('Am_Currency', 'render')); } return $ret; } } class Am_Report_Products extends Am_Report_Date { public function __construct() { $this->title = ___('Payments by products breakdown'); $this->description = ""; } public function _initConfigForm(Am_Form $form) { parent::_initConfigForm($form); $form->addMagicSelect('products', array('class' => 'am-combobox-fixed')) ->setLabel(___("Products\nkeep empty to report all products")) ->loadOptions($this->getDi()->productTable->getOptions()); } protected function runQuery() { $expra = $this->quantity->getSqlExpr('p.dattm'); $fields = array(); foreach ($this->getProducts() as $k => $v) { $fields[] = "ROUND( SUM( IFNULL(( SELECT p.amount * LEAST(1, IF(p.is_first, ii.first_total/p.invoice_total, ii.second_total/p.invoice_total)) FROM ?_invoice_item ii WHERE p.invoice_id=ii.invoice_id AND item_id=$k LIMIT 1 ), 0) ), 2) AS amt_$k"; } $db = $this->getDi()->db; $db->query("DROP TEMPORARY TABLE IF EXISTS ?_invoice_payment_report_tmp"); $db->query("CREATE TEMPORARY TABLE ?_invoice_payment_report_tmp ( dattm DATETIME not null, invoice_id int not null, is_first smallint, amount decimal(12,2), invoice_total decimal(12,2) ) "); $db->query(" INSERT INTO ?_invoice_payment_report_tmp SELECT p.dattm, p.invoice_id ,i.first_total > 0 && NOT EXISTS (SELECT * FROM ?_invoice_payment pp WHERE pp.invoice_id=p.invoice_id AND pp.invoice_payment_id < p.invoice_payment_id) AS is_first ,p.amount / p.base_currency_multi ,(SELECT(IF(is_first, i.first_total, i.second_total))) AS invoice_total FROM ?_invoice_payment p LEFT JOIN ?_invoice i USING (invoice_id) WHERE dattm BETWEEN ? AND ? AND amount > 0 HAVING invoice_total > 0 ", $this->start, $this->stop); $fields = "\n," . implode("\n,", $fields); $this->stmt = $this->getDi()->db->queryResultOnly(" SELECT $expra as point $fields FROM ?_invoice_payment_report_tmp p GROUP BY $expra ", $this->start, $this->stop); } function getProducts() { $vars = $this->form->getValue(); $cache = $this->getDi()->db->selectCol("SELECT DISTINCT product_id as ARRAY_KEY, title FROM ?_product {WHERE product_id IN (?a)} ORDER BY sort_order, title", !empty($vars['products']) ? (array) $vars['products'] : DBSIMPLE_SKIP); return $cache; } function getLines() { $ret = array(); foreach ($this->getProducts() as $k => $ps) { $ret[] = new Am_Report_Line('amt_' . $k, ucfirst($ps), null, array('Am_Currency', 'render')); } return $ret; } } class Am_Report_RefundProducts extends Am_Report_Date { public function __construct() { $this->title = ___('Refunds by products breakdown'); $this->description = ""; } public function _initConfigForm(Am_Form $form) { parent::_initConfigForm($form); $form->addMagicSelect('products', array('class' => 'am-combobox-fixed')) ->setLabel(___("Products\nkeep empty to report all products")) ->loadOptions($this->getDi()->productTable->getOptions()); } public function getPointField() { return 'r.dattm'; } /** @return Am_Query */ public function getQuery() { $q = new Am_Query($this->getDi()->invoiceRefundTable, 'r'); $q->clearFields(); $q->leftJoin('?_invoice_item', 'ii', 'r.invoice_id=ii.invoice_id') ->addWhere('ii.item_type=?', 'product'); foreach ($this->getProducts() as $k => $v) { $q->addField("ROUND(SUM(IF(ii.item_id=$k, r.amount/r.base_currency_multi, 0)),2)", 'amt_' . $k); } return $q; } function getProducts() { $vars = $this->form->getValue(); $cache = $this->getDi()->db->selectCol("SELECT DISTINCT product_id as ARRAY_KEY, title FROM ?_product {WHERE product_id IN (?a)} ORDER BY sort_order, title", !empty($vars['products']) ? (array) $vars['products'] : DBSIMPLE_SKIP); return $cache; } function getLines() { $ret = array(); foreach ($this->getProducts() as $k => $ps) { $ret[] = new Am_Report_Line('amt_' . $k, ucfirst($ps), null, array('Am_Currency', 'render')); } return $ret; } } class Am_Report_ProductCategories extends Am_Report_Date { public function __construct() { $this->title = ___('Payments by product categories breakdown'); $this->description = ""; } public function _initConfigForm(Am_Form $form) { parent::_initConfigForm($form); $form->addMagicSelect('categories', array('class' => 'am-combobox-fixed')) ->setLabel(___("Product categories\nkeep empty to report all categories")) ->loadOptions($this->getDi()->productCategoryTable->getAdminSelectOptions()); } protected function runQuery() { $expra = $this->quantity->getSqlExpr('p.dattm'); $fields = array(); foreach ($this->getCetegoryProducts($this->getCategories()) as $k => $v) { array_push($v, -1); array_walk($v, 'intval'); $v = implode(',', $v); $fields[] = "ROUND( SUM( IFNULL(( SELECT SUM(p.amount * LEAST(1, IF(p.is_first, ii.first_total/p.invoice_total, ii.second_total/p.invoice_total))) FROM ?_invoice_item ii WHERE p.invoice_id=ii.invoice_id AND item_id IN ($v) ), 0) ), 2) AS amt_$k"; } $db = $this->getDi()->db; $db->query("DROP TEMPORARY TABLE IF EXISTS ?_invoice_payment_report_tmp"); $db->query("CREATE TEMPORARY TABLE ?_invoice_payment_report_tmp ( dattm DATETIME not null, invoice_id int not null, is_first smallint, amount decimal(12,2), invoice_total decimal(12,2) ) "); $db->query(" INSERT INTO ?_invoice_payment_report_tmp SELECT p.dattm, p.invoice_id ,i.first_total > 0 && NOT EXISTS (SELECT * FROM ?_invoice_payment pp WHERE pp.invoice_id=p.invoice_id AND pp.invoice_payment_id < p.invoice_payment_id) AS is_first ,p.amount / p.base_currency_multi ,(SELECT(IF(is_first, i.first_total, i.second_total))) AS invoice_total FROM ?_invoice_payment p LEFT JOIN ?_invoice i USING (invoice_id) WHERE dattm BETWEEN ? AND ? AND amount > 0 HAVING invoice_total > 0 ", $this->start, $this->stop); $fields = count($fields) ? "\n," . implode("\n,", $fields) : ''; $this->stmt = $this->getDi()->db->queryResultOnly(" SELECT $expra as point $fields FROM ?_invoice_payment_report_tmp p GROUP BY $expra ", $this->start, $this->stop); } function getCetegoryProducts($categories) { $res = $this->getDi()->productCategoryTable->getCategoryProducts(); foreach ($res as $k => $v) if (!array_key_exists($k, $categories)) unset($res[$k]); return $res; } function getCategories() { $res = array(); $options = $this->getDi()->productCategoryTable->getAdminSelectOptions(); $vars = $this->form->getValue(); if (!empty($vars['categories'])) { foreach ($vars['categories'] as $cat_id) $res[$cat_id] = $options[$cat_id]; } else { $res = $options; } return $res; } function getLines() { $ret = array(); foreach ($this->getCategories() as $k => $ps) { $ret[] = new Am_Report_Line('amt_' . $k, ucfirst($ps), null, array('Am_Currency', 'render')); } return $ret; } } class Am_Report_RefundCategories extends Am_Report_Date { public function __construct() { $this->title = ___('Refunds by product categories breakdown'); $this->description = ""; } public function _initConfigForm(Am_Form $form) { parent::_initConfigForm($form); $form->addMagicSelect('categories', array('class' => 'am-combobox-fixed')) ->setLabel(___("Product categories\nkeep empty to report all categories")) ->loadOptions($this->getDi()->productCategoryTable->getAdminSelectOptions()); } public function getPointField() { return 'r.dattm'; } /** @return Am_Query */ public function getQuery() { $q = new Am_Query($this->getDi()->invoiceRefundTable, 'r'); $q->clearFields(); $q->leftJoin('?_invoice_item', 'ii', 'r.invoice_id=ii.invoice_id') ->addWhere('ii.item_type=?', 'product'); foreach ($this->getCetegoryProducts($this->getCategories()) as $k => $v) { array_push($v, -1); array_walk($v, 'intval'); $v = implode(',', $v); $q->addField("ROUND(SUM(IF(ii.item_id IN($v), r.amount/r.base_currency_multi, 0)),2)", 'amt_' . $k); } return $q; } function getCetegoryProducts($categories) { $res = $this->getDi()->productCategoryTable->getCategoryProducts(); foreach ($res as $k => $v) if (!array_key_exists($k, $categories)) unset($res[$k]); return $res; } function getCategories() { $res = array(); $options = $this->getDi()->productCategoryTable->getAdminSelectOptions(); $vars = $this->form->getValue(); if (!empty($vars['categories'])) { foreach ($vars['categories'] as $cat_id) $res[$cat_id] = $options[$cat_id]; } else { $res = $options; } return $res; } function getLines() { $ret = array(); foreach ($this->getCategories() as $k => $ps) { $ret[] = new Am_Report_Line('amt_' . $k, ucfirst($ps), null, array('Am_Currency', 'render')); } return $ret; } } class Am_Report_NewVsExisting extends Am_Report_Date { public function __construct() { $this->title = ___('Payments by New vs Existing members'); $this->description = ""; } protected function runQuery() { $expra = $this->quantity->getSqlExpr('p.dattm'); $exprpp = $this->quantity->getSqlExpr('pp.dattm'); $this->stmt = $this->getDi()->db->queryResultOnly(" SELECT $expra as point, ROUND(SUM(p.amount / p.base_currency_multi),2) as total, ROUND(SUM(IF( EXISTS (SELECT * FROM ?_invoice_payment pp WHERE user_id=p.user_id AND $exprpp < $expra) , 0, p.amount / p.base_currency_multi)),2) as new, ROUND(SUM(IF( EXISTS (SELECT * FROM ?_invoice_payment pp WHERE user_id=p.user_id AND $exprpp < $expra) , p.amount / p.base_currency_multi, 0)),2) as existing FROM ?_invoice_payment p WHERE dattm BETWEEN ? AND ? AND amount > 0 GROUP BY $expra ", $this->start, $this->stop); } function getLines() { return array( new Am_Report_Line('total', ___('Payments total'), null, array('Am_Currency', 'render')), new Am_Report_Line('existing', ___('Payments from existing customers'), null, array('Am_Currency', 'render')), new Am_Report_Line('new', ___('Payments from new customers'), null, array('Am_Currency', 'render')) // who did not pay earlier in the point period ); } } class Am_Report_SignupsCount extends Am_Report_Date { public function __construct() { $this->title = ___('Count of user signups'); $this->description = ___('including pending records'); } public function getPointField() { return 'u.added'; } /** @return Am_Query */ public function getQuery() { $q = new Am_Query($this->getDi()->userTable, 'u'); $q->clearFields(); $q->addField('COUNT(user_id)', 'cnt'); return $q; } function getLines() { $ret = array(); $ret[] = new Am_Report_Line('cnt', ___('Count of signups')); return $ret; } } class Am_Report_PurchaseCount extends Am_Report_Date { public function __construct() { $this->title = ___('Count of product purchase'); } public function _initConfigForm(Am_Form $form) { parent::_initConfigForm($form); $form->addMagicSelect('products', array('class' => 'am-combobox-fixed')) ->setLabel(___("Products\nkeep empty to report all products")) ->loadOptions($this->getDi()->productTable->getOptions()); } public function getPointField() { return 'i.tm_added'; } /** @return Am_Query */ public function getQuery() { $q = new Am_Query($this->getDi()->invoiceItemTable, 'ii'); $q->clearFields() ->leftJoin('?_invoice', 'i', 'ii.invoice_id=i.invoice_id') ->addWhere('i.status IN (?a)', array(Invoice::PAID, Invoice::RECURRING_ACTIVE, Invoice::RECURRING_FINISHED)) ->addWhere('ii.item_type=?', 'product'); $fields = array(); foreach ($this->getProducts() as $k => $v) { $q->addField("SUM(IF(ii.item_id = $k, ii.qty, 0))", 'cnt_' . $k); } return $q; } function getProducts() { $vars = $this->form->getValue(); $cache = $this->getDi()->db->selectCol("SELECT DISTINCT product_id as ARRAY_KEY, title FROM ?_product {WHERE product_id IN (?a)} ORDER BY sort_order, title", !empty($vars['products']) ? (array) $vars['products'] : DBSIMPLE_SKIP); return $cache; } function getLines() { $ret = array(); foreach ($this->getProducts() as $k => $title) { $ret[] = new Am_Report_Line('cnt_' . $k, ucfirst($title)); } return $ret; } } class Am_Report_PendingInvoiceCount extends Am_Report_Date { public function __construct() { $this->title = ___('Count of Pending Invoices'); } public function _initConfigForm(Am_Form $form) { parent::_initConfigForm($form); $form->addMagicSelect('products', array('class' => 'am-combobox-fixed')) ->setLabel(___("Products\nkeep empty to report all products")) ->loadOptions($this->getDi()->productTable->getOptions()); } public function getPointField() { return 'i.tm_added'; } /** @return Am_Query */ public function getQuery() { $q = new Am_Query($this->getDi()->invoiceItemTable, 'ii'); $q->clearFields() ->leftJoin('?_invoice', 'i', 'ii.invoice_id=i.invoice_id') ->addWhere('i.status IN (?a)', array(Invoice::PENDING)) ->addWhere('ii.item_type=?', 'product'); $fields = array(); foreach ($this->getProducts() as $k => $v) { $q->addField("SUM(IF(ii.item_id = $k, ii.qty, 0))", 'cnt_' . $k); } return $q; } function getProducts() { $vars = $this->form->getValue(); $cache = $this->getDi()->db->selectCol("SELECT DISTINCT product_id as ARRAY_KEY, title FROM ?_product {WHERE product_id IN (?a)} ORDER BY sort_order, title", !empty($vars['products']) ? (array) $vars['products'] : DBSIMPLE_SKIP); return $cache; } function getLines() { $ret = array(); foreach ($this->getProducts() as $k => $title) { $ret[] = new Am_Report_Line('cnt_' . $k, ucfirst($title)); } return $ret; } } class Am_Report_CancelInvoiceCount extends Am_Report_Date { public function __construct() { $this->title = ___('Count of Cancellations'); $this->description = ___('Number of Cancelled Recurring Subscriptions by Period'); } public function _initConfigForm(Am_Form $form) { parent::_initConfigForm($form); $form->addMagicSelect('products', array('class' => 'am-combobox-fixed')) ->setLabel(___("Products\nkeep empty to report all products")) ->loadOptions($this->getDi()->productTable->getOptions()); } public function getPointField() { return 'i.tm_cancelled'; } /** @return Am_Query */ public function getQuery() { $q = new Am_Query($this->getDi()->invoiceItemTable, 'ii'); $q->clearFields() ->leftJoin('?_invoice', 'i', 'ii.invoice_id=i.invoice_id') ->addWhere('i.status IN (?a)', array(Invoice::RECURRING_CANCELLED)) ->addWhere('ii.item_type=?', 'product'); $fields = array(); foreach ($this->getProducts() as $k => $v) { $q->addField("SUM(IF(ii.item_id = $k, ii.qty, 0))", 'cnt_' . $k); } return $q; } function getProducts() { $vars = $this->form->getValue(); $cache = $this->getDi()->db->selectCol("SELECT DISTINCT product_id as ARRAY_KEY, title FROM ?_product {WHERE product_id IN (?a)} ORDER BY sort_order, title", !empty($vars['products']) ? (array) $vars['products'] : DBSIMPLE_SKIP); return $cache; } function getLines() { $ret = array(); foreach ($this->getProducts() as $k => $title) { $ret[] = new Am_Report_Line('cnt_' . $k, ucfirst($title)); } return $ret; } } class Am_Report_Downloads extends Am_Report_Date { public function __construct() { $this->title = ___('Downloads by files breakdown'); $this->description = ___('only files downloaded by registered users is taken to account'); } public function _initConfigForm(Am_Form $form) { parent::_initConfigForm($form); $form->addMagicSelect('files', array('class' => 'am-combobox-fixed')) ->setLabel(___("Files\nkeep empty to report all files")) ->loadOptions($this->getOptions()); } protected function getOptions() { return $this->getDi()->db->selectCol("SELECT DISTINCT file_id as ARRAY_KEY, title FROM ?_file"); } public function getPointField() { return 'fd.dattm'; } /** @return Am_Query */ public function getQuery() { $q = new Am_Query($this->getDi()->fileDownloadTable, 'fd'); $q->clearFields(); foreach ($this->getFiles() as $k => $v) { $q->addField(sprintf('SUM(IF(file_id=%d,1,0))', $k), 'cnt_' . $k); } return $q; } function getFiles() { $vars = $this->form->getValue(); $files = $this->getDi()->db->selectCol("SELECT DISTINCT file_id as ARRAY_KEY, title FROM ?_file {WHERE file_id IN (?a)}", !empty($vars['files']) ? (array) $vars['files'] : DBSIMPLE_SKIP); return $files; } function getLines() { $ret = array(); foreach ($this->getFiles() as $k => $ps) { $ret[] = new Am_Report_Line('cnt_' . $k, ucfirst($ps)); } return $ret; } } class Am_Report_RetentionRate extends Am_Report_Abstract { public function __construct() { $this->title = ___('Retention Rate'); $this->description = ___('Number of cancel on each billing cycle'); $this->setQuantity(new Am_Report_Quant_Exact()); } public function _initConfigForm(Am_Form $form) { parent::_initConfigForm($form); $form->addMagicSelect('products', array('class' => 'am-combobox-fixed')) ->setLabel(___("Products\nkeep empty to report all products")) ->loadOptions($this->getDi()->productTable->getOptions()); $gr = $form->addGroup() ->setLabel(___("Report Period\n" . 'Take into Account only subscriptions that began in defined period, '. 'keep empty to use all subscriptions')); $gr->setSeparator(' '); $gr->addDate('date_start', array('placeholder' => ___('Begin Date'))); $gr->addHtml() ->setHtml('—'); $gr->addDate('date_end', array('placeholder' => ___('End Date'))); } public function runQuery() { $fields = array(); foreach ($this->getProducts() as $k => $product) { $fields[] = "SUM(IF(ii.item_id=$k AND ii.item_type='product', 1, 0)) AS cnt_" . $k; } $fields = implode(',', $fields); $vars = $this->form->getValue(); $date_stmt_start = isset($vars['date_start']) ? sprintf(" AND i.tm_started >= %s", $this->getDi()->db->escape(date('Y-m-d 00:00:00', strtotime($vars['date_start'])))) : ''; $date_stmt_end = isset($vars['date_end']) ? sprintf(" AND i.tm_started <= %s", $this->getDi()->db->escape(date('Y-m-d 23:59:59', strtotime($vars['date_end'])))) : ''; $point_fld = self::POINT_FLD; $sql = "SELECT $fields, (SELECT COUNT(invoice_payment_id) + IF(i.first_total = 0, 1, 0) FROM ?_invoice_payment WHERE invoice_id=i.invoice_id) AS $point_fld FROM ?_invoice i LEFT JOIN ?_invoice_item ii USING(invoice_id) WHERE i.tm_cancelled IS NOT NULL $date_stmt_start $date_stmt_end GROUP BY $point_fld"; $this->stmt = $this->getDi()->db->queryResultOnly($sql); } public function getLines() { $ret = array(); foreach ($this->getProducts() as $k => $product) { $ret[] = new Am_Report_Line('cnt_' . $k, $product); } return $ret; } protected function getProducts() { $vars = $this->form->getValue(); $cache = $this->getDi()->db->selectCol("SELECT DISTINCT product_id as ARRAY_KEY, title FROM ?_product {WHERE product_id IN (?a)} ORDER BY sort_order, title", !empty($vars['products']) ? (array) $vars['products'] : DBSIMPLE_SKIP); return $cache; } public function getOutput(Am_Report_Result $result) { return array( new Am_Report_Graph_Bar($result), new Am_Report_Table($result) ); } } class Am_Report_AverageLifetimeValue extends Am_Report_Abstract { public function __construct() { $this->title = ___('Average Lifetime Value (Cohort Analysis)'); $this->description = ___('report includes only user who did at least one payment'); } public function _initConfigForm(Am_Form $form) { parent::_initConfigForm($form); $form->addSelect('quant')->setLabel(___('Grouping')) ->loadOptions(array( '7' => ___('Week'), '30' => ___('Month (30 days)'), '90' => ___('Quarter (90 days)'), '365' => ___('Year') )); $gr = $form->addGroup() ->setLabel(___("Users\n" . 'Take into Account only user who sign up in defined period, '. 'keep empty to use all user')); $gr->setSeparator(' '); $gr->addDate('date_start', array('placeholder' => ___('Begin Date'))); $gr->addHtml() ->setHtml('—'); $gr->addDate('date_end', array('placeholder' => ___('End Date'))); } public function getPointFieldType() { return Am_Report_Abstract::POINT_VALUE; } protected function processConfigForm(array $values) { $this->setInterval( isset($values['date_start']) ? $values['date_start'] : '1927-01-01', isset($valuse['date_end']) ? $valuse['date_end'] : 'now'); $this->d = (int)$values['quant']; $quant = new Am_Report_Quant_Exact(); $this->setQuantity($quant); } public function setInterval($start, $stop) { $this->start = date('Y-m-d 00:00:00', strtotime($start)); $this->stop = date('Y-m-d 23:59:59', strtotime($stop)); return $this; } public function runQuery() { $db = $this->getDi()->db; $db->query("DROP TEMPORARY TABLE IF EXISTS ?_alv_report_tmp"); $db->query("CREATE TEMPORARY TABLE ?_alv_report_tmp ( user_id INT NOT NULL, delay INT NOT NULL, amount DECIMAL(12,2) )"); $d = $this->d; $db->query("INSERT INTO ?_alv_report_tmp (user_id, delay, amount) SELECT user_id, CEIL((DATEDIFF(ip.dattm, u.added)+1)/$d), (amount / base_currency_multi) FROM ?_invoice_payment ip LEFT JOIN ?_user u USING (user_id) WHERE u.added BETWEEN ? AND ? AND ip.dattm>u.added", $this->start, $this->stop); $db->query("INSERT INTO ?_alv_report_tmp (user_id, delay, amount) SELECT user_id, CEIL((DATEDIFF(ip.dattm, u.added)+1)/$d), (-1 * amount / base_currency_multi) FROM ?_invoice_refund ip LEFT JOIN ?_user u USING (user_id) WHERE u.added BETWEEN ? AND ? AND ip.dattm>u.added", $this->start, $this->stop); $cnt = $db->selectCell("SELECT COUNT(DISTINCT ip.user_id) FROM ?_invoice_payment ip LEFT JOIN ?_user u USING (user_id) WHERE u.added BETWEEN ? AND ? AND ip.dattm>u.added", $this->start, $this->stop); $this->stmt = $this->getDi()->db->queryResultOnly(" SELECT ROUND(SUM(amount)/$cnt,2) AS alv, delay AS point FROM ?_alv_report_tmp GROUP BY delay"); } public function getLines() { return array(new Am_Report_Line('alv', ___('Average Lifetime Value') . ', ' . Am_Currency::getDefault(), null, array('Am_Currency', 'render'))); } public function getOutput(Am_Report_Result $result) { return array( new Am_Report_Graph_Bar($result), new Am_Report_Table($result) ); } } class Am_Report_Active extends Am_Report_Abstract { public function __construct() { $this->title = ___('Active Users by Products'); $this->description = ___('number of active users per product'); } public function _initConfigForm(Am_Form $form) { parent::_initConfigForm($form); $form->addMagicSelect('products', array('class' => 'am-combobox-fixed')) ->setLabel(___("Products\nkeep empty to report all products")) ->loadOptions($this->getDi()->productTable->getOptions()); } public function runQuery() { $now = $this->getDi()->sqlDate; $products = array(); foreach ($this->getProducts() as $k => $product) { $products[] = $k; } $products = implode(',', $products); $point_fld = self::POINT_FLD; $sql = "SELECT COUNT(DISTINCT user_id) as active, product_id AS $point_fld FROM ?_access WHERE begin_date <= '$now' AND expire_date >= '$now' GROUP BY $point_fld HAVING product_id IN ($products)"; $this->stmt = $this->getDi()->db->queryResultOnly($sql); } public function getLines() { return array(new Am_Report_Line('active', ___('Active Users'))); } protected function getProducts() { $vars = $this->form->getValue(); $cache = $this->getDi()->db->selectCol("SELECT DISTINCT product_id as ARRAY_KEY, title FROM ?_product {WHERE product_id IN (?a)} ORDER BY sort_order, title", !empty($vars['products']) ? (array) $vars['products'] : DBSIMPLE_SKIP); return $cache; } protected function processConfigForm(array $values) { $this->setQuantity(new Am_Report_Quant_Enum($this->getProducts())); } public function getOutput(Am_Report_Result $result) { return array( new Am_Report_Graph_Bar($result), new Am_Report_Table($result) ); } } class Am_Report_UserDemography extends Am_Report_Abstract { public function __construct() { $this->title = ___('User Demographics'); $this->description = ___('number of users per region'); } public function _initConfigForm(Am_Form $form) { parent::_initConfigForm($form); $form->addAdvRadio('type') ->setLabel(___('Group By')) ->loadOptions(array( 'country' => ___('Country'), 'state' => ___('State') ))->setValue('country'); } public function runQuery() { $vars = $this->form->getValue(); $field = $vars['type']; $point_fld = self::POINT_FLD; $sql = "SELECT COUNT(user_id) AS demography, $field AS $point_fld FROM ?_user GROUP BY $point_fld HAVING $point_fld<>''"; $this->stmt = $this->getDi()->db->queryResultOnly($sql); } public function getLines() { return array(new Am_Report_Line('demography', ___('User Demographics'))); } protected function getOptions() { $vars = $this->form->getValue(); switch ($vars['type']) { case 'country' : return $this->getDi()->db->selectCol("SELECT country as ARRAY_KEY, title FROM ?_country WHERE country IN (SELECT DISTINCT country FROM ?_user)"); break; case 'state' : return $this->getDi()->db->selectCol("SELECT state as ARRAY_KEY, title FROM ?_state WHERE state IN (SELECT DISTINCT state FROM ?_user)"); break; default: throw new Am_Exception_InputError(sprintf('Unknown type [%s] in %s::%s', $vars['type'], __CLASS__, __METHOD__)); } } protected function processConfigForm(array $values) { $this->setQuantity(new Am_Report_Quant_Enum($this->getOptions())); } public function getOutput(Am_Report_Result $result) { return array( new Am_Report_Graph_Bar($result), new Am_Report_Table($result) ); } } class Am_Report_ChurnRate extends Am_Report_Date { public function __construct() { $this->title = ___('Churn Rate'); $this->description = ___('Number of users who becomes inactive in given period'); } public function _initConfigForm(Am_Form $form) { parent::_initConfigForm($form); $form->addMagicSelect('products', array('class' => 'am-combobox-fixed')) ->setLabel(___("Products\nkeep empty to report all products")) ->loadOptions($this->getDi()->productTable->getOptions()); } protected function runQuery() { $expbegin = $this->quantity->getSqlExpr('begin'); $expend = $this->quantity->getSqlExpr('expire'); $vars = $this->form->getValue(); if (empty($vars['products'])) { $this->stmt = $this->getDi()->db->queryResultOnly( "SELECT $expend as point, COUNT(t.user_id) as cnt FROM ( SELECT user_id, MIN(begin_date) AS begin, MAX(expire_date) AS expire FROM ?_access GROUP BY user_id ) AS t WHERE $expbegin < $expend and expire > ? and expire < ? group by point", sqlDate($this->start), sqlDate($this->stop)); } else { $fields = array(); foreach ($this->getProducts() as $k => $title) { $fields[] = "sum(if(product_id=$k, 1,0)) as cnt_$k"; } $fields = implode(", ", $fields); $this->stmt = $this->getDi()->db->queryResultOnly( "SELECT $expend as point, $fields FROM ( SELECT concat(user_id, '-',product_id) as user_product, user_id, product_id, MIN(begin_date) AS begin, MAX(expire_date) AS expire FROM ?_access GROUP BY user_product ) AS t WHERE $expbegin < $expend and expire > ? and expire < ? group by point", sqlDate($this->start), sqlDate($this->stop)); } } function getProducts() { $vars = $this->form->getValue(); $cache = $this->getDi()->db->selectCol("SELECT DISTINCT product_id as ARRAY_KEY, title FROM ?_product {WHERE product_id IN (?a)} ORDER BY sort_order, title", !empty($vars['products']) ? (array) $vars['products'] : DBSIMPLE_SKIP); return $cache; } function getLines() { $vars = $this->form->getValue(); $ret = array(); if (empty($vars['products'])) { $ret[] = new Am_Report_Line('cnt', ucfirst("Users who became inactive")); } else { foreach ($this->getProducts() as $k => $title) { $ret[] = new Am_Report_Line('cnt_' . $k, ucfirst($title)); } } return $ret; } } class Am_Report_ActiveUsers extends Am_Report_Date { public function __construct() { $this->title = ___('Active Users by Period'); $this->description = ___('Number of Active Users by Date'); } public function _initConfigForm(Am_Form $form) { parent::_initConfigForm($form); $form->addMagicSelect('products', array('class' => 'am-combobox-fixed')) ->setLabel(___("Include only users who have active subscritpions to these products")) ->loadOptions($this->getDi()->productTable->getOptions()); } protected function runQuery() { $expbegin = $this->quantity->getSqlExpr('begin_date'); $expend = $this->quantity->getSqlExpr('expire_date'); $this->getDi()->db->query("DROP TEMPORARY TABLE IF EXISTS ?_active_users_by_period_tmp"); $this->getDi()->db->query( "CREATE TEMPORARY TABLE ?_active_users_by_period_tmp ( point varchar(10) not null, cnt int(10) not null, UNIQUE KEY(point) ) "); $this->getDi()->db->query( "INSERT IGNORE INTO ?_active_users_by_period_tmp (point) " . "SELECT DISTINCT($expbegin) FROM ?_access WHERE begin_date BETWEEN ? AND ? " . "UNION SELECT DISTINCT($expend) FROM ?_access WHERE expire_date BETWEEN ? AND ?", $this->start, $this->stop, $this->start, $this->stop); $vars = $this->form->getValue(); $this->getDi()->db->query("UPDATE ?_active_users_by_period_tmp p SET p.cnt = (SELECT COUNT(DISTINCT(user_id)) FROM ?_access a WHERE p.point BETWEEN $expbegin AND $expend {AND a.product_id in (?a)})", (!empty($vars['products']) ? (array) $vars['products'] : DBSIMPLE_SKIP)); $this->stmt = $this->getDi()->db->queryResultOnly("SELECT point, cnt FROM ?_active_users_by_period_tmp"); } function getProducts() { $vars = $this->form->getValue(); $cache = $this->getDi()->db->selectCol("SELECT DISTINCT product_id as ARRAY_KEY, title FROM ?_product {WHERE product_id IN (?a)} ORDER BY sort_order, title", !empty($vars['products']) ? (array) $vars['products'] : DBSIMPLE_SKIP); return $cache; } public function getLines() { return array(new Am_Report_Line('cnt', 'Active Users')); } } class Am_Report_RollingConversion extends Am_Report_Date { public function __construct() { $this->title = ___('Rolling Conversion'); $this->description = ___('Percentage of users who convert from free to paid within given amount of days'); } public function _initConfigForm(Am_Form $form) { parent::_initConfigForm($form); $form->addMagicSelect('products', array('class' => 'am-combobox-fixed')) ->setLabel(___("Count conversion for these products only")) ->loadOptions($this->getDi()->productTable->getOptions()); $form->addText('rolling_days', array('placeholder' => '30', 'size' => 3)) ->setLabel(___("Rolling Days")); } protected function runQuery() { $pointexp = $this->quantity->getSqlExpr('t.added'); $vars = $this->form->getValue(); $rolling_days = intval($vars['rolling_days']) ? intval($vars['rolling_days']) : 30; $this->getDi()->db->query("DROP TABLE IF EXISTS ?_rolling_conversion_tmp"); $this->getDi()->db->query( "CREATE TEMPORARY TABLE ?_rolling_conversion_tmp ( point varchar(10) not null, added int(10) not null, paid int(10) not null, UNIQUE KEY(point) ) "); // Add count of users who $this->getDi()->db->query( "INSERT INTO ?_rolling_conversion_tmp (point, added) SELECT $pointexp as point, count(t.user_id) AS added FROM ?_user t where t.added>? AND t.added < ? GROUP BY point ", $this->start, $this->stop ); $this->getDi()->db->queryResultOnly( "INSERT INTO ?_rolling_conversion_tmp (point, paid) SELECT $pointexp as point, COUNT(t.user_id) as cnt FROM ( SELECT u.user_id, added, MIN(p.dattm) AS paid FROM ?_user u LEFT JOIN ?_invoice_payment p ON u.user_id = p.user_id {LEFT JOIN ?_access a on p.invoice_payment_id = a.invoice_payment_id WHERE a.product_id IN (?a)} GROUP BY u.user_id ) AS t WHERE to_days(paid) - to_days(added) <= ? AND t.added > ? AND t.addedstart, $this->stop); $this->stmt = $this->getDi()->db->queryResultOnly("SELECT point, paid/added as cnt FROM ?_rolling_conversion_tmp"); } public function getLines() { return array(new Am_Report_Line('cnt', 'Conversion')); } } class Am_Report_ProductConversion extends Am_Report_Date { public function __construct() { $this->title = ___('Product Convertion'); $this->description = ___('Number of Users who Purchase product B after Product A'); } public function _initConfigForm(Am_Form $form) { parent::_initConfigForm($form); $form->addSelect('producta', array('class' => 'am-combobox-fixed')) ->setLabel(___("Product A")) ->loadOptions($this->getDi()->productTable->getOptions()); $form->addSelect('productb', array('class' => 'am-combobox-fixed')) ->setLabel(___("Product B")) ->loadOptions($this->getDi()->productTable->getOptions()); } public function getPointField() { return 'begin_date'; } protected function runQuery() { $expra = $this->quantity->getSqlExpr('begin_date'); $vars = $this->form->getValue(); $db = $this->getDi()->db; $db->query("DROP TEMPORARY TABLE IF EXISTS ?_product_conversion_tmp"); $db->query("CREATE TEMPORARY TABLE ?_product_conversion_tmp ( user_id INT NOT NULL, begin_date DATE NOT NULL )"); $db->query("INSERT INTO ?_product_conversion_tmp (user_id, begin_date) SELECT a.user_id, MIN(a.begin_date) FROM ?_access a LEFT JOIN ?_access a2 ON a.user_id = a2.user_id AND a2.product_id = ? WHERE a.product_id = ? AND a2.product_id IS NOT NULL AND a2.begin_date < a.begin_date GROUP BY a.user_id", $vars['producta'], $vars['productb']); $this->stmt = $this->getDi()->db->queryResultOnly(" SELECT COUNT(DISTINCT user_id) AS cnt, $expra AS point FROM ?_product_conversion_tmp WHERE begin_date BETWEEN ? AND ? GROUP BY $expra", $this->start, $this->stop); } public function getLines() { return array(new Am_Report_Line('cnt', 'Conversion')); } } class Am_Report_CustomUserField extends Am_Report_Abstract { public function __construct() { $this->title = ___('User Distribution by Custom Field'); } protected function runQuery() { $f = $this->field; $point_fld = self::POINT_FLD; if ($f->sql) { $this->stmt = $this->getDi()->db->queryResultOnly(" SELECT ?# AS $point_fld, COUNT(user_id) as cnt FROM ?_user WHERE ?# IS NOT NULL AND ?# <> '' GROUP BY ?#", $f->name, $f->name, $f->name, $f->name, $f->name); } else { $this->stmt = $this->getDi()->db->queryResultOnly(" SELECT value AS $point_fld, COUNT(value) as cnt FROM ?_data WHERE `key`= ? AND value IS NOT NULL AND value<>'' GROUP BY $point_fld", $f->name); } } function getLines() { $ret = array(); $ret[] = new Am_Report_Line('cnt', ___($this->field->title)); return $ret; } public function _initConfigForm(Am_Form $form) { parent::_initConfigForm($form); $opt = $this->getFieldOptions(); if (!$opt) { $text = Am_Html::escape(___('This report works only with radio and select fields. You have not such custom fields yet.')); $form->addHtml(null, array('class' => 'row-wide')) ->setHtml(<<$text CUT ); } else { $sel = $form->addSelect('field') ->setLabel(___("Field")) ->loadOptions($opt); } } protected function getFieldOptions() { $opt = array(); foreach ($this->getDi()->userTable->customFields()->getAll() as $f) { if (in_array($f->type, array('radio', 'select'))) { $opt[$f->name] = $f->title; } } return $opt; } protected function processConfigForm(array $values) { $vars = $this->form->getValue(); $this->field = $this->getDi()->userTable->customFields()->get($vars['field']); $this->setQuantity(new Am_Report_Quant_Enum($this->field->options)); } public function getOutput(Am_Report_Result $result) { return array( new Am_Report_Graph_Bar($result), new Am_Report_Table($result) ); } } class Am_Report_PaymentCouponBatch extends Am_Report_Date { public function __construct() { $this->title = ___("Payments by Used Coupon"); $this->description = ""; parent::__construct(); } public function _initConfigForm(Am_Form $form) { parent::_initConfigForm($form); $sel = $form->addSelect('batch_id', array('class' => 'am-combobox-fixed'))->setLabel(___("Coupon Batch")); $sel->loadOptions($this->getDi()->couponBatchTable->getOptions()); } public function getPointField() { return 'tm_added'; } /** @return Am_Query */ public function getQuery() { $vars = $this->form->getValue(); $batch_id = $vars['batch_id']; $q = new Am_Query($this->getDi()->invoiceTable); $q->leftJoin('?_coupon', 'c', 't.coupon_id=c.coupon_id') ->addWhere('status=?', Invoice::PAID) ->addWhere('t.coupon_id IS NOT NULL') ->addWhere('batch_id=?', $batch_id); $q->clearFields(); $q->addField('ROUND(SUM(first_total/base_currency_multi), 2) AS amt'); return $q; } function getLines() { return array( new Am_Report_Line("amt", ___('Payments Amount') . ', ' . Am_Currency::getDefault(), null, array('Am_Currency', 'render')) ); } } class Am_Report_RefundCouponBatch extends Am_Report_Date { public function __construct() { $this->title = ___("Refunds by Used Coupon"); $this->description = ""; parent::__construct(); } public function _initConfigForm(Am_Form $form) { parent::_initConfigForm($form); $sel = $form->addSelect('batch_id', array('class' => 'am-combobox-fixed'))->setLabel(___("Coupon Batch")); $sel->loadOptions($this->getDi()->couponBatchTable->getOptions()); } public function getPointField() { return 't.dattm'; } /** @return Am_Query */ public function getQuery() { $vars = $this->form->getValue(); $batch_id = $vars['batch_id']; $q = new Am_Query($this->getDi()->invoiceRefundTable); $q->leftJoin('?_invoice', 'i', 'i.invoice_id=t.invoice_id') ->leftJoin('?_coupon', 'c', 'i.coupon_id=c.coupon_id') ->addWhere('status=?', Invoice::PAID) ->addWhere('i.coupon_id IS NOT NULL') ->addWhere('batch_id=?', $batch_id); $q->clearFields(); $q->addField('ROUND(SUM(t.amount/t.base_currency_multi), 2) AS amt'); return $q; } function getLines() { return array( new Am_Report_Line("amt", ___('Refund Amount') . ', ' . Am_Currency::getDefault(), null, array('Am_Currency', 'render')) ); } }PK\f Paginator.phpnu[ < Previous | 1 | 2 | 3 | 4 | 5 | 6 | Next > * * @package Am_Utils */ class Am_Paginator { // configuration protected $cssClass = 'am-pagination'; protected $countOnPage = 11; // number of links on the page protected $boundCount = 2; // number of fixed links in start and end 1,2 98,88 protected $pageVar; // current template protected $totalPages = 0, $currentPage = 0; protected $urlTemplate; public function __construct($totalPages, $currentPage=null, $urlTemplate=null, $pageVar = "p", Am_Mvc_Request $request = null) { $this->pageVar = $pageVar; $this->totalPages = $totalPages; $this->currentPage = $currentPage === null ? $this->_detectCurrentPage() : $currentPage; $this->urlTemplate = $urlTemplate === null ? $this->_detectUrlTemplate($request) : $urlTemplate; } public function setCssClass($class) { $this->cssClass = $class; } public function setPageVar($pageVar) { $this->pageVar = $pageVar; } public function getCurrentPage() { return $this->currentPage; } public function setCurrentPage($p) { $this->currentPage = (int)$p; } public function setPagesCount($p) { $this->countOnPage = (int)$p; } public function _detectCurrentPage() { return (int)Am_Di::getInstance()->request->getParam($this->pageVar); } protected function _detectUrlTemplate($request = null) { if ($request === null) $request = Am_Di::getInstance()->request; $uri = $request->assembleUrl(true); $uri = preg_replace('/([&?]'. preg_quote($this->pageVar, '/') .')=(?:\d+)?(&|$)/' , '\\1=###PAGE###\\2', $uri, 99, $replaced); if (!$replaced) { $insert = urlencode($this->pageVar).'=###PAGE###' ; $uri .= (strpos($uri, '?')!==false) ? ('&'. $insert) : ('?'.$insert); } return $uri; } public function getLink($p) { return htmlentities( str_replace('###PAGE###', (int)$p, $this->urlTemplate) , ENT_QUOTES, 'UTF-8'); } /** * @return array(int, int) - start and end page # */ public function getRange() { $current = $this->currentPage; $total = $this->totalPages; if ($current>($total-1)) $current = $total - 1; $countOnPage = $this->countOnPage - $this->boundCount*2; if ($countOnPage <= 0) throw new Exception("Wrong Am_Paginator configuration, $countOnPage <= 0 in ".__METHOD__); $lower = intval($current + 1 - floor($this->countOnPage/2) - $this->countOnPage%2); $upper = intval($current + floor($this->countOnPage/2)); if ($lower < 0) { $upper += -$lower; $lower = 0; } if ($upper > ($total - 1)) { $lower -= $upper - ($total - 1); if ($lower<0) $lower = 0; $upper = $total - 1; } $ret = range($lower, $upper); // replace first boundCount links for ($i=0; $i<$this->boundCount; $i++) { if (isset($ret[$i])) $ret[$i] = $i; } // replace last boundCount links for ($i=0; $i<$this->boundCount; $i++) { if (isset($ret[count($ret)-$i-1])) $ret[count($ret)-$i-1] = $total-$i-1; } sort($ret); return array_unique($ret); } public function render() { if ($this->totalPages<=1) return ""; $range = $this->getRange(); $next = min($this->currentPage + 1, $this->totalPages-1); $previous = max(0,$this->currentPage - 1); $out = sprintf('
'.PHP_EOL, $this->cssClass); // first link // previous link $disablePrev = $this->currentPage == $previous; $element = $disablePrev ? 'span' : 'a'; $out .= sprintf('<%s%s class="%s-prev%s">%s', $element, ($disablePrev ? '' : sprintf(' href="%s"', $this->getLink($previous))), $this->cssClass, $disablePrev ? ' ' .$this->cssClass . '-current' : '', ___('Prev'), $element); $p = null; foreach ($range as $i) { if (($p !== null) && ($i-$p>1)) { $out .= "..."; } $out .= sprintf('%s', $this->getLink($i), $i == $this->currentPage ? ' class="' . $this->cssClass . '-current"' : '', $i + 1); $p = $i; } // next link $disableNext = $this->currentPage == $next; $element = $disableNext ? 'span' : 'a'; $out .= sprintf('<%s%s class="%s-next%s">%s', $element, ($disableNext ? '' : sprintf(' href="%s"', $this->getLink($next))), $this->cssClass, $disableNext ? ' ' . $this->cssClass . '-current' : '', ___('Next'), $element); $out .= "
".PHP_EOL; return $out; } }PK\cc DbSync.phpnu[ operation */ protected $tableOperations = array(); protected $pieceOperations = array(); protected $tables = array(); /** * If safe_mode is enabled, DROP operations will be done only if specially * specified in XML file, else it will do only create/alter operations * @var bool */ protected $safeMode = true; function toggleSafeMode($flag = true) { $this->safeMode = (bool) $flag; } function addOp($op, $obj) { if ($obj instanceof Am_DbSync_Table) $this->tableOperations[$obj->getTableName()][$op][0] = $obj; else $this->pieceOperations[$obj->getTableName()][$op][] = $obj; $this->tables[$obj->getTableName()] = $obj->getTable(); } function addCreate($obj) { $this->addOp(self::CREATE, $obj); } function addAlter($obj) { $this->addOp(self::ALTER, $obj); } function addDrop($obj) { $this->addOp(self::DROP, $obj); } function addDropConfirmed($obj) { $this->addOp(self::DROP_CONFIRMED, $obj); } function compareArrays(array $objects1, array $objects2) { $create = array_diff(array_keys($objects1), array_keys($objects2)); $drop = array_diff(array_keys($objects2), array_keys($objects1)); $common = array_intersect(array_keys($objects1), array_keys($objects2)); foreach ($create as $fn) $this->addCreate($objects1[$fn]); foreach ($drop as $fn) $this->addDrop($objects2[$fn]); foreach ($common as $fn) $objects1[$fn]->diff($this, $objects2[$fn]); } function render() { $ret = array(); foreach (array_merge($this->tableOperations, $this->pieceOperations) as $tableName => $ops) { if (!empty($ops[self::CREATE])) foreach ($ops[self::CREATE] as $obj) $ret[] = "CREATE " . $obj->render(); if (!empty($ops[self::ALTER])) foreach ($ops[self::ALTER] as $obj) $ret[] = "MODIFY " . $obj->render(); $dropOp = $this->safeMode ? self::DROP_CONFIRMED : self::DROP; if (!empty($ops[$dropOp])) foreach ($ops[$dropOp] as $obj) $ret[] = "DROP " . $obj->render(); } if ($ret) return implode("\n", $ret) . "\n"; } function getSql($prefix) { $ret = array(); foreach ($this->tableOperations as $tableName => $ops) { if (!$this->safeMode && !empty($ops[self::DROP])) { $ret[] = $ops[self::DROP][0]->getDropSql($prefix); break; } if (!empty($ops[self::CREATE])) { $res = $ops[self::CREATE][0]->getCreateSql($prefix); if (!is_array($res)) $res = array($res); $ret = array_merge($ret, $res); } if (!empty($ops[self::ALTER])) $ret[] = $ops[self::ALTER][0]->getAlterSql($prefix); } foreach ($this->pieceOperations as $tableName => $ops) { if ($this->safeMode) $ops[self::DROP] = @$ops[self::DROP_CONFIRMED]; else unset($ops[self::DROP_CONFIRMED]); $ret = array_merge($ret, $this->tables[$tableName]->getSql($prefix, $ops)); } foreach ($ret as $k => $v) $ret[$k].= ";"; return $ret; } function apply(DbSimple_Interface $db) { $prefix = $db->getPrefix(); foreach ($this->getSql($prefix) as $sql) $db->query($sql); } } /** * @package Am_DbSync */ abstract class Am_DbSync_Object { protected $name; /** @var Am_DbSync_Table */ protected $table; protected $oldNames = array(); public function __construct($name = null, $table = null) { $this->name = $name; $this->table = $table; } function setTable(Am_DbSync_Table $table) { $this->table = $table; } function getTableName() { return $this->table->getName(); } function getName() { return $this->name; } function getTable() { return $this->table; } function getOldNames() { return $this->oldNames; } } /** * structure item - index * @package Am_DbSync */ class Am_DbSync_Index extends Am_DbSync_Object { protected $fields = array(); protected $unique; protected $fulltext; function getFields() { return $this->fields; } static function createFromDb(array $rows) { $f = new self; $f->name = $rows[0]['Key_name']; $f->unique = !empty($rows[0]["Non_unique"]) ? false : true; $f->fulltext = $rows[0]["Index_type"] == 'FULLTEXT' ? true : false; foreach ($rows as $row) { $o = new stdclass; if (!empty($row['Sub_part'])) $o->len = $row['Sub_part']; $f->fields[$row['Column_name']] = $o; } return $f; } function generateXml(SimpleXmlElement $table) { $index = $table->addChild("index"); $index->addAttribute('name', $this->name); if ($this->unique) $index->addAttribute('unique', true); if ($this->fulltext) $index->addAttribute('fulltext', true); foreach ($this->fields as $fieldName => $obj) { $field = $index->addChild('field'); $field->addAttribute('name', $fieldName); if (!empty($obj->len)) $field->addAttribute('len', $obj->len); } } static function createFromXml(SimpleXMLElement $index) { $f = new self; $f->name = (string) $index['name']; $f->unique = ((string) $index['unique']) > 0; $f->fulltext = ((string) $index['fulltext']) > 0; foreach ($index->field as $field) { $o = new stdclass; if ((string) $field['len'] > 0) $o->len = (string) $field['len']; $f->fields[(string) $field['name']] = $o; } if ((string) $index['rename']) $f->oldnames = array_filter(array_map('trim', explode(',', (string) $index['rename']))); return $f; } function getAttribs() { return array( 'name' => $this->name, 'fields' => $this->fields, 'unique' => $this->unique, 'fulltext' => $this->fulltext ); } function diff(Am_DbSync_Diff $diff, Am_DbSync_Index $oldIndex) { if ($oldIndex->getAttribs() != $this->getAttribs()) $diff->addAlter($this); } function render() { return "INDEX " . $this->getTableName() . "." . $this->name; } function getSqlDef() { if ($this->name == 'PRIMARY') { $ret = "PRIMARY KEY ("; } elseif ($this->fulltext) { $ret = "FULLTEXT KEY `{$this->name}` ("; } else { $ret = $this->unique ? "UNIQUE KEY " : "KEY "; $ret.= "`{$this->name}` ("; } foreach ($this->fields as $fieldName => $obj) { $ret .= "`{$fieldName}`"; if (!empty($obj->len)) $ret.="({$obj->len})"; $ret .= ","; } $ret = rtrim($ret, ","); $ret.= ")"; return $ret; } function getCreateSql($prefix) { return "ADD " . $this->getSqlDef(); } function getAlterSql($prefix) { return "DROP INDEX `{$this->name}`, ADD " . $this->getSqlDef(); } function getDropSql($prefix) { return "DROP INDEX `{$this->name}`"; } } /** * structure item - field * @package Am_DbSync */ class Am_DbSync_Field extends Am_DbSync_Object { protected $type; protected $len; protected $unsigned = false; protected $null = true; protected $default; protected $extra; protected $comment; function isInt() { return preg_match('/int$/i', $this->type); } static function createFromDb(array $row) { $f = new self; $f->name = $row['Field']; @list($type, $unsigned) = explode(' ', $row['Type'], 2); if ($unsigned == 'unsigned') $f->unsigned = true; @list($f->type, $f->len) = preg_split('/[()]/', $type); if ($f->isInt()) $f->len = null; $f->null = $row['Null'] == 'YES' ? true : false; $f->default = strlen($row['Default']) ? $row['Default'] : null; $f->comment = $row['Comment']; $f->extra = strlen($row['Extra']) ? $row['Extra'] : null; return $f; } function generateXml(SimpleXmlElement $table) { $field = $table->addChild('field'); $field->addAttribute('name', $this->name); $field->addAttribute('type', $this->type); if ($this->unsigned) $field['unsigned'] = true; if ($this->len) $field->addAttribute('len', $this->len); if (!$this->null) $field->addAttribute('notnull', !$this->null); if (strlen($this->default)) $field->addAttribute('default', $this->default); if (strlen($this->comment)) $field->addAttribute('comment', $this->comment); if ($this->extra !== null) $field->addAttribute('extra', $this->extra); if ($this->oldNames != null) $field->addAttribute('rename', implode(',', $this->oldNames)); } static function createFromXml(SimpleXmlElement $field) { $f = new self; $f->name = (string) $field['name']; $f->type = (string) $field['type']; if (strlen((string) $field['len'])) $f->len = (string) $field['len']; if ((string) $field['unsigned'] > 0) $f->unsigned = true; $f->null = !(string) $field['notnull']; if (isset($field['default'])) $f->default = (string) $field['default']; if (isset($field['comment'])) $f->comment = (string) $field['comment']; if ((string) $field['extra']) $f->extra = (string) $field['extra']; if ((string) $field['rename']) $f->oldNames = array_filter(array_map('trim', explode(',', (string) $field['rename']))); return $f; } function getAttribs() { return array( 'name' => $this->name, 'unsigned' => $this->unsigned, 'type' => $this->type, 'len' => $this->len, 'null' => $this->null, 'default' => $this->default, 'comment' => $this->comment, 'extra' => $this->extra, ); } function diff(Am_DbSync_Diff $diff, Am_DbSync_Field $oldField) { if ($oldField->getAttribs() != $this->getAttribs()) $diff->addAlter($this); } function render() { return "FIELD " . $this->getTableName() . "." . $this->name; } function getSqlDef() { $ret = "`{$this->name}` {$this->type}"; if ($this->len) $ret.= "({$this->len})"; if ($this->unsigned) $ret.= " unsigned"; $ret .= " "; if (!$this->null) $ret .= "NOT NULL "; elseif (!strlen($this->default) && !preg_match('/(blob|text)$/i', $this->type)) $ret .= "DEFAULT NULL "; if (strlen($this->default)) if (in_array($this->default, array('CURRENT_TIMESTAMP', 'NULL'))) $ret .= "DEFAULT " . $this->default . " "; else $ret .= "DEFAULT '" . $this->default . "' "; if (strlen($this->comment)) { $ret .= "COMMENT '" . str_replace("'", "\'", $this->comment) . "' "; } if ($this->extra) $ret .= strtoupper($this->extra); return rtrim($ret); } function getCreateSql($prefix) { return "ADD COLUMN " . $this->getSqlDef(); } function getAlterSql($prefix) { return "MODIFY COLUMN " . $this->getSqlDef(); } function getDropSql($prefix) { return "DROP COLUMN `{$this->name}`"; } } /** * structure item - table * @package Am_DbSync */ class Am_DbSync_Table { protected $name; protected $fields = array(); protected $indexes = array(); protected $oldNames = array(); protected $dropFields = array(); protected $dropIndexes = array(); protected $data = array(); protected $createTableAdd = ""; protected $engine; function __construct($name) { $this->name = $name; } function setCreateTableAdd($add) { $this->createTableAdd = $add; } function getName() { return $this->name; } function getTableName() { return $this->getName(); } function getTable() { return $this; } function getEngine() { return $this->engine; } function addField(Am_DbSync_Field $field) { $field->setTable($this); $this->fields[$field->getName()] = $field; } function getFields() { return $this->fields; } /** @return Am_DbSync_Field|null */ function getField($fieldName) { return @$this->fields[$fieldName]; } function addIndex(Am_DbSync_Index $index) { $index->setTable($this); $this->indexes[$index->getName()] = $index; } function getIndexes() { return $this->indexes; } /** @return Am_DbSync_Index|null */ function getIndex($indexName) { return @$this->indexes[$indexName]; } static function createFromDb($name, array $rows) { $f = new self($name); preg_match('/ENGINE=(MyISAM|InnoDB)/i', $rows[0]['Create Table'], $match); $f->engine = $match[1]; return $f; } function generateXml(SimpleXmlElement $xml) { $table = $xml->addChild("table"); if ($this->oldNames) $table['rename'] = implode(",", $this->oldNames); $table->addAttribute("name", $this->name); if ($this->engine) $table->addAttribute("engine", $this->engine); foreach ($this->getFields() as $field) $field->generateXml($table); foreach ($this->getIndexes() as $index) $index->generateXml($table); return $xml; } /** @return Am_DbSync_Table */ static function createFromXml(SimpleXmlElement $table) { $t = new self((string) $table['name']); if (isset($table['engine']) && $table['engine']) $t->engine = $table['engine']; $t->oldNames = array_filter(array_map('trim', explode(",", $table["rename"]))); foreach ($table->field as $field) $t->addField(Am_DbSync_Field::createFromXml($field)); foreach ($table->index as $index) $t->addIndex(Am_DbSync_Index::createFromXml($index)); foreach ($table->alter as $alter) foreach ($alter->drop as $drop) { if ((string) $drop['field']) $t->addDropField((string) $drop['field']); if ((string) $drop['index']) $t->addDropIndex(((string) $drop['index'])); } // check oldnames $fieldNames = array_keys($t->getFields()); foreach ($t->getFields() as $field) if ($field->getOldNames() && $intersect = array_intersect($fieldNames, $field->getOldNames())) throw new Exception("XML file error - attempt to rename a field defined in schema /scheme/table[{$t->name}]/field=[{$intersect[0]}] to [{$field->getName()}]"); $indexNames = array_keys($t->getIndexes()); foreach ($t->getIndexes() as $index) if ($index->getOldNames() && $intersect = array_intersect($indexNames, $index->getOldNames())) throw new Exception("XML file error - attempt to rename an index defined in schema /scheme/table[{$t->name}]/index=[{$intersect[0]}] to [{$index->getName()}]"); // create by data if ($table->data && $table->data->query) foreach ($table->data->query as $query) $t->data[] = (string) $query; // create by table_data if ($table->table_data && $table->table_data->row) { foreach ($table->table_data->row as $row) { $record = array(); foreach ($row->field as $field) $record[(string) $field['name']] = (string) $field; $t->data[] = $record; } } return $t; } function merge(Am_DbSync_Table $table) { foreach ($table->getFields() as $field) $this->addField($field); foreach ($table->getIndexes() as $index) $this->addIndex($index); // @TODO merge other attributes too (alter, etc.) } function addDropField($fieldName) { if (array_key_exists($fieldName, $this->fields)) throw new Exception("XML file error - attempt to drop field /scheme/table[{$this->name}]/alter/drop[field={$fieldName}] also specified in XML as existing field"); $this->dropFields[] = $fieldName; } function addDropIndex($indexName) { if (array_key_exists($indexName, $this->indexes)) throw new Exception("XML file error - attempt to drop index /scheme/table[{$this->name}]/alter/drop[index={$indexName}] also specified in XML as existing index"); $this->dropIndexes[] = $indexName; } /** * @param Am_DbSyncTable $compareTo * @return array of differences */ function diff(Am_DbSync_Diff $diff, Am_DbSync_Table $compareTo) { if ($this->getEngine() && ($this->getEngine() != $compareTo->getEngine())) $diff->addAlter($this); $diff->compareArrays($this->getFields(), $compareTo->getFields()); $diff->compareArrays($this->getIndexes(), $compareTo->getIndexes()); foreach ($this->dropFields as $fieldName) if ($compareTo->getField($fieldName)) $diff->addDropConfirmed(new Am_DbSync_Field($fieldName, $this)); foreach ($this->dropIndexes as $indexName) if ($compareTo->getIndex($indexName)) $diff->addDropConfirmed(new Am_DbSync_Index($indexName, $this)); } function render() { return "TABLE " . $this->name; } function getSql($prefix, array $ops) { $ret = array(); if (!empty($ops[Am_DbSync_Diff::CREATE])) foreach ($ops[Am_DbSync_Diff::CREATE] as $obj) $ret[] = $obj->getCreateSql($prefix); if (!empty($ops[Am_DbSync_Diff::DROP])) foreach ($ops[Am_DbSync_Diff::DROP] as $obj) $ret[] = $obj->getDropSql($prefix); if (!empty($ops[Am_DbSync_Diff::ALTER])) foreach ($ops[Am_DbSync_Diff::ALTER] as $obj) $ret[] = $obj->getAlterSql($prefix); if (!$ret) return array(); return array("ALTER TABLE `{$prefix}{$this->name}` " . implode(", ", $ret)); } function getCreateSql($prefix) { $dataSql = (array) $this->getDataSql($prefix); $ret = "CREATE TABLE `{$prefix}{$this->name}` (\n"; $items = array(); foreach ($this->getFields() as $field) $items[] = " " . $field->getSqlDef(); foreach ($this->getIndexes() as $index) $items[] = " " . $index->getSqlDef(); $ret .= implode(",\n", $items) . "\n)"; $ret .= $this->engine ? ' ENGINE=' . $this->engine : ''; $ret .= $this->createTableAdd; array_unshift($dataSql, $ret); return $dataSql; } function _escape($v) { $search = array("\\", "\0", "\n", "\r", "\x1a", "'", '"'); $replace = array("\\\\", "\\0", "\\n", "\\r", "\Z", "\'", '\"'); return str_replace($search, $replace, $v); } function getDataSql($prefix) { $ret = array(); foreach ($this->data as $d) { if (is_string($d)) $ret[] = $d; elseif (is_array($d)) { $s = "INSERT INTO $prefix" . $this->getTableName(); $s .= " SET "; foreach ($d as $k => $v) $s .= "`$k`='" . $this->_escape($v) . "',"; $s = trim($s, ","); $ret[] = $s; } } return $ret; } function getDropSql($prefix) { return "DROP TABLE `{$prefix}{$this->name}`"; } function getAlterSql($prefix) { return "ALTER TABLE `{$prefix}{$this->name}` ENGINE={$this->engine}"; } function addOldName($name) { $this->oldNames[] = trim($name); } function getOldNames() { return $this->oldNames; } } /** * sync mysql database structure and its XML representation * @package Am_DbSync */ class Am_DbSync { protected $tables = array(); protected $dropTables = array(); protected $createTableAdd = ""; const CREATE_UTF8 = " CHARACTER SET utf8 COLLATE utf8_general_ci"; public function __construct($utf8 = true) { if ($utf8) $this->setCreateTableAdd(self::CREATE_UTF8); } function setCreateTableAdd($add) { $this->createTableAdd = $add; } /** @return Am_DbSync_Table */ function addTable(Am_DbSync_Table $table) { $table->setCreateTableAdd($this->createTableAdd); return $this->tables[$table->getName()] = $table; } /** @return Am_DbSync_Table */ function getTable($tableName) { return @$this->tables[$tableName]; } function getTables() { return $this->tables; } function addDropTable($tableName) { if (!$tableName) throw new Exception("Empty tablename passed to " . __METHOD__); if (array_key_exists($tableName, $this->tables)) throw new Exception("XML file error - attempt to drop table /scheme/alter/drop[table={$tableName}] also specified in XML as existing table"); return $this->dropTables[] = $tableName; } /** * @return SimpleXmlElement|string */ public function generateXml($returnFormatted = false, $version=null) { $xml = new SimpleXMLElement(""); foreach ($this->getTables() as $table) $table->generateXml($xml); if ($returnFormatted) { $doc = new DOMDocument('1.0'); $doc->formatOutput = true; $domnode = dom_import_simplexml($xml); $domnode = $doc->importNode($domnode, true); $domnode = $doc->appendChild($domnode); return $doc->saveXML(); } else return $xml; } /** * @return Am_DbSync_Diff */ public function diff(Am_DbSync $compareTo) { $diff = new Am_DbSync_Diff; $diff->compareArrays($this->getTables(), $compareTo->getTables()); foreach ($this->dropTables as $tableName) if ($compareTo->getTable($tableName)) $diff->addDropConfirmed(new Am_DbSync_Table($tableName)); return $diff; } public function parseTables(DbSimple_Interface $db) { $prefix = $db->getPrefix(); foreach ($db->selectCol("SHOW TABLES LIKE ?", $prefix . '%') as $tablename) { if (strlen($prefix) && (strpos($tablename, $prefix) !== 0)) continue; // other prefix? $name = substr($tablename, strlen($prefix)); $table = Am_DbSync_Table::createFromDb($name, $db->select("SHOW CREATE TABLE ?#", $tablename)); foreach ($db->select("SHOW FULL COLUMNS FROM ?#", $tablename) as $row) $table->addField(Am_DbSync_Field::createFromDb($row)); $indexes = array(); foreach ($db->select("SHOW INDEX FROM ?#", $tablename) as $row) $indexes[$row['Key_name']][] = $row; foreach ($indexes as $indexRows) $table->addIndex(Am_DbSync_Index::createFromDb($indexRows)); $this->addTable($table); } } public function parseXml($xmlString) { $xml = new SimpleXMLElement($xmlString); foreach ($xml->table as $table) { $table = Am_DbSync_Table::createFromXml($table); if ($this->getTable($table->getName())) $this->getTable($table->getName())->merge($table); else $this->addTable($table); } foreach ($xml->alter as $alter) $this->parseAlter($alter); } protected function parseAlter(SimpleXMLElement $xml) { foreach ($xml->children() as $el) { if ($el->getName() == 'drop') $this->addDropTable((string) $el['table']); else throw new Exception("Unknown element found in XML: schema/alter/" . $el->getName()); } } } PK\Form.phpnu[addFilter(array(__CLASS__, '_trimArray')); if ($id === null) $id = str_replace('\\', '_', get_class($this)); $i = 0; $suggestId = $id; while (isset(self::$_usedIds[$suggestId])) { $suggestId = $id . '-' . ++$i; } $id = $suggestId; self::$_usedIds[$id] = 1; if (!$attributes) $attributes = array(); if (empty($attributes['action'])) $attributes['action'] = preg_replace('/\?.*/', '', $_SERVER['REQUEST_URI']); parent::__construct($id, $method, $attributes, false); $this->addElement('hidden', '_save_')->setValue($id); $this->init(); } public function addElement($elementOrType, $name = null, $attributes = null, array $data = array()) { $ret = parent::addElement($elementOrType, $name, $attributes, $data); if ($ret instanceof HTML_QuickForm2_Element_InputFile) $this->setAttribute('enctype', 'multipart/form-data'); return $ret; } function addSaveButton($title = null) { if ($title === null) $title = ___("Save"); return $this->addSubmit('save', array('value'=>$title)); } static function _trimArray($var) { array_walk_recursive($var, array(__CLASS__, '_trim')); return $var; } static function _trim(& $var) { if (is_string($var)) $var = trim($var); } /** * Add your elements here */ function init() {} public function addCsrf() { $csrf = new Am_Form_Element_Csrf('_csrf'); $this->addElement($csrf)->setId('_csrf'); return $csrf; } /** * Determine if form was submitted * @return bool */ function isSubmitted() { $origId = preg_replace('#\\\+#', '_', $this->getId()); foreach ($this->getDataSources() as $ds) { $id = preg_replace('#\\\+#', '_', $ds->getValue('_save_')); if ($id == $origId) return true; } return false; } function addProlog($string) { $this->prolog .= $string; } function addEpilog($string) { $this->epilog .= $string; } /** return rendered code before prolog; } /** return rendered code after tag */ function renderEpilog() { return $this->epilog; } function setAction($url) { $this->setAttribute('action', $url); } public function __toString() { $view = new Am_View(); $view->form = $this; return $view->render('_form.phtml'); } public function render(HTML_QuickForm2_Renderer $renderer) { if (method_exists($renderer->getJavascriptBuilder(), 'addValidateJs')) { $renderer->getJavascriptBuilder()->addValidateJs('errorElement: "span"'); } Am_Di::getInstance()->hook->call(Am_Event::FORM_BEFORE_RENDER, array('form' => $this)); return parent::render($renderer); } public function setWidth($cssWidth) { $this->width = (string)$cssWidth; } public function getWidth() { return $this->width; } /** @return object with rendered input elements + ->hidden for hidden inputs */ public function toObject() { $arr = $this->render(HTML_QuickForm2_Renderer::factory('array'))->toArray(); $ret = new stdclass; foreach ($arr['elements'] as $el) $ret->{preg_replace('/-\d+$/', '', $el['id'])} = $el['html']; $ret->_id = $arr['id']; $ret->_hidden = implode("\n", $arr['hidden']); $ret->_javascript = $arr['javascript']; $ret->_attributes = $arr['attributes']; return $ret; } public function getAllErrors() { $ret = array(); if ($this->getError()) $ret[] = $this->getError(); foreach ($this->getIterator() as $el) if ($el->getError()) $ret[] = $el->getError(); return $ret; } public function removeElementByName($name) { foreach ($this->getIterator() as $el) if ($el->getName() == $name) $el->getContainer()->removeChild($el); } public function findRuleMessage(HTML_QuickForm2_Rule $rule, HTML_QuickForm2_Node $el) { $strings = array( 'rule.required' => ___('This is a required field'), ); $type = lcfirst(preg_replace('/^.+rule_/i', '', get_class($rule))); $tr = Zend_Registry::get('Zend_Translate'); $fuzzy = sprintf('rule.%s', $type); if (array_key_exists($fuzzy, $strings)) return $strings[$fuzzy]; } /** * @return array of elements for easy custom form building */ public function renderEasyArray() { $renderer = HTML_QuickForm2_Renderer::factory('array'); $renderer->setJavascriptBuilder(new Am_Form_JavascriptBuilder); $renderer->getJavascriptBuilder()->addValidateJs('errorElement: "span"'); /* @var $renderer HTML_QuickForm2_Renderer_Array */ $this->render($renderer); $arr = $renderer->toArray(); if (isset($arr['hidden'])) $arr['hidden'] = implode("\n", $arr['hidden']); $this->_renderArrayGroups($arr); return $arr; } /** * Modify array created by HTML_QuickForm2_Renderer_Array * so groups contains html of containting elements * @param array $arr */ protected function _renderArrayGroups(array & $arr, $level = 0) { // replace numeric ids with element ids foreach ($arr['elements'] as $k => $v) if (!empty($v['id'])) { unset($arr['elements'][$k]); $arr['elements'][$v['id']] = $v; } if ($level && !isset($arr['html'])) { $arr['html'] = ''; $arr['htmle'] = ''; } foreach ($arr['elements'] as & $v) { if (isset($v['elements'])) $this->_renderArrayGroups($v, $level+1); // merge elements html and error - create htmle if (!empty($v['error'])) $error = ''.Am_Html::escape($v['error']).'
'; else $error = ""; $v['htmle'] = $error . $v['html']; if ($level) { $arr['html'] .= $v['html']; $arr['htmle'] .= $v['htmle']; } } } } HTML_QuickForm2_Factory::registerElement('name', 'Am_Form_Element_Name'); HTML_QuickForm2_Factory::registerElement('raw', 'Am_Form_Element_Raw'); HTML_QuickForm2_Factory::registerElement('period', 'Am_Form_Element_Period'); HTML_QuickForm2_Factory::registerElement('date', 'Am_Form_Element_Date'); HTML_QuickForm2_Factory::registerElement('datetime', 'Am_Form_Element_DateTime'); HTML_QuickForm2_Factory::registerElement('integer', 'Am_Form_Element_Integer'); HTML_QuickForm2_Factory::registerElement('advcheckbox', 'Am_Form_Element_AdvCheckbox'); HTML_QuickForm2_Factory::registerElement('advradio', 'Am_Form_Element_AdvRadio'); HTML_QuickForm2_Factory::registerElement('email_checkbox', 'Am_Form_Element_EmailCheckbox'); HTML_QuickForm2_Factory::registerElement('email_select', 'Am_Form_Element_EmailSelect'); HTML_QuickForm2_Factory::registerElement('email_link', 'Am_Form_Element_EmailLink'); HTML_QuickForm2_Factory::registerElement('email_with_days', 'Am_Form_Element_EmailWithDays'); HTML_QuickForm2_Factory::registerElement('upload', 'Am_Form_Element_Upload'); HTML_QuickForm2_Factory::registerElement('script', 'Am_Form_Element_Script'); HTML_QuickForm2_Factory::registerElement('html', 'Am_Form_Element_Html'); HTML_QuickForm2_Factory::registerElement('csrf', 'Am_Form_Element_Csrf'); HTML_QuickForm2_Factory::registerElement('options_editor', 'Am_Form_Element_OptionsEditor'); HTML_QuickForm2_Factory::registerElement('htmleditor', 'Am_Form_Element_HtmlEditor'); HTML_QuickForm2_Factory::registerElement('magicselect', 'Am_Form_Element_MagicSelect'); HTML_QuickForm2_Factory::registerElement('sortablemagicselect', 'Am_Form_Element_SortableMagicSelect'); HTML_QuickForm2_Factory::registerElement('checkboxedgroup', 'Am_Form_Element_CheckboxedGroup'); HTML_QuickForm2_Factory::registerElement('advfieldset', 'Am_Form_Container_AdvFieldset'); HTML_QuickForm2_Factory::registerElement('multi_select', 'Am_Form_Element_MultiSelect'); HTML_QuickForm2_Factory::registerElement('category', 'Am_Form_Element_Category'); HTML_QuickForm2_Factory::registerRule('callback2', 'Am_Rule_Callback2'); HTML_QuickForm2_Factory::registerRule('remote', 'HTML_QuickForm2_Rule_Remote'); /** * Callback function must return error message if failed, * and empty string or null if OK */ class Am_Rule_Callback2 extends HTML_QuickForm2_Rule_Callback { /** * Validates the owner element * * @return bool the value returned by a callback function */ protected function validateOwner() { $value = $this->owner->getValue(); $config = $this->getConfig(); $ret = call_user_func_array( $config['callback'], array_merge(array($value), array($this->owner), $config['arguments']) ); $this->setMessage($ret); return (bool)($ret == ""); } } /** * Just for client side validation */ class HTML_QuickForm2_Rule_Remote extends HTML_QuickForm2_Rule { protected function validateOwner() { return true; } protected function getJavascriptCallback() { return "function () { return true; }"; } } class Am_Form_Element_Raw extends HTML_QuickForm2_Element_Static { public function __toString() { return $this->getIndent() . $this->getContent(); } } class Am_Form_Element_Integer extends HTML_QuickForm2_Element_Input { protected $attributes = array('type' => 'text', 'size' => 5, 'maxlength' => 10,); public function __construct($name = null, $attributes = null, $data = null) { parent::__construct($name, $attributes, $data); $this->addRule('regex', 'Integer value required', '/^\d+$/'); } } class Am_Form_Element_OptionsEditor extends HTML_QuickForm2_Element_Input { protected $attributes = array('type' => 'hidden'); public function __construct($name = null, $attributes = null, $data = null) { if (is_array($attributes) && isset($attributes['class'])) { $attributes['class'] = $attributes['class'] . ' options-editor'; } else { $attributes['class'] = 'options-editor'; } parent::__construct($name, $attributes, $data); } public function setValue($value) { $value = is_array($value) ? json_encode($this->doOrder($value)) : $value; parent::setValue($value); } public function getRawValue() { $value = parent::getRawValue(); return $this->doOrder(json_decode($value, true)); } protected function doOrder($v) { if (!$v) return $v; if (isset($v['order'])) { //from element $op = array(); foreach ($v['order'] as $k) { $op[$k] = $v['options'][$k]; } $v['options'] = $op; unset($v['order']); } else { //to element $v['order'] = !empty($v['options']) ? array_keys($v['options']) : array(); } return $v; } } class Am_Form_Element_AdvCheckbox extends HTML_QuickForm2_Element_InputCheckbox { // Do not change element value if there is no element in datasources; function setValue($value) { if(is_null($value)) return $this; return parent::setValue($value); } /** * returns empty string instead of null, so value is present in Form::getValue() */ function getValue() { $value = parent::getValue(); $data = $this->getData(); $empty_value = isset($data['empty_value']) ? $data['empty_value'] : ""; return $value == null ? $empty_value : $value; } } class Am_Form_Element_Category extends HTML_QuickForm2_Container_Group { public function __construct($name = null, $attributes = null, $data = null) { parent::__construct(null, $attributes, $data); $this->setSeparator(' '); $sel = $this->addSelect($name, array('multiple'=>'multiple', 'class'=>'magicselect')) ->loadOptions($data['options']); $id = $sel->getId(); $this->addHtml()->setHtml(sprintf('', $id, Am_Di::getInstance()->url($data['base_url']), $data['link_title'])); $root = REL_ROOT_URL; $url = json_encode(Am_Di::getInstance()->url($data['base_url'].'/options',false)); $this->addScript() ->setScript(<<'); jQuery('body').append(div); div.load(this.href, function(){ div.dialog({ title: '{$data['title']}', modal: true, autoOpen : true, width: Math.min(700, Math.round(jQuery(window).width() * 0.7)), close : function(){ jQuery('#node-form').dialog('destroy'); jQuery('#am-category-manage').dialog('destroy'); jQuery('#am-category-manage').remove(); jQuery.get($url, function(res){ jQuery('#$id').empty(); for (var k in res) { jQuery('#$id').append(jQuery('').attr('value', k).html(res[k])); } jQuery('#$id').restoreMagicSelect(); }) } }) }) return false; }) CUT ); } } class Am_Form_Element_CheckboxedGroup extends HTML_QuickForm2_Container_Group { public function __construct($name = null, $attributes = null, $data = null) { parent::__construct(null, $attributes, $data); $this->setSeparator(' '); $el = $this->addAdvCheckbox($name); $id = $el->getId(); $this->addScript()->setScript(<<)([\s\S]+)/, '$1$2')); jQuery(".checkboxed-cnt", el).toggle( jQuery("#$id").is(":checked") ); jQuery("#$id").change(function() { jQuery(this).closest(".element").find(".checkboxed-cnt").toggle( this.checked ); }); }); // end of init checkboxed group CUT ); } } class Am_Form_Element_Name extends HTML_QuickForm2_Element_InputText { protected function updateValue() { parent::updateValue(); if (!$this->getValue()) { foreach ($this->getDataSources() as $ds) { if (null !== ($name_f = $ds->getValue('name_f')) | null !== ($name_l = $ds->getValue('name_l'))) { $this->setValue("$name_f $name_l"); return; } } } } } class Am_Form_Element_AdvRadio extends HTML_QuickForm2_Element_Select { protected $separator = "
\n"; /** * Support list of options like it is done for  %s', htmlentities($id), htmlentities($this->getName()), $attrs, htmlentities($id), $option['attr']['value'] == $this->getValue() ? ' checked="checked"' : '', $option['text'] ); } return $out ? implode($this->separator, $out) : ''; } function setSeparator($string) { $this->separator = $string; } } class Am_Form_Element_SignupCheckboxGroup extends HTML_QuickForm2_Element { protected $options = array(); protected $type = 'checkbox'; public function __construct($name = null, $options, $type) { parent::__construct($name, null, null); $this->options = $options; $this->type = $type; } public function __toString() { /* *
* * * *
*/ $ret = array(); $name = Am_Html::escape($this->getName()); foreach ($this->options as $o) { $value = Am_Html::escape($o['options']['value']); $id = 'product-' . $value; $label = $o['options']['label']; $attrs = ""; foreach ($o as $k=>$v) { if ($k == 'options') continue; $attrs .= Am_Html::escape($k) . '="' . Am_Html::escape($v) . '" '; } if ($o['options']['selected']) $attrs .= 'checked="checked" '; $qty_input = ""; if ($o['options']['variable_qty']) { $qty = (int)$o['options']['qty']; if (!$qty) $qty = 1; $qty_attrs = $this->type != 'hidden' ? "disabled='disabled' style='display:none;'" : ""; $qty_input = ""; } $el_name = $this->type == 'checkbox' ? "{$name}[{$value}]" : ($name.'[]'); $value = Am_Html::escape($o['options']['value']); $ret[] = " "; } $add_empty = ''; if ($this->type == 'checkbox') { $name = Am_Html::escape($this->getName() . '[]'); $add_empty = sprintf('', $name); } return $add_empty . implode('
', $ret); } public function getRawValue() { $ret = array(); foreach ($this->options as $o) { $opt = $o['options']; if (!$opt['selected']) continue; $ret[] = $opt['value'] . '-' . $opt['qty']; } return $ret; } public function getType() { return 'signup-form-checkboxes'; } public function setValue($value) { /* for checkbox we get something like: * Array( [1] => 1 [2] => 2 [_qty-2] => 3 ) */ foreach ($value as $k => $v) { // restore from getValue() format if (preg_match('#(\d+-\d+)-(\d+)#', $v, $regs)) { $v = $regs[1]; $value['_qty-'.$v] = $regs[2]; } // now process if (!array_key_exists($v, $this->options)) continue; $opt = & $this->options[$v]['options']; $opt['selected'] = true; $qk = '_qty-' . $v; if ($opt['variable_qty'] && array_key_exists($qk, $value) && (trim($value[$qk])>0)) $opt['qty'] = trim($value[$qk]); } } } class Am_Form_Element_Upload extends HTML_QuickForm2_Element_InputText { protected $prefix = null; protected $upload_id = null; protected $secure = null; protected $mimeTypes = array(); protected $jsOptions = '{}'; const EMPTY_VAL = -1; public function __construct($name = null, $attributes = null, $data = null) { if (!is_null($attributes) && isset($attributes['class'])) { $attributes['class'] = $attributes['class'] . ' ' . 'upload'; } else { $attributes['class'] = 'upload'; } if (!is_array($data) || !isset($data['prefix'])) { throw new Am_Exception_InternalError('prefix is not defined in element ' . __CLASS__); } $this->prefix = $data['prefix']; $this->secure = isset($data['secure']) ? $data['secure'] : false; unset($data['secure']); unset($data['prefix']); $attributes['data-prefix'] = $this->prefix; $attributes['data-secure'] = $this->secure ? 1 : 0; $attributes['data-info'] = json_encode(array()); $attributes['data-error'] = json_encode(array()); parent::__construct($name, $attributes, $data); } public function setAllowedMimeTypes(array $mimeTypes) { $this->mimeTypes = $mimeTypes; $this->_setJsOptions(); return $this; } public function __toString() { try { if ($this->frozen) { return $this->getFrozenHtml(); } else { if (empty($this->attributes['multiple'])) { $attrString = $this->getAttributes(true); } else { $this->attributes['name'] .= '[]'; $attrString = $this->getAttributes(true); $this->attributes['name'] = substr($this->attributes['name'], 0, -2); } $indent = $this->getIndent(); return $indent . ''; } } catch (Exception $e) { echo "Internal Error:" . $e->getMessage(); exit(); } } public function getFrozenHtml() { $value = $this->getValue(); if (!$value) return ''; $value = empty($this->attributes['multiple']) ? array($value) : $value; $renderedFiles = array(); $hiddens = array(); foreach (array_filter($value) as $upload_id) { $upload = Am_Di::getInstance()->uploadTable->load($upload_id); $renderedFiles[] = sprintf('%s (%s)', Am_Di::getInstance()->url('admin-upload/get',array('id'=>$upload->pk())), $upload->getName(), $upload->getSizeReadable() ); $hiddens[] = sprintf('', $this->getName() . (empty($this->attributes['multiple']) ? '' : '[]'), ($this->secure ? $this->signValue($upload->pk()) : $upload->pk()) ); } return sprintf("
%s\n%s
", implode(', ', $renderedFiles), implode("\n", $hiddens) ); } protected function filterValue($val) { if (!$val) return $val; if (is_scalar($val) && $this->checkSign($val)) { return $this->trimSign($val); } if (is_array($val)) { $val = array_filter($val, array($this, 'checkSign')); foreach ($val as $k=>$v) { $val[$k] = $this->trimSign($v); } return $val; } return null; } protected function trimSign($val) { list($val) = explode("|", $val); return $val; } public static function signValue($val) { if ($val == self::EMPTY_VAL) return $val; if (strpos($val, '|')!==false) return $val; $val = $val . '|' . self::sign($val); return $val; } protected function checkSign($val) { if ($val == self::EMPTY_VAL) return true; if(!$val) return false; @list($val, $sign) = explode('|', $val); if (!$sign) return false; return $this->sign($val) == $sign; } protected static function sign($val) { return Am_Di::getInstance()->security->siteHash($val, 5); } public function setValue($value) { $data = array(); $error = array(); $value = array_filter(empty($this->attributes['multiple']) ? array($value) : (array)$value); $hasEmpty = false; foreach ($value as $k => $v) { if ($v == self::EMPTY_VAL) { unset($value[$k]); $hasEmpty = true; break; } } foreach ($value as $k => $upload_id) { try { $upload = Am_Di::getInstance()->plugins_storage->getFile($upload_id); if ($upload) { $data[$this->secure ? $this->signValue($upload_id) : $upload_id] = $upload->info(); } } catch (Exception $e) { Am_Di::getInstance()->errorLogTable->logException($e); $error[] = $e->getMessage(); unset($value[$k]); } } $this->setAttribute('data-error', json_encode($error)); if (!$hasEmpty && !$value) return; reset($value); if ($this->secure) { $value = array_map(array($this, 'signValue'), $value); } $plainValue = empty($this->attributes['multiple']) ? current($value) : implode(',', $value); $this->setAttribute('data-info', json_encode($data)); parent::setValue($plainValue); } function getRawValue() { $value = parent::getRawValue(); $val = (empty($this->attributes['multiple']) || is_null($value)) ? $value : explode(',', $value); return $this->secure ? $this->filterValue($val) : $val; } protected function updateValue() { $name = $this->getName(); //proceess upload only once fo each name static $executed = array(); if (!isset($executed[$name])) { $executed[$name]=1; $name = $this->getName(); $upload = new Am_Upload(Am_Di::getInstance()); $upload->setPrefix($this->prefix); $upload->loadFromStored(); $ids_before = $this->getUploadIds($upload); $upload->processSubmit($name); //find currently uploaded file $x = array_diff($this->getUploadIds($upload), $ids_before); $upload_id = array_pop($x); if ($upload_id) { $this->upload_id = $upload_id; } } $value = null; foreach ($this->getDataSources() as $ds) { if (null !== ($value = $ds->getValue($name))) { break; } } if ($this->secure && $value && isset($ds) && ($ds instanceof HTML_QuickForm2_DataSource_Submit)) { $value = $this->filterValue($value); } if (empty($this->attributes['multiple'])) { $value = $this->upload_id ? $this->upload_id : $value; } else { if ($value) { $value = $this->upload_id ? array_merge($value, array($this->upload_id)) : $value; } else { $value = $this->upload_id ? array($this->upload_id) : null; } } $this->setValue($value); } protected function getUploadIds(Am_Upload $upload) { $upload_ids = array(); foreach($upload->getUploads() as $upload) { $upload_ids[] = $upload->pk(); } return $upload_ids; } /** * @param string $jsOptions */ public function setJsOptions($jsOptions) { $this->jsOptions = $jsOptions; $this->_setJsOptions(); return $this; } protected function getAllJsOptions() { $jsOptions = $this->jsOptions; if (!count($this->mimeTypes)) { return $jsOptions; } $jsOptions = trim($jsOptions); $jsOptions = trim($jsOptions, '{},'); $jsOptions .= ($jsOptions ? ',' : '') . sprintf("\nfileMime : [%s]", implode(',', array_map(function($el) {return "'$el'";}, $this->mimeTypes)) ); return sprintf("{%s}", $jsOptions); } protected function _setJsOptions() { $jsOptions = $this->getAllJsOptions(); $classes = explode(' ', $this->getAttribute('class')); $customClassHere = false; foreach ($classes as $k=>$class) { if ($class == 'upload') { unset($classes[$k]); } if ($class == 'custom-' . $this->getId()) { $customClassHere = true; } } if (!$customClassHere) { $classes[] = 'custom-' . $this->getId(); } $this->setAttribute('class', implode(' ', $classes)); $id = $this->getId(); $jsScript = <<getContainer()->getElementsByName('script-' . $this->getId()); if (count($elements)) { $script = $elements[0]; } else { $script = $this->getContainer()->addElement('script', 'script-' . $this->getId()); } $script->setScript($jsScript); } } class Am_Form_Element_DateTime extends HTML_QuickForm2_Element_Input { function setValue($value) { if (is_array($value)) { $value['d'] = Am_Form_Element_Date::convertReadableToSQL($value['d']); $value = implode(' ', $value); } parent::setValue($value); } function __toString() { list($d, $t) = explode(' ', $this->getValue()); $t = explode(':', $t); if (count($t) == 3) unset($t[2]); $t = implode(':', $t); return sprintf(<< CUT , $this->getName(), $this->getId(), Am_Html::escape(amDate($d)), $this->getName(), $this->getId(), Am_Html::escape($t)); } } class Am_Form_Element_Date extends HTML_QuickForm2_Element_InputText { const DATE_FORMAT_SQL_REGEXPR = '/^\d{4}-\d{2}-\d{2}$/'; public function __construct($name = null, $attributes = null, $data = null) { if (!is_null($attributes) && isset($attributes['class'])) { $attributes['class'] = $attributes['class'] . ' ' . 'datepicker'; } else { $attributes['class'] = 'datepicker'; } $attributes['size'] = isset($attributes['size']) ? $attributes['size'] : 10; parent::__construct($name, $attributes, $data); $this->addRule('callback2', 'error', array($this, 'checkDate')); } public function checkDate($date) { if ($date === false) { return ___('Date must be in format %s', Am_Di::getInstance()->locale->getDateFormat()); } } /** * @param string $value date in SQL or Readable format */ public function setValue($value) { if (preg_match(self::DATE_FORMAT_SQL_REGEXPR, $value)) { //SQL format parent::setValue(self::convertSqlToReadable($value)); } else { //Readable format parent::setValue($value); } } /** * @return mixed (string|null|false) @see self::convertReadableToSQL */ public function getValue() { return self::convertReadableToSQL(parent::getValue()); } /** * @param string $date date in Readable format * @return mixed (string|false|null) date in SQL format, null - string is empty, false - string is incorrect */ public static function convertReadableToSQL($date) { if (!$date) return null; $format = Am_Di::getInstance()->locale->getDateFormat(); if (is_callable(array('DateTime', 'createFromFormat'))) { $d = DateTime::createFromFormat($format, $date); if(!$d) $d = new DateTime($date); if(!$d) return $date; if ($d->format('Y') > 2037) //respect cutoff year $d->modify('-100 years'); } else $d = self::createFromFormat($format, $date); if ($d === false) return false; return $d->format('Y-m-d'); } /** * Parse date from string (for PHP 5.2.x) * @param string $dateFormat subset of DateTime::createFromFormat() : dmyYM or null to use default * @param strin $string to parse * @return DateTime|false */ public static function createFromFormat($dateFormat = null, $string) { if ($dateFormat === null) $dateFormat = Am_Di::getInstance()->locale->getDateFormat(); $dt = DateTime::createFromFormat($dateFormat, $string); $dt->setTime(0,0,0); return $dt; } public static function convertSqlToReadable($date) { if (!$date) return ''; return date(Am_Di::getInstance()->locale->getDateFormat(), strtotime($date)); } } class Am_Form_Element_EmailCheckbox extends Am_Form_Element_AdvCheckbox { function __construct($name = null, $attributes = null, array $data = array()) { $data['empty_value'] = 0; parent::__construct($name, $attributes, $data); } function __toString() { return Am_Form_Element_EmailLink::decorateWithLink(parent::__toString(), $this); } } class Am_Form_Element_EmailSelect extends HTML_QuickForm2_Element_Select { function __toString() { return Am_Form_Element_EmailLink::decorateWithLink(parent::__toString(), $this); } } class Am_Form_Element_EmailLink extends HTML_QuickForm2_Element { function setValue($value) { } function getRawValue() { return null; } function getType() { return 'email_link'; } function updateValue() { } function __toString() { return self::decorateWithLink('', $this); } public static function decorateWithLink($str, HTML_QuickForm2_Element $el) { return self::getPrefix($el) . $str . ( ($el instanceof HTML_QuickForm2_Element_Select) ? '
' : ' ' ) . self::getEditLink($el); } public static function getPrefix(HTML_QuickForm2_Element $el) { return sprintf('', $el->getName()); } public static function getEditLink($el, $day = null, $product_id=null) { $label = $el->getLabel(); if (is_array($label)) { $label = array_map('strip_tags', $label); $label = implode(' ', $label); } $params = array( 'name' => Am_Form_Setup::name2dots($el->getName()), 'b' => $_SERVER['REQUEST_URI'] . '#' . $el->getName(), 'label' => $label ); if (!is_null($day)) { $params['day'] = (int)$day; } $url = Am_Di::getInstance()->url('admin-email-templates/edit', $params); $attr = $el->getAttributes(); return sprintf('', $url , isset($attr['rel']) ? Am_Html::escape($attr['rel']) : '', ___('Edit E-Mail Template') ); } } class Am_Form_Element_PendingNotificationRules extends HTML_QuickForm2_Element { function setValue($valus) {} function getRawValue() { return null; } function getType() { return 'pending_notification_rules'; } function updateValue(){} protected function renderRule($tpl) { return sprintf ('%s %s', $this->getFrequencyString(array_filter(explode(',', $tpl->days), function($a) {return $a!=="";})), $this->getConditionString($tpl->conditions)); } protected function getNumberString($i) { switch ($i) { case 1 : return $i . 'st'; break; case 2 : return $i . 'nd'; break; case 3 : return $i . 'rd'; break; default : return $i . 'th'; } } protected function getConditionString($conditions) { if (!$conditions) return 'for any invoices'; $res = ''; $conds = array(); foreach(explode(',', $conditions) as $item) { preg_match('/([A-Z]*)-(.*)/', $item, $match); $conds[$match[1]][] = $match[2]; } if (isset($conds['PRODUCT'])) { $res = sprintf('product IN (%s)', implode(', ', Am_Di::getInstance()->productTable->getProductTitles($conds['PRODUCT']))); } if (isset($conds['CATEGORY'])) { $options = Am_Di::getInstance()->productCategoryTable->getAdminSelectOptions(); $categories = array(); foreach ($conds['CATEGORY'] as $category_id) { $categories[] = $options[$category_id]; } $res .= ($res ? ' OR ' : '') . sprintf('product category IN (%s)', implode(', ', $categories)); } if (isset($conds['PAYSYSTEM'])) { $res .= ($res ? ' AND ' : '') . sprintf('paysystem IN (%s)', implode(', ', $conds['PAYSYSTEM'])); } return 'if ' . $res; } protected function getFrequencyString($days) { $add_end = false; if (!count($days)) { return 'never'; } $res = ''; if (!$days[0]) { $add_end = true; array_shift($days); $res = 'immediately'; } if (count($days)) { $hours = array(); while(isset($days[0]) && substr($days[0], -1) == 'h') { $h = array_shift($days); $hours[] = str_replace('h', '', $h); } if (count($hours)) { $add_end = true; $hours = array_map(array($this, 'getNumberString'), $hours); $res .= ($res ? ' and ' : '') . 'on ' . '' . implode(', ', $hours) . (count($days) > 1 ? ' hours' : ' hour') . ''; } } if (count($days)) { $add_end = true; $days = array_map(array($this, 'getNumberString'), $days); $res .= ($res ? ' and ' : '') . 'on ' . '' . implode(', ', $days) . (count($days) > 1 ? ' days' : ' day') . ''; } if ($add_end) { $res .= ' after invoice creation'; } return $res; } function __toString() { $label = $this->getLabel(); if (is_array($label)) { $label = array_map('strip_tags', $label); $label = implode(' ', $label); } $tmplates = Am_Di::getInstance()->emailTemplateTable->findByName($this->getName(), null, null, 'days'); $out = ''; foreach ($tmplates as $t) { $p = array( 'id' => $t->email_template_id, 'b' => $_SERVER['REQUEST_URI'] . '#' . $this->getName(), 'label' => $label, 'name' => $this->getName() ); $delUrl = Am_Di::getInstance()->url('admin-email-templates/delete', $p); $editUrl = Am_Di::getInstance()->url('admin-email-templates/pending-notification-rule', $p); $out.= '
– ' . $this->renderRule($t) . ' [] []
'; } $params = array( 'name' => Am_Form_Setup::name2dots($this->getName()), 'b' => $_SERVER['REQUEST_URI'] . '#' . $this->getName(), 'label' => $label ); $url = Am_Di::getInstance()->url('admin-email-templates/pending-notification-rule', $params); if ($out) $out .= '
'; $out = sprintf('
%s
', $this->getName(), $out, $url, ___('Add New Notification Rule')); return $out; } public function render(HTML_QuickForm2_Renderer $renderer) { $renderer->getJavascriptBuilder()->addElementJavascript(<<attributes['type'] = 'period'; $this->options = array( 'd' => ___('Days'), 'm' => ___('Months'), 'y' => ___('Years'), 'lifetime' => ___('Lifetime'), // 'fixed' => ___('Fixed'), ); parent::__construct($name, $attributes, $data); $this->period = new Am_Period(); } function setValue($value) { if (is_array($value)) { if ($value['u'] == 'lifetime') { $this->period = Am_Period::getLifetime(); } else if ($value['c'] && $value['u']) { $this->period = new Am_Period($value['c'], $value['u']); } else { $this->period = new Am_Period; } } else { $this->period = new Am_Period($value); } $value = $this->period->__toString(); parent::setValue($value); } function __toString() { return sprintf('
'. ' '. '
', $this->getName(), $this->period->getCount(), $this->getId() . '-c', $this->getName(), $this->getId() . '-u'); } } class Am_Form_Element_Script extends HTML_QuickForm2_Element { protected $script; public function getType() { return 'script'; } public function getRawValue() { return null; } public function setValue($value) { } public function __toString() { return ''; } public function setScript($script) { $this->script = $script; } public function render(HTML_QuickForm2_Renderer $renderer) { $renderer->renderHidden($this); return $renderer; } } class Am_Form_Element_Html extends HTML_QuickForm2_Element { protected $html = ''; public function getType() { return 'html'; } public function setValue($value) { } public function getRawValue() { return null; } public function setHtml($html) { $this->html = $html; return $this; } public function getHtml() { return $this->html; } public function __toString() { return $this->html; } } class Am_Form_Element_Csrf extends HTML_QuickForm2_Element_InputHidden { /** @var Zend_Session_Namespace */ protected $session; protected $sessionNamespace = 'amember_admin_csrf'; protected $startCleanup = 100; protected $keepAfterCleanup = 80; const LEN = 8; public function __construct($name = null, $attributes = null, $data = null) { parent::__construct($name, $attributes, $data); $this->addRule('regex', "CSRF protection error - no value provided", '/^[a-zA-Z0-9_]{'.self::LEN.'}$/'); $this->addRule('callback', $this->getErrorMessage(), array($this, 'keyExists')); } public function __toString() { $this->setValue($this->keyCreate()); return parent::__toString(); } public function getErrorMessage() { return sprintf(___("CSRF protection error - form must be submitted within %d minutes after displaying, please repeat"),60); } function keyCreate() { $keys = $this->getSession()->keys; $keys[] = $ret = Am_Di::getInstance()->security->randomString(self::LEN); if (count($keys) > $this->startCleanup) // if we got > 100 array_splice($keys, 0, count($keys) - $this->keepAfterCleanup ); // keep last 80 keys\ $this->getSession()->keys = $keys; return $ret; } function keyExists($key) { return in_array($key, $this->getSession()->keys); } /** @access private */ function _keysGet() { return $this->getSession()->keys; } function getSession() { if (empty($this->session)) { $this->session = new Zend_Session_Namespace($this->sessionNamespace); $this->session->setExpirationSeconds(3600); } if (!($this->session->keys)) { $this->session->keys = array(); } return $this->session; } function setCleanupParams($startCleanup, $keepAfterCleanup) { $this->startCleanup = (int)$startCleanup; $this->keepAfterCleanup = (int)$keepAfterCleanup; } function setSessionNamespace($ns) { $this->sessionNamespace = $ns; $this->session = null; } } class Am_Form_Element_HtmlEditor extends HTML_QuickForm2_Element_Textarea { protected $dontInitMce = false; protected $showInPopup = false; protected $mceOptions = false; public function __construct($name = null, $attributes = null, $data = null) { if ($data === null) $data = array(); if ($attributes === null) $attributes = array('rows' => 10); $attributes = (array)$attributes; if (!isset($data['showInPopup']) || !$data['showInPopup']) $attributes['class'] = 'row-wide el-wide'; $this->showInPopup = isset($data['showInPopup']) && $data['showInPopup']; $this->dontInitMce = isset($data['dontInitMce']) && $data['dontInitMce']; parent::__construct($name, $attributes, null); } public function setMceOptions($options) { $this->mceOptions = $options; return $this; } public function render(HTML_QuickForm2_Renderer $renderer) { if (!Am_Di::getInstance()->config->get('disable_rte')) { $id = $this->getId(); $view = new Am_View; $url = $view->_scriptJs('ckeditor/ckeditor.js'); $renderer->getJavascriptBuilder()->addElementJavascript(<<'); jQuery('head').append(script); } CUT ); if (!($this->dontInitMce || $this->showInPopup)) { $options = $this->mceOptions ? json_encode($this->mceOptions) : '{}'; $renderer->getJavascriptBuilder()->addElementJavascript(<<frozen || !$this->showInPopup) return $out; $link_title = Am_Html::escape(___('Edit')); list($window_title) = $this->getLabel(); $window_title = Am_Html::escape($window_title); $id = str_replace('.', '-', $this->getId()); $elid = $this->getId(); $mceOptions = $this->mceOptions ? Am_Html::escape(json_encode($this->mceOptions)) : '{}'; return <<$link_title CUT; } } class Am_Form_Element_MagicSelect extends HTML_QuickForm2_Element_Select { public function __construct($name = null, $attributes = null, array $data = array()) { if ($attributes === null) $attributes = array(); $attributes['class'] = empty($attributes['class']) ? 'magicselect' : $attributes['class'] . ' magicselect'; $attributes['multiple'] = 'multiple'; $attributes['data-offer'] = '-- ' . ___("Please Select") . ' --'; parent::__construct($name, $attributes, $data); } function setValue($value) { parent::setValue($value); $this->setAttribute('data-value', json_encode($this->values)); return $this; } function getValue() { $value = parent::getValue(); return $value == null ? array() : $value; } function setJsOptions($jsOptions) { $classes = explode(' ', $this->getAttribute('class')); $customClassHere = false; foreach ($classes as $k=>$class) { if ($class == 'magicselect') { unset($classes[$k]); } if ($class == 'magicselect-custom-' . $this->getId()) { $customClassHere = true; } } if (!$customClassHere) { $classes[] = 'magicselect-custom-' . $this->getId(); } $this->setAttribute('class', implode(' ', $classes)); $id = $this->getId(); $jsScript = <<getContainer()->getElementsByName('script-' . $this->getId()); if (count($elements)) { $script = $elements[0]; } else { $script = $this->getContainer()->addElement('script', 'script-' . $this->getId()); } $script->setScript($jsScript); return $this; } } class Am_Form_Element_SortableMagicSelect extends HTML_QuickForm2_Element_Select { public function __construct($name = null, $attributes = null, array $data = array()) { if ($attributes === null) $attributes = array(); $attributes['class'] = empty($attributes['class']) ? 'magicselect-sortable' : $attributes['class'] . ' magicselect-sortable'; $attributes['multiple'] = 'multiple'; $attributes['data-offer'] = '-- ' . ___("Please Select") . ' --'; parent::__construct($name, $attributes, $data); } function setValue($value) { parent::setValue($value); $options = $this->optionContainer->getOptions(); $before = $options; foreach ($options as $k=>$val) { if ( ($key = array_search($val['attr']['value'], $this->values))!==false ) { $options[$k]['attr']['data-sort_order'] = 1000 - $key; } else { $options[$k]['attr']['data-sort_order'] = 0; } } $this->optionContainer = new HTML_QuickForm2_Element_Select_OptionContainer($this->values, $this->possibleValues); //reset options foreach ($options as $k => $val) { $this->optionContainer->addOption($val['text'], $val['attr']['value'], $val['attr']); } $this->setAttribute('data-value', json_encode($this->values)); return $this; } function getValue() { $value = parent::getValue(); return $value == null ? array() : $value; } function setJsOptions($jsOptions) { $classes = explode(' ', $this->getAttribute('class')); $customClassHere = false; foreach ($classes as $k=>$class) { if ($class == 'magicselect-sortable') { unset($classes[$k]); } if ($class == 'magicselect-sortable-custom-' . $this->getId()) { $customClassHere = true; } } if (!$customClassHere) { $classes[] = 'magicselect-sortable-custom-' . $this->getId(); } $this->setAttribute('class', implode(' ', $classes)); $id = $this->getId(); $jsScript = <<getContainer()->getElementsByName('script-' . $this->getId()); if (count($elements)) { $script = $elements[0]; } else { $script = $this->getContainer()->addElement('script', 'script-' . $this->getId()); } $script->setScript($jsScript); return $this; } } class Am_Form_Element_SortableList extends HTML_QuickForm2_Element { protected $options = array(); protected $val = array(); public function loadOptions(array $options) { $this->options = $options; return $this; } public function __toString() { $id = Am_Html::escape($this->getId()); $name = Am_Html::escape($this->getName()); $ret = "
    \n"; // sort list by $this->val, then remaining entries $options = array(); $uoptions = $this->options; // unsorted options foreach ($this->val as $k) { if (!empty($uoptions[$k])) $options[] = array($k, $uoptions[$k]); unset($uoptions[$k]); } foreach ($uoptions as $k => $v) {// handle remaining values $options[] = array($k, $v); } foreach ($options as $a) { list($k,$v) = $a; $k = Am_Html::escape($k); $v = Am_Html::escape($v); $ret .= "
  • "; $ret .= "$v"; $ret .= ""; $ret .= "
  • \n"; } $id = json_encode($this->getId()); $ret .= "
\n"; $ret .= "\n"; return $ret; } /** * Return groups as it was sorted in the list * @return array */ public function getRawValue() { return $this->val; } public function getType() { return 'sortable-list'; } public function setValue($value) { foreach ($value as $k => $v) { if (empty($this->options[$v])) continue; // we have no such option, skip it! $this->val[$k] = $v; } return $this; } } class Am_Form_Container_AdvFieldset extends HTML_QuickForm2_Container_Fieldset { public function __construct($name = null, $attributes = null, $data = null) { if ($attributes === null) $attributes = array(); $attributes['class'] = isset($attributes['class']) ? "{$attributes['class']} am-adv-fieldset" : 'am-adv-fieldset'; parent::__construct($name, $attributes, $data); $id = $this->getId(); $opened = explode(';', @$_COOKIE['am-adv-fieldset']); if (in_array($id,$opened)) { $this->setAttribute('data-hidden', false); } else { if (!isset($attributes['data-hidden'])) $this->setAttribute('data-hidden', true); } $this->addScript()->setScript(<<