Version Notes
changes:
- removes magento compilator errors
Download this release
Release Info
Developer | Juraj Simon |
Extension | Liveagent |
Version | 1.0.15 |
Comparing to | |
See all releases |
Version 1.0.15
- app/code/local/Qualityunit/.buildpath +10 -0
- app/code/local/Qualityunit/.project +28 -0
- app/code/local/Qualityunit/.settings/.jsdtscope +11 -0
- app/code/local/Qualityunit/.settings/org.eclipse.php.core.prefs +5 -0
- app/code/local/Qualityunit/.settings/org.eclipse.wst.jsdt.ui.superType.container +1 -0
- app/code/local/Qualityunit/.settings/org.eclipse.wst.jsdt.ui.superType.name +1 -0
- app/code/local/Qualityunit/Liveagent/Block/Account.php +95 -0
- app/code/local/Qualityunit/Liveagent/Block/Accountbutton.php +34 -0
- app/code/local/Qualityunit/Liveagent/Block/Adminhtml/Config/Account.php +117 -0
- app/code/local/Qualityunit/Liveagent/Block/Adminhtml/Liveagent.php +12 -0
- app/code/local/Qualityunit/Liveagent/Block/Adminhtml/Liveagent/Grid.php +117 -0
- app/code/local/Qualityunit/Liveagent/Block/Base.php +50 -0
- app/code/local/Qualityunit/Liveagent/Block/ButtonsGrid.php +116 -0
- app/code/local/Qualityunit/Liveagent/Block/Connectioninfo.php +44 -0
- app/code/local/Qualityunit/Liveagent/Block/CreateFreeAccountWidget.php +18 -0
- app/code/local/Qualityunit/Liveagent/Block/CustomHeader.php +28 -0
- app/code/local/Qualityunit/Liveagent/Block/CustomHeader2.php +213 -0
- app/code/local/Qualityunit/Liveagent/Block/Dialog.php +5 -0
- app/code/local/Qualityunit/Liveagent/Block/ErrorMessageWidget.php +30 -0
- app/code/local/Qualityunit/Liveagent/Block/FloatButtonWidget.php +14 -0
- app/code/local/Qualityunit/Liveagent/Block/Liveagent.php +16 -0
- app/code/local/Qualityunit/Liveagent/Block/Signup.php +124 -0
- app/code/local/Qualityunit/Liveagent/Block/Waiting.php +80 -0
- app/code/local/Qualityunit/Liveagent/Exception/ConnectProblem.php +12 -0
- app/code/local/Qualityunit/Liveagent/Exception/SignupFailed.php +12 -0
- app/code/local/Qualityunit/Liveagent/Helper/Auth.php +79 -0
- app/code/local/Qualityunit/Liveagent/Helper/Base.php +52 -0
- app/code/local/Qualityunit/Liveagent/Helper/Buttons.php +143 -0
- app/code/local/Qualityunit/Liveagent/Helper/Data.php +6 -0
- app/code/local/Qualityunit/Liveagent/Helper/PhpApi.php +4310 -0
- app/code/local/Qualityunit/Liveagent/Helper/Settings.php +187 -0
- app/code/local/Qualityunit/Liveagent/Helper/Signup.php +26 -0
- app/code/local/Qualityunit/Liveagent/Model/Buttons.php +10 -0
- app/code/local/Qualityunit/Liveagent/Model/Liveagent.php +10 -0
- app/code/local/Qualityunit/Liveagent/Model/Mysql4/Buttons.php +9 -0
- app/code/local/Qualityunit/Liveagent/Model/Mysql4/Buttons/Collection.php +10 -0
- app/code/local/Qualityunit/Liveagent/Model/Mysql4/Liveagent.php +10 -0
- app/code/local/Qualityunit/Liveagent/Model/Mysql4/Liveagent/Collection.php +10 -0
- app/code/local/Qualityunit/Liveagent/Model/Mysql4/Settings.php +10 -0
- app/code/local/Qualityunit/Liveagent/Model/Mysql4/Settings/Collection.php +10 -0
- app/code/local/Qualityunit/Liveagent/Model/Settings.php +10 -0
- app/code/local/Qualityunit/Liveagent/Model/Status.php +15 -0
- app/code/local/Qualityunit/Liveagent/controllers/Adminhtml/ButtonsController.php +84 -0
- app/code/local/Qualityunit/Liveagent/controllers/Adminhtml/LiveagentController.php +242 -0
- app/code/local/Qualityunit/Liveagent/controllers/IndexController.php +9 -0
- app/code/local/Qualityunit/Liveagent/etc/config.xml +153 -0
- app/code/local/Qualityunit/Liveagent/sql/liveagent_setup/mysql4-install-0.1.0.php +59 -0
- app/design/adminhtml/default/default/layout/liveagent.xml +8 -0
- app/design/adminhtml/default/default/template/liveagent/dialog.phtml +1 -0
- app/design/frontend/base/default/layout/liveagent.xml +11 -0
- app/design/frontend/base/default/template/liveagent/button.phtml +10 -0
- app/design/frontend/base/default/template/liveagent/header.phtml +5 -0
- app/etc/modules/Qualityunit_Liveagent.xml +9 -0
- package.xml +20 -0
app/code/local/Qualityunit/.buildpath
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0" encoding="UTF-8"?>
|
2 |
+
<buildpath>
|
3 |
+
<buildpathentry kind="con" path="org.eclipse.php.core.LANGUAGE"/>
|
4 |
+
<buildpathentry kind="src" path="Liveagent/Model"/>
|
5 |
+
<buildpathentry kind="src" path="Liveagent/Block"/>
|
6 |
+
<buildpathentry kind="src" path="Liveagent/Helper"/>
|
7 |
+
<buildpathentry kind="src" path="Liveagent/controllers"/>
|
8 |
+
<buildpathentry kind="src" path="Liveagent/sql/liveagent_setup"/>
|
9 |
+
<buildpathentry combineaccessrules="false" kind="prj" path="/magento"/>
|
10 |
+
</buildpath>
|
app/code/local/Qualityunit/.project
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0" encoding="UTF-8"?>
|
2 |
+
<projectDescription>
|
3 |
+
<name>la_code</name>
|
4 |
+
<comment></comment>
|
5 |
+
<projects>
|
6 |
+
</projects>
|
7 |
+
<buildSpec>
|
8 |
+
<buildCommand>
|
9 |
+
<name>org.eclipse.wst.jsdt.core.javascriptValidator</name>
|
10 |
+
<arguments>
|
11 |
+
</arguments>
|
12 |
+
</buildCommand>
|
13 |
+
<buildCommand>
|
14 |
+
<name>org.eclipse.wst.validation.validationbuilder</name>
|
15 |
+
<arguments>
|
16 |
+
</arguments>
|
17 |
+
</buildCommand>
|
18 |
+
<buildCommand>
|
19 |
+
<name>org.eclipse.dltk.core.scriptbuilder</name>
|
20 |
+
<arguments>
|
21 |
+
</arguments>
|
22 |
+
</buildCommand>
|
23 |
+
</buildSpec>
|
24 |
+
<natures>
|
25 |
+
<nature>org.eclipse.php.core.PHPNature</nature>
|
26 |
+
<nature>org.eclipse.wst.jsdt.core.jsNature</nature>
|
27 |
+
</natures>
|
28 |
+
</projectDescription>
|
app/code/local/Qualityunit/.settings/.jsdtscope
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0" encoding="UTF-8"?>
|
2 |
+
<classpath>
|
3 |
+
<classpathentry kind="con" path="org.eclipse.wst.jsdt.launching.JRE_CONTAINER"/>
|
4 |
+
<classpathentry kind="con" path="org.eclipse.wst.jsdt.launching.WebProject">
|
5 |
+
<attributes>
|
6 |
+
<attribute name="hide" value="true"/>
|
7 |
+
</attributes>
|
8 |
+
</classpathentry>
|
9 |
+
<classpathentry kind="con" path="org.eclipse.wst.jsdt.launching.baseBrowserLibrary"/>
|
10 |
+
<classpathentry kind="output" path=""/>
|
11 |
+
</classpath>
|
app/code/local/Qualityunit/.settings/org.eclipse.php.core.prefs
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#Fri Sep 16 12:31:44 CEST 2011
|
2 |
+
eclipse.preferences.version=1
|
3 |
+
include_path=0;/la_code\u00052;/magento
|
4 |
+
phpVersion=php5.3
|
5 |
+
use_asp_tags_as_php=false
|
app/code/local/Qualityunit/.settings/org.eclipse.wst.jsdt.ui.superType.container
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
org.eclipse.wst.jsdt.launching.baseBrowserLibrary
|
app/code/local/Qualityunit/.settings/org.eclipse.wst.jsdt.ui.superType.name
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
Window
|
app/code/local/Qualityunit/Liveagent/Block/Account.php
ADDED
@@ -0,0 +1,95 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Qualityunit_Liveagent_Block_Account extends Qualityunit_Liveagent_Block_Base {
|
4 |
+
|
5 |
+
const SAVE_ACCOUNT_SETTINGS_ACTION_FLAG = 'sas';
|
6 |
+
|
7 |
+
public function _prepareLayout() {
|
8 |
+
parent::_prepareLayout();
|
9 |
+
$this->assignVariable('dialogCaption', Mage::helper('adminhtml')->__('Account options'));
|
10 |
+
$this->assignVariable('submitCaption', Mage::helper('adminhtml')->__('Save Account Settings'));
|
11 |
+
$this->assignVariable('formKey', Mage::getSingleton('core/session')->getFormKey());
|
12 |
+
$this->assignVariable('saveUrlAction', $this->getUrl('*/*/post'));
|
13 |
+
$this->assignVariable(Qualityunit_Liveagent_Helper_Settings::LA_URL_SETTING_NAME, $this->getInputBox(Qualityunit_Liveagent_Helper_Settings::LA_URL_SETTING_NAME, ''));
|
14 |
+
$this->assignVariable(Qualityunit_Liveagent_Helper_Settings::LA_OWNER_EMAIL_SETTING_NAME, $this->getInputBox(Qualityunit_Liveagent_Helper_Settings::LA_OWNER_EMAIL_SETTING_NAME, ''));
|
15 |
+
$this->assignVariable(Qualityunit_Liveagent_Helper_Settings::LA_OWNER_PASSWORD_SETTING_NAME, $this->getPasswordBox(Qualityunit_Liveagent_Helper_Settings::LA_OWNER_PASSWORD_SETTING_NAME, ''));
|
16 |
+
$this->assignVariable('saveActionSettingsFlag', self::SAVE_ACCOUNT_SETTINGS_ACTION_FLAG);
|
17 |
+
}
|
18 |
+
|
19 |
+
protected function getPasswordBox($name, $value) {
|
20 |
+
$settings = new Qualityunit_Liveagent_Helper_Settings();
|
21 |
+
return parent::getPasswordBox($name, $settings->getOption($name));
|
22 |
+
}
|
23 |
+
|
24 |
+
protected function getInputBox($name, $value) {
|
25 |
+
$settings = new Qualityunit_Liveagent_Helper_Settings();
|
26 |
+
return parent::getInputBox($name, $settings->getOption($name));
|
27 |
+
}
|
28 |
+
|
29 |
+
protected function getTemplateString() {
|
30 |
+
return '
|
31 |
+
<div class="wrap">
|
32 |
+
<div class="nlStepBox">
|
33 |
+
<div class="nlStepHeader">
|
34 |
+
<div class="nlStepHeaderLeft">
|
35 |
+
<span class="nlStepName">
|
36 |
+
Account options
|
37 |
+
</span>
|
38 |
+
</div>
|
39 |
+
<div class="clear"></div>
|
40 |
+
</div>
|
41 |
+
<form id="edit_form" name="edit_form" action="{saveUrlAction}" method="post">
|
42 |
+
<input name="form_key" type="hidden" value="{formKey}" />
|
43 |
+
<input name="action" type="hidden" value="{saveActionSettingsFlag}"/>
|
44 |
+
<div class="nlStepBoxContent">
|
45 |
+
<div class="nlStepBoxLeft">
|
46 |
+
<div class="nlFormField">
|
47 |
+
<div class="nlFormFieldLabel">
|
48 |
+
Account Url
|
49 |
+
</div>
|
50 |
+
<div class="nlFormFieldInput">
|
51 |
+
{la-url}
|
52 |
+
</div>
|
53 |
+
<div class="nlFormFieldDesc">
|
54 |
+
include \'http://\' or \'https://\'
|
55 |
+
</div>
|
56 |
+
</div>
|
57 |
+
<div class="nlFormField">
|
58 |
+
<div class="nlFormFieldLabel">
|
59 |
+
Email
|
60 |
+
</div>
|
61 |
+
<div class="nlFormFieldInput">
|
62 |
+
{la-owner-email}
|
63 |
+
</div>
|
64 |
+
</div>
|
65 |
+
<div class="nlFormField">
|
66 |
+
<div class="nlFormFieldLabel">
|
67 |
+
Password
|
68 |
+
</div>
|
69 |
+
<div class="nlFormFieldInput">
|
70 |
+
{la-owner-password}
|
71 |
+
</div>
|
72 |
+
</div>
|
73 |
+
<input type="hidden" value="submit">
|
74 |
+
<input class="nlBigButton" value="{submitCaption}" type="submit" style="border-width:0px;width:300px;"/>
|
75 |
+
</div>
|
76 |
+
<div class="nlBoxWithScreenshots"></div>
|
77 |
+
<div class="nlContactUs">
|
78 |
+
<div class="nlDarkOrangeText">
|
79 |
+
Do you need help with this plugin?
|
80 |
+
</div>
|
81 |
+
<div class="nlDarkOrangeText">
|
82 |
+
Feel free to
|
83 |
+
<a href="http://support.qualityunit.com/la/chat/index.php?bid=858b57ea" target="_blank">
|
84 |
+
contact us
|
85 |
+
</a>
|
86 |
+
</div>
|
87 |
+
</div>
|
88 |
+
<div class="clear"></div>
|
89 |
+
</div>
|
90 |
+
</form>
|
91 |
+
</div>
|
92 |
+
</div>
|
93 |
+
';
|
94 |
+
}
|
95 |
+
}
|
app/code/local/Qualityunit/Liveagent/Block/Accountbutton.php
ADDED
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Qualityunit_Liveagent_Block_Accountbutton extends Qualityunit_Liveagent_Block_Base {
|
4 |
+
/**
|
5 |
+
* @var Qualityunit_Liveagent_Helper_Settings
|
6 |
+
*/
|
7 |
+
private $settings;
|
8 |
+
|
9 |
+
protected function _prepareLayout() {
|
10 |
+
parent::_prepareLayout();
|
11 |
+
$this->assignVariable('href', $this->getHref());
|
12 |
+
$this->assignVariable('caption', Mage::helper('adminhtml')->__('Login to Admin panel'));
|
13 |
+
}
|
14 |
+
|
15 |
+
public function setSettings(Qualityunit_Liveagent_Helper_Settings $settings) {
|
16 |
+
$this->settings = $settings;
|
17 |
+
}
|
18 |
+
|
19 |
+
private function getHref() {
|
20 |
+
$authToken = $this->settings->getOwnerAuthToken();
|
21 |
+
if ($authToken == '') {
|
22 |
+
$sessionId = $this->settings->getOwnerSessionId();
|
23 |
+
if ($sessionId != '') {
|
24 |
+
return $this->settings->getLiveAgentUrl() . '/agent?S='.$this->settings->getOwnerSessionId();
|
25 |
+
}
|
26 |
+
return $this->settings->getLiveAgentUrl() . '/agent';
|
27 |
+
}
|
28 |
+
return $this->settings->getLiveAgentUrl() . '/agent?AuthToken='.$authToken;
|
29 |
+
}
|
30 |
+
|
31 |
+
protected function getTemplateString() {
|
32 |
+
return '<a href="{href}" target="_blank" class="nlBigButton" style="width:300px;">{caption}</a>';
|
33 |
+
}
|
34 |
+
}
|
app/code/local/Qualityunit/Liveagent/Block/Adminhtml/Config/Account.php
ADDED
@@ -0,0 +1,117 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Qualityunit_Liveagent_Block_Adminhtml_Liveagent_Grid extends Mage_Adminhtml_Block_Widget_Grid
|
4 |
+
{
|
5 |
+
|
6 |
+
public function __construct()
|
7 |
+
{
|
8 |
+
parent::__construct();
|
9 |
+
$this->setId('liveagentGrid');
|
10 |
+
$this->setDefaultSort('liveagent_id');
|
11 |
+
$this->setDefaultDir('ASC');
|
12 |
+
$this->setSaveParametersInSession(true);
|
13 |
+
}
|
14 |
+
|
15 |
+
protected function _prepareCollection()
|
16 |
+
{
|
17 |
+
$collection = Mage::getModel('liveagent/liveagent')->getCollection();
|
18 |
+
$this->setCollection($collection);
|
19 |
+
return parent::_prepareCollection();
|
20 |
+
}
|
21 |
+
|
22 |
+
protected function _prepareColumns()
|
23 |
+
{
|
24 |
+
$this->addColumn('liveagent_id', array(
|
25 |
+
'header' => Mage::helper('liveagent')->__('ID'),
|
26 |
+
'align' =>'right',
|
27 |
+
'width' => '50px',
|
28 |
+
'index' => 'liveagent_id',
|
29 |
+
));
|
30 |
+
|
31 |
+
$this->addColumn('title', array(
|
32 |
+
'header' => Mage::helper('liveagent')->__('Title'),
|
33 |
+
'align' =>'left',
|
34 |
+
'index' => 'title',
|
35 |
+
));
|
36 |
+
|
37 |
+
/*
|
38 |
+
$this->addColumn('content', array(
|
39 |
+
'header' => Mage::helper('liveagent')->__('Item Content'),
|
40 |
+
'width' => '150px',
|
41 |
+
'index' => 'content',
|
42 |
+
));
|
43 |
+
*/
|
44 |
+
|
45 |
+
$this->addColumn('status', array(
|
46 |
+
'header' => Mage::helper('liveagent')->__('Status'),
|
47 |
+
'align' => 'left',
|
48 |
+
'width' => '80px',
|
49 |
+
'index' => 'status',
|
50 |
+
'type' => 'options',
|
51 |
+
'options' => array(
|
52 |
+
1 => 'Enabled',
|
53 |
+
2 => 'Disabled',
|
54 |
+
),
|
55 |
+
));
|
56 |
+
|
57 |
+
$this->addColumn('action',
|
58 |
+
array(
|
59 |
+
'header' => Mage::helper('liveagent')->__('Action'),
|
60 |
+
'width' => '100',
|
61 |
+
'type' => 'action',
|
62 |
+
'getter' => 'getId',
|
63 |
+
'actions' => array(
|
64 |
+
array(
|
65 |
+
'caption' => Mage::helper('liveagent')->__('Edit'),
|
66 |
+
'url' => array('base'=> '*/*/edit'),
|
67 |
+
'field' => 'id'
|
68 |
+
)
|
69 |
+
),
|
70 |
+
'filter' => false,
|
71 |
+
'sortable' => false,
|
72 |
+
'index' => 'stores',
|
73 |
+
'is_system' => true,
|
74 |
+
));
|
75 |
+
|
76 |
+
$this->addExportType('*/*/exportCsv', Mage::helper('liveagent')->__('CSV'));
|
77 |
+
$this->addExportType('*/*/exportXml', Mage::helper('liveagent')->__('XML'));
|
78 |
+
|
79 |
+
return parent::_prepareColumns();
|
80 |
+
}
|
81 |
+
|
82 |
+
protected function _prepareMassaction()
|
83 |
+
{
|
84 |
+
$this->setMassactionIdField('liveagent_id');
|
85 |
+
$this->getMassactionBlock()->setFormFieldName('liveagent');
|
86 |
+
|
87 |
+
$this->getMassactionBlock()->addItem('delete', array(
|
88 |
+
'label' => Mage::helper('liveagent')->__('Delete'),
|
89 |
+
'url' => $this->getUrl('*/*/massDelete'),
|
90 |
+
'confirm' => Mage::helper('liveagent')->__('Are you sure?')
|
91 |
+
));
|
92 |
+
|
93 |
+
$statuses = Mage::getSingleton('liveagent/status')->getOptionArray();
|
94 |
+
|
95 |
+
array_unshift($statuses, array('label'=>'', 'value'=>''));
|
96 |
+
$this->getMassactionBlock()->addItem('status', array(
|
97 |
+
'label'=> Mage::helper('liveagent')->__('Change status'),
|
98 |
+
'url' => $this->getUrl('*/*/massStatus', array('_current'=>true)),
|
99 |
+
'additional' => array(
|
100 |
+
'visibility' => array(
|
101 |
+
'name' => 'status',
|
102 |
+
'type' => 'select',
|
103 |
+
'class' => 'required-entry',
|
104 |
+
'label' => Mage::helper('liveagent')->__('Status'),
|
105 |
+
'values' => $statuses
|
106 |
+
)
|
107 |
+
)
|
108 |
+
));
|
109 |
+
return $this;
|
110 |
+
}
|
111 |
+
|
112 |
+
public function getRowUrl($row)
|
113 |
+
{
|
114 |
+
return $this->getUrl('*/*/edit', array('id' => $row->getId()));
|
115 |
+
}
|
116 |
+
|
117 |
+
}
|
app/code/local/Qualityunit/Liveagent/Block/Adminhtml/Liveagent.php
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
class Qualityunit_Liveagent_Block_Adminhtml_Liveagent extends Mage_Adminhtml_Block_Widget_Grid_Container
|
3 |
+
{
|
4 |
+
public function __construct()
|
5 |
+
{
|
6 |
+
$this->_controller = 'adminhtml_liveagent';
|
7 |
+
$this->_blockGroup = 'liveagent';
|
8 |
+
$this->_headerText = Mage::helper('liveagent')->__('Item Manager');
|
9 |
+
$this->_addButtonLabel = Mage::helper('liveagent')->__('Add Item');
|
10 |
+
parent::__construct();
|
11 |
+
}
|
12 |
+
}
|
app/code/local/Qualityunit/Liveagent/Block/Adminhtml/Liveagent/Grid.php
ADDED
@@ -0,0 +1,117 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Qualityunit_Liveagent_Block_Adminhtml_Liveagent_Grid extends Mage_Adminhtml_Block_Widget_Grid
|
4 |
+
{
|
5 |
+
|
6 |
+
public function __construct()
|
7 |
+
{
|
8 |
+
parent::__construct();
|
9 |
+
$this->setId('liveagentGrid');
|
10 |
+
$this->setDefaultSort('liveagent_id');
|
11 |
+
$this->setDefaultDir('ASC');
|
12 |
+
$this->setSaveParametersInSession(true);
|
13 |
+
}
|
14 |
+
|
15 |
+
protected function _prepareCollection()
|
16 |
+
{
|
17 |
+
$collection = Mage::getModel('liveagent/liveagent')->getCollection();
|
18 |
+
$this->setCollection($collection);
|
19 |
+
return parent::_prepareCollection();
|
20 |
+
}
|
21 |
+
|
22 |
+
protected function _prepareColumns()
|
23 |
+
{
|
24 |
+
$this->addColumn('liveagent_id', array(
|
25 |
+
'header' => Mage::helper('liveagent')->__('ID'),
|
26 |
+
'align' =>'right',
|
27 |
+
'width' => '50px',
|
28 |
+
'index' => 'liveagent_id',
|
29 |
+
));
|
30 |
+
|
31 |
+
$this->addColumn('title', array(
|
32 |
+
'header' => Mage::helper('liveagent')->__('Title'),
|
33 |
+
'align' =>'left',
|
34 |
+
'index' => 'title',
|
35 |
+
));
|
36 |
+
|
37 |
+
/*
|
38 |
+
$this->addColumn('content', array(
|
39 |
+
'header' => Mage::helper('liveagent')->__('Item Content'),
|
40 |
+
'width' => '150px',
|
41 |
+
'index' => 'content',
|
42 |
+
));
|
43 |
+
*/
|
44 |
+
|
45 |
+
$this->addColumn('status', array(
|
46 |
+
'header' => Mage::helper('liveagent')->__('Status'),
|
47 |
+
'align' => 'left',
|
48 |
+
'width' => '80px',
|
49 |
+
'index' => 'status',
|
50 |
+
'type' => 'options',
|
51 |
+
'options' => array(
|
52 |
+
1 => 'Enabled',
|
53 |
+
2 => 'Disabled',
|
54 |
+
),
|
55 |
+
));
|
56 |
+
|
57 |
+
$this->addColumn('action',
|
58 |
+
array(
|
59 |
+
'header' => Mage::helper('liveagent')->__('Action'),
|
60 |
+
'width' => '100',
|
61 |
+
'type' => 'action',
|
62 |
+
'getter' => 'getId',
|
63 |
+
'actions' => array(
|
64 |
+
array(
|
65 |
+
'caption' => Mage::helper('liveagent')->__('Edit'),
|
66 |
+
'url' => array('base'=> '*/*/edit'),
|
67 |
+
'field' => 'id'
|
68 |
+
)
|
69 |
+
),
|
70 |
+
'filter' => false,
|
71 |
+
'sortable' => false,
|
72 |
+
'index' => 'stores',
|
73 |
+
'is_system' => true,
|
74 |
+
));
|
75 |
+
|
76 |
+
$this->addExportType('*/*/exportCsv', Mage::helper('liveagent')->__('CSV'));
|
77 |
+
$this->addExportType('*/*/exportXml', Mage::helper('liveagent')->__('XML'));
|
78 |
+
|
79 |
+
return parent::_prepareColumns();
|
80 |
+
}
|
81 |
+
|
82 |
+
protected function _prepareMassaction()
|
83 |
+
{
|
84 |
+
$this->setMassactionIdField('liveagent_id');
|
85 |
+
$this->getMassactionBlock()->setFormFieldName('liveagent');
|
86 |
+
|
87 |
+
$this->getMassactionBlock()->addItem('delete', array(
|
88 |
+
'label' => Mage::helper('liveagent')->__('Delete'),
|
89 |
+
'url' => $this->getUrl('*/*/massDelete'),
|
90 |
+
'confirm' => Mage::helper('liveagent')->__('Are you sure?')
|
91 |
+
));
|
92 |
+
|
93 |
+
$statuses = Mage::getSingleton('liveagent/status')->getOptionArray();
|
94 |
+
|
95 |
+
array_unshift($statuses, array('label'=>'', 'value'=>''));
|
96 |
+
$this->getMassactionBlock()->addItem('status', array(
|
97 |
+
'label'=> Mage::helper('liveagent')->__('Change status'),
|
98 |
+
'url' => $this->getUrl('*/*/massStatus', array('_current'=>true)),
|
99 |
+
'additional' => array(
|
100 |
+
'visibility' => array(
|
101 |
+
'name' => 'status',
|
102 |
+
'type' => 'select',
|
103 |
+
'class' => 'required-entry',
|
104 |
+
'label' => Mage::helper('liveagent')->__('Status'),
|
105 |
+
'values' => $statuses
|
106 |
+
)
|
107 |
+
)
|
108 |
+
));
|
109 |
+
return $this;
|
110 |
+
}
|
111 |
+
|
112 |
+
public function getRowUrl($row)
|
113 |
+
{
|
114 |
+
return $this->getUrl('*/*/edit', array('id' => $row->getId()));
|
115 |
+
}
|
116 |
+
|
117 |
+
}
|
app/code/local/Qualityunit/Liveagent/Block/Base.php
ADDED
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Qualityunit_Liveagent_Block_Base extends Mage_Core_Block_Template {
|
4 |
+
|
5 |
+
protected $variables = array();
|
6 |
+
|
7 |
+
protected function curPageURL() {
|
8 |
+
$pageURL = 'http';
|
9 |
+
if (isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == "on") {$pageURL .= "s";}
|
10 |
+
$pageURL .= "://";
|
11 |
+
if ($_SERVER["SERVER_PORT"] != "80") {
|
12 |
+
$pageURL .= $_SERVER["SERVER_NAME"].":".$_SERVER["SERVER_PORT"].$_SERVER["REQUEST_URI"];
|
13 |
+
} else {
|
14 |
+
$pageURL .= $_SERVER["SERVER_NAME"].$_SERVER["REQUEST_URI"];
|
15 |
+
}
|
16 |
+
|
17 |
+
$pageURL = preg_replace("/\?.*$/", "", $pageURL);
|
18 |
+
|
19 |
+
return $pageURL;
|
20 |
+
}
|
21 |
+
|
22 |
+
protected function getPasswordBox($name, $value) {
|
23 |
+
return '<input type="password" id="'.$name.'" name="'.$name.'" value="'.$value.'" class="nlInput" />';
|
24 |
+
}
|
25 |
+
|
26 |
+
protected function getInputBox($name, $value) {
|
27 |
+
return '<input type="text" id="'.$name.'" name="'.$name.'" value="'.$value.'" class="nlInput" />';
|
28 |
+
}
|
29 |
+
|
30 |
+
protected function _toHtml() {
|
31 |
+
$html = $this->getTemplateString();
|
32 |
+
foreach ($this->variables as $name => $value) {
|
33 |
+
$html = str_replace('{'.$name.'}', $value, $html);
|
34 |
+
}
|
35 |
+
return $html;
|
36 |
+
}
|
37 |
+
|
38 |
+
protected function _prepareLayout() {
|
39 |
+
parent::_prepareLayout();
|
40 |
+
//$this->getLayout()->getBlock('head')->addCss('css/liveagent/liveagent.css');
|
41 |
+
}
|
42 |
+
|
43 |
+
protected function assignVariable($name, $value) {
|
44 |
+
$this->variables[$name] = $value;
|
45 |
+
}
|
46 |
+
|
47 |
+
protected function getTemplateString() {
|
48 |
+
return '';
|
49 |
+
}
|
50 |
+
}
|
app/code/local/Qualityunit/Liveagent/Block/ButtonsGrid.php
ADDED
@@ -0,0 +1,116 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Qualityunit_Liveagent_Block_ButtonsGrid extends Mage_Adminhtml_Block_Widget_Grid
|
4 |
+
{
|
5 |
+
|
6 |
+
public function __construct()
|
7 |
+
{
|
8 |
+
parent::__construct();
|
9 |
+
$this->setId('liveagentGrid');
|
10 |
+
$this->setDefaultSort('buttonid');
|
11 |
+
$this->setDefaultDir('ASC');
|
12 |
+
$this->setSaveParametersInSession(true);
|
13 |
+
}
|
14 |
+
|
15 |
+
protected function _prepareCollection()
|
16 |
+
{
|
17 |
+
$collection = Mage::getModel('liveagent/buttons')->getCollection()->addFilter('contenttype', 'F');
|
18 |
+
$this->setCollection($collection);
|
19 |
+
return parent::_prepareCollection();
|
20 |
+
}
|
21 |
+
|
22 |
+
protected function _prepareColumns()
|
23 |
+
{
|
24 |
+
$this->addColumn('buttonid', array(
|
25 |
+
'header' => Mage::helper('liveagent')->__('ID'),
|
26 |
+
'align' =>'right',
|
27 |
+
'width' => '50px',
|
28 |
+
'index' => 'buttonid',
|
29 |
+
));
|
30 |
+
|
31 |
+
$this->addColumn('name', array(
|
32 |
+
'header' => Mage::helper('liveagent')->__('Name'),
|
33 |
+
'align' =>'left',
|
34 |
+
'index' => 'name',
|
35 |
+
));
|
36 |
+
|
37 |
+
/*
|
38 |
+
$this->addColumn('content', array(
|
39 |
+
'header' => Mage::helper('liveagent')->__('Item Content'),
|
40 |
+
'width' => '150px',
|
41 |
+
'index' => 'content',
|
42 |
+
));
|
43 |
+
*/
|
44 |
+
|
45 |
+
$this->addColumn('status', array(
|
46 |
+
'header' => Mage::helper('liveagent')->__('Status'),
|
47 |
+
'align' => 'left',
|
48 |
+
'width' => '80px',
|
49 |
+
'index' => 'onlinestatus',
|
50 |
+
'type' => 'options',
|
51 |
+
'options' => array(
|
52 |
+
'Y' => 'Enabled',
|
53 |
+
'N' => 'Disabled',
|
54 |
+
),
|
55 |
+
));
|
56 |
+
|
57 |
+
/*$this->addColumn('action',
|
58 |
+
array(
|
59 |
+
'header' => Mage::helper('liveagent')->__('Action'),
|
60 |
+
'width' => '100',
|
61 |
+
'type' => 'action',
|
62 |
+
'getter' => 'getId',
|
63 |
+
'actions' => array(
|
64 |
+
array(
|
65 |
+
'caption' => Mage::helper('liveagent')->__('Edit'),*/
|
66 |
+
//'url' => array('base'=> '*/*/edit'),
|
67 |
+
/*'field' => 'id'
|
68 |
+
)
|
69 |
+
),
|
70 |
+
'filter' => false,
|
71 |
+
'sortable' => false,
|
72 |
+
'index' => 'stores',
|
73 |
+
'is_system' => true,
|
74 |
+
));*/
|
75 |
+
|
76 |
+
//$this->addExportType('*/*/exportCsv', Mage::helper('liveagent')->__('CSV'));
|
77 |
+
//$this->addExportType('*/*/exportXml', Mage::helper('liveagent')->__('XML'));
|
78 |
+
|
79 |
+
return parent::_prepareColumns();
|
80 |
+
}
|
81 |
+
|
82 |
+
protected function _prepareMassaction()
|
83 |
+
{
|
84 |
+
$this->setMassactionIdField('liveagentbutton_id');
|
85 |
+
$this->getMassactionBlock()->setFormFieldName('buttonids');
|
86 |
+
|
87 |
+
// $this->getMassactionBlock()->addItem('delete', array(
|
88 |
+
// 'label' => Mage::helper('liveagent')->__('Delete'),
|
89 |
+
// 'url' => $this->getUrl('*/*/massDelete'),
|
90 |
+
// 'confirm' => Mage::helper('liveagent')->__('Are you sure?')
|
91 |
+
// ));
|
92 |
+
|
93 |
+
$statuses = Mage::getSingleton('liveagent/status')->getOptionArray();
|
94 |
+
array_unshift($statuses, array('label'=>'', 'value'=>''));
|
95 |
+
$this->getMassactionBlock()->addItem('status', array(
|
96 |
+
'label'=> Mage::helper('liveagent')->__('Change status'),
|
97 |
+
'url' => $this->getUrl('*/*/massStatus', array('_current'=>true)),
|
98 |
+
'additional' => array(
|
99 |
+
'visibility' => array(
|
100 |
+
'name' => 'status',
|
101 |
+
'type' => 'select',
|
102 |
+
'class' => 'required-entry',
|
103 |
+
'label' => Mage::helper('liveagent')->__('Status'),
|
104 |
+
'values' => $statuses
|
105 |
+
)
|
106 |
+
)
|
107 |
+
));
|
108 |
+
return $this;
|
109 |
+
}
|
110 |
+
|
111 |
+
// public function getRowUrl($row)
|
112 |
+
// {
|
113 |
+
// return $this->getUrl('*/*/edit', array('id' => $row->getId()));
|
114 |
+
// }
|
115 |
+
|
116 |
+
}
|
app/code/local/Qualityunit/Liveagent/Block/Connectioninfo.php
ADDED
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Qualityunit_Liveagent_Block_Connectioninfo extends Qualityunit_Liveagent_Block_Base {
|
4 |
+
private $connectionValid;
|
5 |
+
|
6 |
+
public function setConnectionValid($valid) {
|
7 |
+
$this->connectionValid = $valid;
|
8 |
+
}
|
9 |
+
|
10 |
+
public function _prepareLayout() {
|
11 |
+
parent::_prepareLayout();
|
12 |
+
$this->assignVariable('connectionInfo', $this->getConnectionInfo());
|
13 |
+
}
|
14 |
+
|
15 |
+
/**
|
16 |
+
* @return string
|
17 |
+
*/
|
18 |
+
private function getConnectionInfo() {
|
19 |
+
if ($this->connectionValid) {
|
20 |
+
return $this->getConnectionOk();
|
21 |
+
}
|
22 |
+
return $this->getConnectionError();
|
23 |
+
}
|
24 |
+
|
25 |
+
private function getConnectionOk() {
|
26 |
+
return '
|
27 |
+
<div class="nlHurrayMessage">
|
28 |
+
'.Mage::helper('adminhtml')->__('Your Magento installation is succesfully connected with Live Agent').'
|
29 |
+
</div>
|
30 |
+
';
|
31 |
+
}
|
32 |
+
|
33 |
+
private function getConnectionError() {
|
34 |
+
return '
|
35 |
+
<div class="nlHurrayMessage">
|
36 |
+
'.Mage::helper('adminhtml')->__('Unable to connect, check your account settings').'
|
37 |
+
</div>
|
38 |
+
';
|
39 |
+
}
|
40 |
+
|
41 |
+
protected function getTemplateString() {
|
42 |
+
return '{connectionInfo}';
|
43 |
+
}
|
44 |
+
}
|
app/code/local/Qualityunit/Liveagent/Block/CreateFreeAccountWidget.php
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Qualityunit_Liveagent_Block_CreateFreeAccountWidget extends Qualityunit_Liveagent_Block_Base {
|
4 |
+
public function _prepareLayout() {
|
5 |
+
parent::_prepareLayout();
|
6 |
+
$this->assignVariable('preMessage', Mage::helper('adminhtml')->__('No account selected. Enter your existing account credetials, or create new'));
|
7 |
+
$this->assignVariable('link', '<a href="'.$this->curPageURL() . '?action='.Qualityunit_Liveagent_Adminhtml_LiveagentController::ACTION_CREATE.'">' . Mage::helper('adminhtml')->__('free account') . '</a>');
|
8 |
+
$this->assignVariable('postMessage', Mage::helper('adminhtml')->__('(No credit card required)'));
|
9 |
+
}
|
10 |
+
|
11 |
+
protected function getTemplateString() {
|
12 |
+
return '
|
13 |
+
<div class="wrap">
|
14 |
+
{preMessage} {link}. {postMessage}
|
15 |
+
</div>
|
16 |
+
';
|
17 |
+
}
|
18 |
+
}
|
app/code/local/Qualityunit/Liveagent/Block/CustomHeader.php
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
class Qualityunit_Liveagent_Block_CustomHeader extends Mage_Page_Block_Html_Head {
|
3 |
+
|
4 |
+
private function includePhpApi() {
|
5 |
+
$path = dirname(__FILE__);
|
6 |
+
if (file_exists($path . '/../Helper/PhpApi.php')) {
|
7 |
+
require_once $path . '/../Helper/PhpApi.php';
|
8 |
+
return;
|
9 |
+
}
|
10 |
+
require_once ('Qualityunit_Liveagent_Helper_PhpApi.php');
|
11 |
+
}
|
12 |
+
|
13 |
+
protected function _construct() {
|
14 |
+
parent::_construct();
|
15 |
+
$settings = new Qualityunit_Liveagent_Helper_Settings();
|
16 |
+
if ((time() - $settings->getButtonsLastReloadTime()) > 120) {
|
17 |
+
Mage::log('Buttons outdated. Refreshing from application...', Zend_Log::DEBUG);
|
18 |
+
$buttons = new Qualityunit_Liveagent_Helper_Buttons();
|
19 |
+
try {
|
20 |
+
$this->includePhpApi();
|
21 |
+
$settings->login();
|
22 |
+
$buttons->refresh();
|
23 |
+
} catch (Exception $e) {
|
24 |
+
Mage::log('Unable to refresh buttons', Zend_Log::ERR);
|
25 |
+
}
|
26 |
+
}
|
27 |
+
}
|
28 |
+
}
|
app/code/local/Qualityunit/Liveagent/Block/CustomHeader2.php
ADDED
@@ -0,0 +1,213 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Qualityunit_Liveagent_Block_CustomHeader2 extends Mage_Adminhtml_Block_Page_Head {
|
4 |
+
private function includePhpApi() {
|
5 |
+
$path = dirname(__FILE__);
|
6 |
+
if (file_exists($path . '/../Helper/PhpApi.php')) {
|
7 |
+
require_once $path . '/../Helper/PhpApi.php';
|
8 |
+
return;
|
9 |
+
}
|
10 |
+
require_once ('Qualityunit_Liveagent_Helper_PhpApi.php');
|
11 |
+
}
|
12 |
+
|
13 |
+
protected function _construct() {
|
14 |
+
parent::_construct();
|
15 |
+
$settings = new Qualityunit_Liveagent_Helper_Settings();
|
16 |
+
if ((time() - $settings->getButtonsLastReloadTime()) > 120) {
|
17 |
+
Mage::log('Buttons outdated. Refreshing from application...', Zend_Log::DEBUG);
|
18 |
+
$buttons = new Qualityunit_Liveagent_Helper_Buttons();
|
19 |
+
try {
|
20 |
+
$this->includePhpApi();
|
21 |
+
$settings->login();
|
22 |
+
$buttons->refresh();
|
23 |
+
} catch (Exception $e) {
|
24 |
+
Mage::log('Unable to refresh buttons', Zend_Log::ERR);
|
25 |
+
}
|
26 |
+
}
|
27 |
+
}
|
28 |
+
|
29 |
+
protected function _toHtml() {
|
30 |
+
return parent::_toHtml() . '
|
31 |
+
<style type="text/css">
|
32 |
+
/* CLASSES from Juraj */
|
33 |
+
|
34 |
+
div.liveagentInfo {
|
35 |
+
background-color: #D0E4F5;
|
36 |
+
border-color: #52AAF2;
|
37 |
+
}
|
38 |
+
|
39 |
+
div.laSignup {
|
40 |
+
display: block;
|
41 |
+
}
|
42 |
+
|
43 |
+
.buttonTableRow {
|
44 |
+
display: inline;
|
45 |
+
clear: both;
|
46 |
+
float: left;
|
47 |
+
position: relative;
|
48 |
+
background: #ffb347;
|
49 |
+
margin-bottom:3px;
|
50 |
+
}
|
51 |
+
|
52 |
+
.laButtonPreview { /*position: absolute;*/
|
53 |
+
overflow:hidden;
|
54 |
+
}
|
55 |
+
|
56 |
+
.laButtonPreview * {
|
57 |
+
border:none;
|
58 |
+
}
|
59 |
+
|
60 |
+
|
61 |
+
.laButtonsTableCell {
|
62 |
+
position: relative;
|
63 |
+
float: left;
|
64 |
+
width: 300px;
|
65 |
+
height: 100px;
|
66 |
+
vertical-align: middle;
|
67 |
+
text-align: center;
|
68 |
+
}
|
69 |
+
|
70 |
+
.laButtonsTableHeader {
|
71 |
+
position: relative;
|
72 |
+
float: left;
|
73 |
+
overflow: auto;
|
74 |
+
width: 300px;
|
75 |
+
text-align: center;
|
76 |
+
}
|
77 |
+
|
78 |
+
.laButtonsTable {
|
79 |
+
position: relative;
|
80 |
+
clear: both;
|
81 |
+
}
|
82 |
+
|
83 |
+
.laButtonsTableSubmit {
|
84 |
+
clear: both;
|
85 |
+
float: left;
|
86 |
+
}
|
87 |
+
|
88 |
+
.laButtonsTableHeaderType,
|
89 |
+
.laButtonsTableCellType {
|
90 |
+
width:150px;
|
91 |
+
}
|
92 |
+
|
93 |
+
.laButtonsTableHeaderEnabled,
|
94 |
+
.laButtonsTableCellEnabled {
|
95 |
+
width:150px;
|
96 |
+
}
|
97 |
+
|
98 |
+
.laButtonsTableCellType,
|
99 |
+
.laButtonsTableCellEnabled {
|
100 |
+
line-height:100px;
|
101 |
+
position:relative;
|
102 |
+
}
|
103 |
+
|
104 |
+
.laCheckboxWrap {
|
105 |
+
position:absolute;
|
106 |
+
top:50%;
|
107 |
+
left:50%;
|
108 |
+
width:14px;
|
109 |
+
height:14px;
|
110 |
+
}
|
111 |
+
.laCheckboxWrap input {
|
112 |
+
position:relative;
|
113 |
+
top:-5px;
|
114 |
+
left:-5px;
|
115 |
+
margin:0;
|
116 |
+
}
|
117 |
+
|
118 |
+
.VisitsTableHeader {
|
119 |
+
font-weight: bold;
|
120 |
+
}
|
121 |
+
|
122 |
+
.VisitorCell{
|
123 |
+
}
|
124 |
+
|
125 |
+
.VisitorLocation {
|
126 |
+
float: left;
|
127 |
+
clear: both;
|
128 |
+
font-weight: bold;
|
129 |
+
}
|
130 |
+
|
131 |
+
.VisitorFirstTime, .VisitorLastTime, .VisitorName, .VisitorRefUrl, .VisitorUrl {
|
132 |
+
float: left;
|
133 |
+
clear: both;
|
134 |
+
}
|
135 |
+
|
136 |
+
/* NEW CLASSES */
|
137 |
+
|
138 |
+
.nlFormFieldDomain nlDomainSelection {float:left;width: 186px;}
|
139 |
+
|
140 |
+
.clear {clear:both;}
|
141 |
+
.nlFormField {margin:0 0 15px 0;}
|
142 |
+
.nlFormFieldLabel {font-size:13px; font-weight:bold;}
|
143 |
+
.nlFormFieldInput, .nlFormFieldInputDomain {background:#fff; border:1px solid #949494; border-color:#888888 #AAAAAA #DDDDDD; border-radius:7px 7px 7px 7px; border-style:solid; border-width:1px; height:35px;}
|
144 |
+
.nlInput, .nlFormFieldInput .password-focus, .nlFormFieldInput .password, .nlFormFieldInput .text, .nlFormFieldInput .text-focus {font-size:17px !important; border-radius:5px 5px 5px 5px; height:100%; margin:0; border:none; padding:0 6px; width:275px;}
|
145 |
+
.nlFormFieldInputDomain .text-focus, .nlFormFieldInputDomain .text {font-size:17px !important; border-radius:5px 5px 5px 5px; height:100%; margin:0; border:none; padding:0 6px; width:186px;}
|
146 |
+
|
147 |
+
.nlStepBox {margin:20px 0; width:962px; font-family:\'PT Sans\', arial, serif; position:relative;}
|
148 |
+
.nlStepHeader {background:#1a1a1a url(\'#\') repeat-x; border-radius:8px 8px 0 0; -moz-border-radius:8px 8px 0 0; -webkit-border-radius:8px 8px 0 0; padding:18px 20px; text-align:left; font-size:25px; font-weight:bold; color:#bebebe;}
|
149 |
+
.nlStepHeaderLeft {float:left;}
|
150 |
+
.nlStepNumber {font-weight:normal;}
|
151 |
+
.nlStepHeaderRight {float:right; text-align:right; font-weight:normal; line-height:18px;}
|
152 |
+
.nlStepBoxContent {min-height:320px; _height:320px; background:#d9d9d9; border-radius:0 0 8px 8px; -moz-border-radius:0 0 8px 8px; -webkit-border-radius:0 0 8px 8px; border:1px solid #fc8700; padding:15px 0; background: -webkit-gradient(linear, left top, left bottom, from(#fd8100), to(#fdab00)); background:-moz-linear-gradient(top,#fd8100,#fdab00); filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=\'#fd8100\', endColorstr=\'#fdab00\');}
|
153 |
+
.nlStepBoxLeft {width:300px; float:left; margin:0 20px;}
|
154 |
+
.nlBoxWithScreenshots {position:absolute; top:50px; left:350px; width:590px; height:395px; background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAk4AAAGKCAYAAAD6yM7KAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2RpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo5MTNCMDlDRTZGODBFMDExQUEzQUUyQ0Q5QjkxNTQ0NCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDoxMUEzMEMxMzhCOTUxMUUwQjIyRUZCRDUyQjM5REIzOSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxMUEzMEMxMjhCOTUxMUUwQjIyRUZCRDUyQjM5REIzOSIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IFdpbmRvd3MiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo3NjM3RENDQTZFOEJFMDExQTU2RUZDMkVGQjU4NTkyRiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo5MTNCMDlDRTZGODBFMDExQUEzQUUyQ0Q5QjkxNTQ0NCIvPiA8L3JkZjpEZXNjcmlwdGlv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) no-repeat top left;}
|
155 |
+
.nlDomainSelection {width:200px; float:left;}
|
156 |
+
.nlDomainSelection .nlInput {width:186px;}
|
157 |
+
.nlDomainName {width:80px; float:left; font-size:13px; margin:10px 0 0 10px;}
|
158 |
+
.nlTermsAndConditions {font-size:11px; font-family:"Trebuchet MS",Arial,Verdana; margin:0 0 15px;}
|
159 |
+
.nlTermsAndConditions a {color:#26813f;}
|
160 |
+
.nlTermsAndConditions a:hover {text-decoration:none;}
|
161 |
+
.nlContactUs {position:absolute; right:25px; bottom:20px; text-align:right;}
|
162 |
+
.nlOwnButtons {position:absolute; left:25px; bottom:20px; text-align:left;}
|
163 |
+
.nlGridHolder {padding:20px;}
|
164 |
+
|
165 |
+
.nlAboveStepBox {font-family:\'PT Sans\', arial, serif;}
|
166 |
+
.nlAboveStepBox .nlStepBoxLeft {margin:0;}
|
167 |
+
|
168 |
+
.nlBigButton {text-decoration:none; cursor:pointer; text-align:center; font-size:23px; line-height:50px; color:#295700; padding:0; clear:both; margin:10px 0 5px; display:block; box-shadow:#222 0 1px 2px; -moz-box-shadow:#222 0 1px 2px; webkit-box-shadow:#222 0 1px 2px; font-weight:bold; text-shadow:#cff400 0px 1px 1px; color:#295700; display:block; background:#5ac600; -moz-border-radius:5px; -webkit-border-radius:5px; border-radius:5px 5px 5px 5px; text-decoration:none; text-align:center; background: -webkit-gradient(linear, left top, left bottom, from(#c2e800), to(#5ec400)); background:-moz-linear-gradient(top,#c2e800,#5ec400); filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=\'#c2e800\', endColorstr=\'#5ec400\');}
|
169 |
+
.nlBigButton:hover {background:#7fe710; background: -webkit-gradient(linear, left top, left bottom, from(#d1f200), to(#8bdd00)); background:-moz-linear-gradient(top,#d1f200,#8bdd00); filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=\'#d1f200\', endColorstr=\'#8bdd00\');}
|
170 |
+
.nlBigButton.nlSmallText {font-size:14px;}
|
171 |
+
|
172 |
+
.nlDarkOrangeText {color:#7d4000; font-size:14px;}
|
173 |
+
.nlDarkOrangeText.nlSmallText {font-size:12px;}
|
174 |
+
.nlDarkOrangeText a {color:#7d4000;}
|
175 |
+
.nlDarkOrangeText a:hover {color:#7d4000; text-decoration:none;}
|
176 |
+
|
177 |
+
.nlDarkGrayText {color:#333; font-size:14px; margin:0 0 10px;}
|
178 |
+
.nlDarkGrayText a {color:#333;}
|
179 |
+
.nlDarkGrayText a:hover {color:#333; text-decoration:none;}
|
180 |
+
|
181 |
+
.nlLightText {color:#bebebe; font-size:14px;}
|
182 |
+
.nlLightText a {color:#bebebe;}
|
183 |
+
.nlLightText a:hover {color:#bebebe; text-decoration:none;}
|
184 |
+
|
185 |
+
.nlHurrayMessage {font-size:17px; font-weight:bold; text-align:left; margin:0 0 10px;}
|
186 |
+
|
187 |
+
.nlLoader {height:50px; background:url(data:image/gif;base64,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) no-repeat center center; margin:20px 0;}
|
188 |
+
.nlLoader span {display:none;}
|
189 |
+
.buttonsSave {
|
190 |
+
width:150px;
|
191 |
+
clear:both;
|
192 |
+
float: left;
|
193 |
+
}
|
194 |
+
.buttonsSettings .nlStepHeader {
|
195 |
+
width: 902px;
|
196 |
+
}
|
197 |
+
.buttonsSettings .nlStepBoxContent {
|
198 |
+
width:900px;
|
199 |
+
float:left;
|
200 |
+
clear:both;
|
201 |
+
}
|
202 |
+
.nlFormFieldDesc {
|
203 |
+
font-size: 11px;
|
204 |
+
}
|
205 |
+
|
206 |
+
.nlFormFieldInputDomain {
|
207 |
+
float:left;
|
208 |
+
}
|
209 |
+
|
210 |
+
</style>
|
211 |
+
';
|
212 |
+
}
|
213 |
+
}
|
app/code/local/Qualityunit/Liveagent/Block/Dialog.php
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Qualityunit_Liveagent_Block_Dialog extends Qualityunit_Liveagent_Block_Base {
|
4 |
+
|
5 |
+
}
|
app/code/local/Qualityunit/Liveagent/Block/ErrorMessageWidget.php
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Qualityunit_Liveagent_Block_ErrorMessageWidget extends Qualityunit_Liveagent_Block_Base {
|
4 |
+
|
5 |
+
private $messages = array();
|
6 |
+
|
7 |
+
public function addMessage($message) {
|
8 |
+
$this->messages[] = $message;
|
9 |
+
}
|
10 |
+
|
11 |
+
protected function _toHtml() {
|
12 |
+
$messagesString = '';
|
13 |
+
foreach ($this->messages as $message) {
|
14 |
+
$messagesString .= "
|
15 |
+
<div class=\"laMessage\">".$message."</div>\n
|
16 |
+
";
|
17 |
+
}
|
18 |
+
$this->assignVariable('message', $messagesString);
|
19 |
+
return parent::_toHtml();
|
20 |
+
|
21 |
+
}
|
22 |
+
|
23 |
+
protected function getTemplateString() {
|
24 |
+
return '
|
25 |
+
<div class="wrap">
|
26 |
+
{message}
|
27 |
+
</div>
|
28 |
+
';
|
29 |
+
}
|
30 |
+
}
|
app/code/local/Qualityunit/Liveagent/Block/FloatButtonWidget.php
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Qualityunit_Liveagent_Block_FloatButtonWidget extends Qualityunit_Liveagent_Block_Base {
|
4 |
+
|
5 |
+
private $buttonCode = '';
|
6 |
+
|
7 |
+
public function setCode($code) {
|
8 |
+
$this->buttonCode = $code;
|
9 |
+
}
|
10 |
+
|
11 |
+
protected function getTemplateString() {
|
12 |
+
return $this->buttonCode;
|
13 |
+
}
|
14 |
+
}
|
app/code/local/Qualityunit/Liveagent/Block/Liveagent.php
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
class Qualityunit_Liveagent_Block_Liveagent extends Mage_Core_Block_Template
|
3 |
+
{
|
4 |
+
public function _prepareLayout()
|
5 |
+
{
|
6 |
+
return parent::_prepareLayout();
|
7 |
+
}
|
8 |
+
|
9 |
+
public function getLiveagent()
|
10 |
+
{
|
11 |
+
if (!$this->hasData('liveagent')) {
|
12 |
+
$this->setData('liveagent', Mage::registry('liveagent'));
|
13 |
+
}
|
14 |
+
return $this->getData('liveagent');
|
15 |
+
}
|
16 |
+
}
|
app/code/local/Qualityunit/Liveagent/Block/Signup.php
ADDED
@@ -0,0 +1,124 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Qualityunit_Liveagent_Block_Signup extends Qualityunit_Liveagent_Block_Base {
|
4 |
+
|
5 |
+
const FULL_NAME_FIELD = 'la-full-name';
|
6 |
+
|
7 |
+
public function _prepareLayout() {
|
8 |
+
parent::_prepareLayout();
|
9 |
+
$this->assignVariable('dialogCaption', Mage::helper('adminhtml')->__('Create your Free account'));
|
10 |
+
$this->assignVariable(self::FULL_NAME_FIELD, $this->getInputBox(self::FULL_NAME_FIELD, $this->getOwnerName()));
|
11 |
+
$this->assignVariable(Qualityunit_Liveagent_Helper_Settings::LA_OWNER_EMAIL_SETTING_NAME, $this->getInputBox(Qualityunit_Liveagent_Helper_Settings::LA_OWNER_EMAIL_SETTING_NAME, $this->getOwnerEmail()));
|
12 |
+
$this->assignVariable(Qualityunit_Liveagent_Helper_Settings::LA_URL_SETTING_NAME, $this->getInputBox(Qualityunit_Liveagent_Helper_Settings::LA_URL_SETTING_NAME, $this->getdomainOnly()));
|
13 |
+
$this->assignVariable('submitCaption', Mage::helper('adminhtml')->__('Create your account'));
|
14 |
+
$this->assignVariable('skipUrlAction', $this->curPageURL() . '?action=s');
|
15 |
+
$this->assignVariable('registerUrlAction', $this->getUrl('*/*/post'));
|
16 |
+
$this->assignVariable('formKey', Mage::getSingleton('core/session')->getFormKey());
|
17 |
+
}
|
18 |
+
|
19 |
+
private function getdomainOnly() {
|
20 |
+
$domain = preg_replace('/^(.*\.)?([^.]*\..*)$/', '$2', @$_SERVER['HTTP_HOST']);
|
21 |
+
if (trim($domain) == 'localhost') {
|
22 |
+
return strtolower(str_replace(' ', '', $this->getOwnerName())) . rand(100, 5000);
|
23 |
+
}
|
24 |
+
return $domain;
|
25 |
+
}
|
26 |
+
|
27 |
+
private function getOwnerName() {
|
28 |
+
try {
|
29 |
+
$user = Mage::getSingleton('admin/session')->getUser();
|
30 |
+
return $user->getFirstname() . ' ' . $user->getLastname();
|
31 |
+
} catch (Exception $e) {
|
32 |
+
Mage::log($e->getMessage(), Zend_Log::ERR);
|
33 |
+
return '';
|
34 |
+
}
|
35 |
+
}
|
36 |
+
|
37 |
+
private function getOwnerEmail() {
|
38 |
+
try {
|
39 |
+
$user = Mage::getSingleton('admin/session')->getUser();
|
40 |
+
return $user->getEmail();
|
41 |
+
} catch (Exception $e) {
|
42 |
+
Mage::log($e->getMessage(), Zend_Log::ERR);
|
43 |
+
return '';
|
44 |
+
}
|
45 |
+
}
|
46 |
+
|
47 |
+
protected function getTemplateString() {
|
48 |
+
return '
|
49 |
+
<div class="nlStepBox">
|
50 |
+
<div class="nlStepHeader">
|
51 |
+
<div class="nlStepHeaderLeft">
|
52 |
+
<span class="nlStepName">
|
53 |
+
{dialogCaption}
|
54 |
+
</span>
|
55 |
+
</div>
|
56 |
+
<div class="clear"></div>
|
57 |
+
</div>
|
58 |
+
<div class="nlStepBoxContent">
|
59 |
+
<div class="nlStepBoxLeft">
|
60 |
+
<form id="edit_form" name="edit_form" action="{registerUrlAction}" method="post">
|
61 |
+
<div class="nlFormField">
|
62 |
+
<div class="nlFormFieldLabel">
|
63 |
+
Full name
|
64 |
+
</div>
|
65 |
+
<div class="nlFormFieldInput">
|
66 |
+
{la-full-name}
|
67 |
+
</div>
|
68 |
+
</div>
|
69 |
+
<div class="nlFormField">
|
70 |
+
<div class="nlFormFieldLabel">
|
71 |
+
Email
|
72 |
+
</div>
|
73 |
+
<div class="nlFormFieldInput">
|
74 |
+
{la-owner-email}
|
75 |
+
</div>
|
76 |
+
</div>
|
77 |
+
<div class="nlFormField">
|
78 |
+
<div class="nlFormFieldLabel">
|
79 |
+
Domain selection
|
80 |
+
</div>
|
81 |
+
<div class="nlFormFieldInputDomain nlDomainSelection">
|
82 |
+
{la-url}
|
83 |
+
</div>
|
84 |
+
<div class="nlDomainName">
|
85 |
+
.ladesk.com
|
86 |
+
</div>
|
87 |
+
<div class="clear"></div>
|
88 |
+
</div>
|
89 |
+
<input name="form_key" type="hidden" value="{formKey}" />
|
90 |
+
<input name="action" type="hidden" value="r"/>
|
91 |
+
<input class="nlBigButton" value="{submitCaption}" type="submit" style="border-width:0px;width:300px;"/>
|
92 |
+
<div class="nlTermsAndConditions">
|
93 |
+
By creating an account I agree with
|
94 |
+
<a href="http://www.qualityunit.com/liveagent/pricing/hosted/terms-and-conditions" target="_blank">
|
95 |
+
Terms & Conditions
|
96 |
+
</a>
|
97 |
+
</div>
|
98 |
+
<div class="nlDarkOrangeText">
|
99 |
+
<a href="{skipUrlAction}" name="liveagent_link_onSignupCancel">
|
100 |
+
Skip this step, I have already account »
|
101 |
+
</a>
|
102 |
+
</div>
|
103 |
+
</form>
|
104 |
+
</div>
|
105 |
+
<div class="nlBoxWithScreenshots"></div>
|
106 |
+
<div class="nlContactUs">
|
107 |
+
<div class="nlDarkOrangeText">
|
108 |
+
Do you need help with this plugin?
|
109 |
+
</div>
|
110 |
+
<div class="nlDarkOrangeText">
|
111 |
+
Feel free to
|
112 |
+
<a href="http://support.qualityunit.com/la/chat/index.php?bid=858b57ea" target="_blank">
|
113 |
+
contact us
|
114 |
+
</a>
|
115 |
+
</div>
|
116 |
+
</div>
|
117 |
+
<div class="clear"></div>
|
118 |
+
</div>
|
119 |
+
</div>
|
120 |
+
</div>
|
121 |
+
<div class="clear"></div>
|
122 |
+
';
|
123 |
+
}
|
124 |
+
}
|
app/code/local/Qualityunit/Liveagent/Block/Waiting.php
ADDED
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
class Qualityunit_Liveagent_Block_Waiting extends Qualityunit_Liveagent_Block_Base {
|
3 |
+
protected function _prepareLayout() {
|
4 |
+
parent::_prepareLayout();
|
5 |
+
$this->assignVariable('dialogCaption', Mage::helper('adminhtml')->__('Account Installation'));
|
6 |
+
$this->assignVariable('completeUrlAction', $this->getUrl('*/*/post'));
|
7 |
+
$this->assignVariable('formKey', Mage::getSingleton('core/session')->getFormKey());
|
8 |
+
}
|
9 |
+
|
10 |
+
protected function getTemplateString() {
|
11 |
+
return '
|
12 |
+
<div class="wrap">
|
13 |
+
<div class="nlStepBox">
|
14 |
+
<div class="nlStepHeader">
|
15 |
+
<div class="nlStepHeaderLeft">
|
16 |
+
<span class="nlStepName">
|
17 |
+
{dialogCaption}
|
18 |
+
</span>
|
19 |
+
</div>
|
20 |
+
<div class="clear"></div>
|
21 |
+
</div>
|
22 |
+
<div class="nlStepBoxContent">
|
23 |
+
<div class="nlStepBoxLeft">
|
24 |
+
<div class="nlHurrayMessage">
|
25 |
+
Thank you!
|
26 |
+
</div>
|
27 |
+
|
28 |
+
<div class="nlDarkOrangeText">
|
29 |
+
Your account will be online within next few minutes.
|
30 |
+
<br/><br/>
|
31 |
+
</div>
|
32 |
+
<div class="nlDarkOrangeText">
|
33 |
+
Please wait, once it will be online ....
|
34 |
+
<br/><br/>
|
35 |
+
</div>
|
36 |
+
<div class="nlDarkOrangeText">
|
37 |
+
You should recieve confirmation email with your account credentials. <br/><br/>
|
38 |
+
Note: Sometimes account creation process may take a <a href=\'http://support.qualityunit.com/knowledgebase/live-agent/integration/magento-plugin/frequently-asked-questions.html\' target="_blank">bit longer</a>.
|
39 |
+
</div>
|
40 |
+
<div class="nlLoader"><span>loading...</span></div>
|
41 |
+
<div class="nlDarkOrangeText" name="liveagent_wait_status" id="liveagent_wait_status">
|
42 |
+
Installing...
|
43 |
+
</div>
|
44 |
+
</div>
|
45 |
+
<form id="liveagent_wait_form" name="edit_form" action="{completeUrlAction}" method="post">
|
46 |
+
<input name="form_key" type="hidden" value="{formKey}" />
|
47 |
+
<input name="action" type="hidden" value="r"/>
|
48 |
+
</form>
|
49 |
+
<div class="nlBoxWithScreenshots"></div>
|
50 |
+
<div class="nlContactUs">
|
51 |
+
<div class="nlDarkOrangeText">
|
52 |
+
Do you need help with this plugin?
|
53 |
+
</div>
|
54 |
+
<div class="nlDarkOrangeText">
|
55 |
+
Feel free to
|
56 |
+
<a href="http://support.qualityunit.com/la/chat/index.php?bid=858b57ea" target="_blank">
|
57 |
+
contact us
|
58 |
+
</a>
|
59 |
+
</div>
|
60 |
+
</div>
|
61 |
+
<div class="clear"></div>
|
62 |
+
</div>
|
63 |
+
</form>
|
64 |
+
</div>
|
65 |
+
</div>
|
66 |
+
<div class="clear"></div>
|
67 |
+
<script type="text/javascript"><!--//--><![CDATA[//><!--
|
68 |
+
setTimeout("document.getElementById(\'liveagent_wait_status\').innerHTML = \'Initializing...\'", 10);
|
69 |
+
var timer = 3000;
|
70 |
+
var percentage = 4;
|
71 |
+
for (i=0;i<24;i++) {
|
72 |
+
setTimeout("document.getElementById(\'liveagent_wait_status\').innerHTML = \'Installing " + percentage + "% ...\'", timer);
|
73 |
+
timer+=1000;
|
74 |
+
percentage+=4;
|
75 |
+
}
|
76 |
+
setTimeout("window.location.reload()", timer);
|
77 |
+
//--><!]]></script>
|
78 |
+
';
|
79 |
+
}
|
80 |
+
}
|
app/code/local/Qualityunit/Liveagent/Exception/ConnectProblem.php
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* @copyright Copyright (c) 2011 Quality Unit s.r.o.
|
4 |
+
* @author Juraj Simon
|
5 |
+
* @package MgLiveAgentPlugin
|
6 |
+
* @version 1.0.0
|
7 |
+
*
|
8 |
+
* Licensed under GPL2
|
9 |
+
*/
|
10 |
+
|
11 |
+
class Qualityunit_Liveagent_Exception_ConnectProblem extends Exception {}
|
12 |
+
?>
|
app/code/local/Qualityunit/Liveagent/Exception/SignupFailed.php
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* @copyright Copyright (c) 2011 Quality Unit s.r.o.
|
4 |
+
* @author Juraj Simon
|
5 |
+
* @package MgLiveAgentPlugin
|
6 |
+
* @version 1.0.0
|
7 |
+
*
|
8 |
+
* Licensed under GPL2
|
9 |
+
*/
|
10 |
+
|
11 |
+
class Qualityunit_Liveagent_Exception_SignupFailed extends Exception {}
|
12 |
+
?>
|
app/code/local/Qualityunit/Liveagent/Helper/Auth.php
ADDED
@@ -0,0 +1,79 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* @copyright Copyright (c) 2007 Quality Unit s.r.o.
|
4 |
+
* @author Juraj Simon
|
5 |
+
* @package WpLiveAgentPlugin
|
6 |
+
* @version 1.0.0
|
7 |
+
*
|
8 |
+
* Licensed under GPL2
|
9 |
+
*/
|
10 |
+
|
11 |
+
class Qualityunit_Liveagent_Helper_Auth extends Qualityunit_Liveagent_Helper_Base {
|
12 |
+
public function ping() {
|
13 |
+
if (strpos($this->getRemoteApiUrl(), '.ladesk.com') === false) {
|
14 |
+
$this->internalPing($this->getRemoteApiUrl());
|
15 |
+
return;
|
16 |
+
}
|
17 |
+
//hack to fix dns problem - should be romved in the future myla.ladesk.com is not accessible, but www.myla.ladesk.com is - so try both
|
18 |
+
try {
|
19 |
+
$this->internalPing($this->getRemoteApiUrl());
|
20 |
+
} catch (Qualityunit_Liveagent_Exception_ConnectProblem $e) {
|
21 |
+
$url = $this->getRemoteApiUrl();
|
22 |
+
$url = preg_replace('/http:\/\//', 'http://www.', $url);
|
23 |
+
$this->internalPing($url);
|
24 |
+
}
|
25 |
+
}
|
26 |
+
|
27 |
+
private function internalPing($url) {
|
28 |
+
$request = new La_Rpc_DataRequest("Gpf_Common_ConnectionUtil", "ping");
|
29 |
+
$request->setUrl($url);
|
30 |
+
try {
|
31 |
+
$request->sendNow();
|
32 |
+
} catch (Exception $e) {
|
33 |
+
$this->_log('Unable to ping Live Agent remotelly' . $e->getMessage());
|
34 |
+
throw new Qualityunit_Liveagent_Exception_ConnectProblem();
|
35 |
+
}
|
36 |
+
$data = $request->getData();
|
37 |
+
if ($data->getParam('status') != 'OK') {
|
38 |
+
throw new Qualityunit_Liveagent_Exception_ConnectProblem();
|
39 |
+
}
|
40 |
+
}
|
41 |
+
|
42 |
+
private function InternalLoginAndGetLoginData($url) {
|
43 |
+
$request = new La_Rpc_DataRequest("Gpf_Api_AuthService", "authenticate");
|
44 |
+
|
45 |
+
$request->setField('username' ,$this->settingsModel->getOwnerEmail());
|
46 |
+
$request->setField('password' ,$this->settingsModel->getOwnerPassword());
|
47 |
+
$request->setUrl($url);
|
48 |
+
try {
|
49 |
+
$request->sendNow();
|
50 |
+
} catch (Exception $e) {
|
51 |
+
$this->_log('Unable to login.');
|
52 |
+
//$this->_log($e->getMessage());
|
53 |
+
throw new Qualityunit_Liveagent_Exception_ConnectProblem();
|
54 |
+
}
|
55 |
+
if ($request->getData()->getParam('error')!=null) {
|
56 |
+
$this->_log('Answer from server: ' . print_r($request->getResponseObject()->toObject(), true));
|
57 |
+
throw new Qualityunit_Liveagent_Exception_ConnectProblem();
|
58 |
+
}
|
59 |
+
return $request->getData();
|
60 |
+
}
|
61 |
+
|
62 |
+
/**
|
63 |
+
* @return La_Rpc_Data
|
64 |
+
*/
|
65 |
+
public function LoginAndGetLoginData() {
|
66 |
+
if (strpos($this->getRemoteApiUrl(), '.ladesk.com') === false) {
|
67 |
+
return $this->InternalLoginAndGetLoginData($this->getRemoteApiUrl());
|
68 |
+
}
|
69 |
+
//hack to fix dns problem - should be romved in the future myla.ladesk.com is not accessible, but www.myla.ladesk.com is - so try both
|
70 |
+
try {
|
71 |
+
return $this->InternalLoginAndGetLoginData($this->getRemoteApiUrl());
|
72 |
+
} catch (Qualityunit_Liveagent_Exception_ConnectProblem $e) {
|
73 |
+
$url = $this->getRemoteApiUrl();
|
74 |
+
$url = preg_replace('/http:\/\//', 'http://www.', $url);
|
75 |
+
return $this->InternalLoginAndGetLoginData($url);
|
76 |
+
}
|
77 |
+
}
|
78 |
+
}
|
79 |
+
?>
|
app/code/local/Qualityunit/Liveagent/Helper/Base.php
ADDED
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* @copyright Copyright (c) 2007 Quality Unit s.r.o.
|
4 |
+
* @author Juraj Simon
|
5 |
+
* @package WpLiveAgentPlugin
|
6 |
+
* @version 1.0.0
|
7 |
+
*
|
8 |
+
* Licensed under GPL2
|
9 |
+
*/
|
10 |
+
|
11 |
+
class Qualityunit_Liveagent_Helper_Base {
|
12 |
+
/**
|
13 |
+
* @var Qualityunit_Liveagent_Helper_Settings
|
14 |
+
*/
|
15 |
+
protected $settingsModel;
|
16 |
+
const ACCOUNT_STATUS_NOTSET = 'N';
|
17 |
+
const ACCOUNT_STATUS_SET = 'S';
|
18 |
+
const ACCOUNT_STATUS_WAIT = 'W';
|
19 |
+
|
20 |
+
public function _log($message) {
|
21 |
+
Mage::log($message, Zend_Log::DEBUG);
|
22 |
+
}
|
23 |
+
|
24 |
+
public function __construct() {
|
25 |
+
$this->settingsModel = new Qualityunit_Liveagent_Helper_Settings();
|
26 |
+
}
|
27 |
+
|
28 |
+
public function showAdminError($error) {
|
29 |
+
Mage::log($message, Zend_Log::ERR);
|
30 |
+
}
|
31 |
+
|
32 |
+
public function showConnectionError() {
|
33 |
+
$this->showAdminError(Mage::helper('liveagent')->__('Unable to connect to Live Agent. please check your connection settings'));
|
34 |
+
}
|
35 |
+
|
36 |
+
public function getRemoteTrackJsUrl() {
|
37 |
+
return $this->settingsModel->getOption(Qualityunit_Liveagent_Helper_Settings::LA_URL_SETTING_NAME) . '/scripts/trackjs.php';
|
38 |
+
}
|
39 |
+
|
40 |
+
public function getRemotePixUrl() {
|
41 |
+
return $this->settingsModel->getOption(Qualityunit_Liveagent_Helper_Settings::LA_URL_SETTING_NAME) . '/scripts/pix.gif';
|
42 |
+
}
|
43 |
+
|
44 |
+
public function getRemoteApiUrl() {
|
45 |
+
return $this->settingsModel->getOption(Qualityunit_Liveagent_Helper_Settings::LA_URL_SETTING_NAME) . '/api/index.php';
|
46 |
+
}
|
47 |
+
|
48 |
+
protected function isEmpty($var) {
|
49 |
+
return $var=== null || $var=='';
|
50 |
+
}
|
51 |
+
}
|
52 |
+
?>
|
app/code/local/Qualityunit/Liveagent/Helper/Buttons.php
ADDED
@@ -0,0 +1,143 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* @copyright Copyright (c) 2007 Quality Unit s.r.o.
|
4 |
+
* @author Juraj Simon
|
5 |
+
* @package WpLiveAgentPlugin
|
6 |
+
* @version 1.0.0
|
7 |
+
*
|
8 |
+
* Licensed under GPL2
|
9 |
+
*/
|
10 |
+
|
11 |
+
class Qualityunit_Liveagent_Helper_Buttons extends Qualityunit_Liveagent_Helper_Base {
|
12 |
+
|
13 |
+
const CLASS_NAME = 'La_Button_ButtonTable';
|
14 |
+
|
15 |
+
public function refresh() {
|
16 |
+
$rows = $this->getData();
|
17 |
+
if ($rows->getSize() == 0) {
|
18 |
+
Mage::log('No buttons recieved from LA', Zend_Log::INFO);
|
19 |
+
return;
|
20 |
+
}
|
21 |
+
Mage::log($rows->getSize() . ' buttons recieved from LA', Zend_Log::INFO);
|
22 |
+
Mage::log(print_r($rows, true), Zend_Log::INFO);
|
23 |
+
$this->settingsModel->updateLastButtonsReloadTime();
|
24 |
+
//clear existing buttons
|
25 |
+
Mage::log('Clearing cached buttons...', Zend_Log::INFO);
|
26 |
+
$enabledButtons = array();
|
27 |
+
foreach (Mage::getModel('liveagent/buttons')->getCollection() as $row) {
|
28 |
+
Mage::log('Clearing button ' . $row->getButtonid() , Zend_Log::INFO);
|
29 |
+
if ($row->getOnlinestatus() == 'Y') {
|
30 |
+
$enabledButtons[] = $row->getButtonid();
|
31 |
+
}
|
32 |
+
$row->delete();
|
33 |
+
}
|
34 |
+
Mage::log('Clear complete', Zend_Log::INFO);
|
35 |
+
foreach ($rows as $row) {
|
36 |
+
Mage::log('Processing button ' . $row->get('id'), Zend_Log::INFO);
|
37 |
+
$button = Mage::getModel('liveagent/buttons')->load($row->get('id'), 'buttonid');
|
38 |
+
$button->setButtonid($row->get('id'));
|
39 |
+
$button->setUserid($row->get('userid'));
|
40 |
+
$button->setName($row->get('name'));
|
41 |
+
$button->setContenttype($row->get('contenttype'));
|
42 |
+
$button->setOnlinecode($row->get('onlinecode'));
|
43 |
+
$button->setOfflinecode($row->get('offlinecode'));
|
44 |
+
$button->setImpressions($row->get('impressions'));
|
45 |
+
$button->setChats($row->get('chats'));
|
46 |
+
$button->setData1($row->get('data1'));
|
47 |
+
$button->setData2($row->get('data2'));
|
48 |
+
$button->setData3($row->get('data3'));
|
49 |
+
$button->setData4($row->get('data4'));
|
50 |
+
$button->setData5($row->get('data5'));
|
51 |
+
if (in_array($row->get('id'), $enabledButtons)) {
|
52 |
+
$button->setOnlinestatus('Y');
|
53 |
+
} else {
|
54 |
+
$button->setOnlinestatus('N');
|
55 |
+
}
|
56 |
+
$button->save();
|
57 |
+
}
|
58 |
+
}
|
59 |
+
|
60 |
+
public function enableDefaultButtonIfNoImpressions() {
|
61 |
+
//b2222222 only for compatibility reasons
|
62 |
+
$button1 = Mage::getModel('liveagent/buttons')->load('b2222222', 'buttonid');
|
63 |
+
if ($button1->getButtonid() != '' && $button1->getImpressions() > 0) {
|
64 |
+
$this->enableDefaultButton();
|
65 |
+
}
|
66 |
+
$button2 = Mage::getModel('liveagent/buttons')->load('button1', 'buttonid');
|
67 |
+
if($button2->getButtonid() != '' && $button2->getImpressions() > 0) {
|
68 |
+
$this->enableDefaultButton('button1');
|
69 |
+
}
|
70 |
+
}
|
71 |
+
|
72 |
+
public function enableDefaultButton($buttonId = 'b2222222') {
|
73 |
+
//b2222222 only for compatibility reasons
|
74 |
+
$button = Mage::getModel('liveagent/buttons')->load($buttonId, 'buttonid');
|
75 |
+
if ($button->getButtonid() != '') {
|
76 |
+
$button->setOnlinestatus('Y');
|
77 |
+
$button->save();
|
78 |
+
}
|
79 |
+
}
|
80 |
+
|
81 |
+
public function getIntegrationCode($buttonId) {
|
82 |
+
return '<img src="'.$this->getRemotePixUrl().'" onLoad="LiveAgentTracker.createButton(\''.$buttonId.'\', this);"/>' . "\n";
|
83 |
+
}
|
84 |
+
|
85 |
+
public function setOption($name, $value) {
|
86 |
+
$setting = Mage::getModel('liveagent/settings')->load($name, 'name');
|
87 |
+
$setting->setValue($value);
|
88 |
+
$setting->setName($name);
|
89 |
+
$setting->save();
|
90 |
+
}
|
91 |
+
|
92 |
+
public function getOption($name) {
|
93 |
+
$setting = Mage::getModel('liveagent/settings')->load($name, 'name');
|
94 |
+
return $setting->getData('value');
|
95 |
+
}
|
96 |
+
|
97 |
+
public function getAccountStatus() {
|
98 |
+
return $this->getOption(Qualityunit_Liveagent_Helper_Settings::ACCOUNT_STATUS);
|
99 |
+
}
|
100 |
+
|
101 |
+
public function connectionSettingsAreEmpty() {
|
102 |
+
return $this->getOption(Qualityunit_Liveagent_Helper_Settings::LA_URL_SETTING_NAME) == '' && $this->getOption(Qualityunit_Liveagent_Helper_Settings::LA_OWNER_EMAIL_SETTING_NAME) == '';
|
103 |
+
}
|
104 |
+
|
105 |
+
private function internalGetData($url) {
|
106 |
+
$request = new La_Rpc_Request(self::CLASS_NAME, 'getRows');
|
107 |
+
try {
|
108 |
+
$request->setUrl($url);
|
109 |
+
} catch (Qualityunit_Liveagent_Exception_ConnectProblem $e) {
|
110 |
+
$this->_log('Unable to connect and get session id');
|
111 |
+
return new La_Data_RecordSet();
|
112 |
+
}
|
113 |
+
|
114 |
+
try {
|
115 |
+
$request->sendNow();
|
116 |
+
} catch (Exception $e) {
|
117 |
+
$this->_log(sprintf('Unable to get data for %s', self::CLASS_NAME));
|
118 |
+
$this->_log($e->getMessage());
|
119 |
+
return new La_Data_RecordSet();
|
120 |
+
}
|
121 |
+
$grid = new La_Data_Grid();
|
122 |
+
$grid->loadFromObject($request->getStdResponse());
|
123 |
+
return $grid->getRecordset();
|
124 |
+
}
|
125 |
+
|
126 |
+
public function getData() {
|
127 |
+
$url = $this->getRemoteApiUrl() . '?S=' . $this->settingsModel->getOwnerSessionId();
|
128 |
+
if (strpos($this->getRemoteApiUrl(), '.ladesk.com') === false) {
|
129 |
+
return $this->internalGetData($url);
|
130 |
+
}
|
131 |
+
$secondUrl = preg_replace('/http:\/\//', 'http://www.', $url);
|
132 |
+
try {
|
133 |
+
$rows = $this->internalGetData($url);
|
134 |
+
} catch (Exception $e) {
|
135 |
+
return $this->internalGetData($secondUrl);
|
136 |
+
}
|
137 |
+
if ($rows->getSize() == 0) {
|
138 |
+
return $this->internalGetData($secondUrl);
|
139 |
+
}
|
140 |
+
return $rows;
|
141 |
+
}
|
142 |
+
}
|
143 |
+
?>
|
app/code/local/Qualityunit/Liveagent/Helper/Data.php
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Qualityunit_Liveagent_Helper_Data extends Mage_Core_Helper_Abstract
|
4 |
+
{
|
5 |
+
|
6 |
+
}
|
app/code/local/Qualityunit/Liveagent/Helper/PhpApi.php
ADDED
@@ -0,0 +1,4310 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* @copyright Copyright (c) 2010-2011 Quality Unit s.r.o.
|
4 |
+
* @author Quality Unit
|
5 |
+
* @package PhpApi
|
6 |
+
*
|
7 |
+
* Licensed under the Quality Unit, s.r.o. Dual License Agreement,
|
8 |
+
* Version 1.0 (the "License"); you may not use this file except in compliance
|
9 |
+
* with the License. You may obtain a copy of the License at
|
10 |
+
* http://www.qualityunit.com/licenses/gpf
|
11 |
+
* Generated on: 2011-06-06 04:17:42
|
12 |
+
* Framework version: 1.5.22
|
13 |
+
*
|
14 |
+
*/
|
15 |
+
|
16 |
+
@ini_set('session.gc_maxlifetime', 28800);
|
17 |
+
@ini_set('session.cookie_path', '/');
|
18 |
+
@ini_set('session.use_cookies', true);
|
19 |
+
@ini_set('magic_quotes_runtime', false);
|
20 |
+
@ini_set('session.use_trans_sid', false);
|
21 |
+
@ini_set('zend.ze1_compatibility_mode', false);
|
22 |
+
|
23 |
+
if (!class_exists('La_Lang', false)) {
|
24 |
+
class La_Lang {
|
25 |
+
public static function _replaceArgs($message, $args = null) {
|
26 |
+
if (!is_array($args)) {
|
27 |
+
$args = func_get_args();
|
28 |
+
}
|
29 |
+
if(count($args) > 1 && substr_count($message, '%s') < count($args)) {
|
30 |
+
array_shift($args);
|
31 |
+
return vsprintf($message, $args);
|
32 |
+
}
|
33 |
+
return $message;
|
34 |
+
}
|
35 |
+
|
36 |
+
public static function _($message, $args = null, $langCode = '') {
|
37 |
+
if (!is_array($args)) {
|
38 |
+
$args = func_get_args();
|
39 |
+
}
|
40 |
+
return self::_replaceArgs($message, $args);
|
41 |
+
}
|
42 |
+
|
43 |
+
public static function _sys($message, $args = null) {
|
44 |
+
if (!is_array($args)) {
|
45 |
+
$args = func_get_args();
|
46 |
+
}
|
47 |
+
return self::_replaceArgs($message, $args);
|
48 |
+
}
|
49 |
+
|
50 |
+
public static function _runtime($message) {
|
51 |
+
return $message;
|
52 |
+
}
|
53 |
+
|
54 |
+
public static function _localizeRuntime($message, $langCode = '') {
|
55 |
+
preg_match_all('/##(.+?)##/ms', $message, $attributes, PREG_OFFSET_CAPTURE);
|
56 |
+
foreach ($attributes[1] as $index => $attribute) {
|
57 |
+
$message = str_replace($attributes[0][$index][0], self::_($attribute[0], null, $langCode), $message);
|
58 |
+
}
|
59 |
+
return $message;
|
60 |
+
|
61 |
+
}
|
62 |
+
}
|
63 |
+
}
|
64 |
+
|
65 |
+
if (!class_exists('La_Object', false)) {
|
66 |
+
class La_Object {
|
67 |
+
/**
|
68 |
+
* Translate input message into selected language.
|
69 |
+
* If translation will not be found, return same message.
|
70 |
+
*
|
71 |
+
* @param string $message
|
72 |
+
* @return string
|
73 |
+
*/
|
74 |
+
public function _($message) {
|
75 |
+
$args = func_get_args();
|
76 |
+
return La_Lang::_($message, $args);
|
77 |
+
}
|
78 |
+
|
79 |
+
/**
|
80 |
+
* Translates text enclosed in ##any text##
|
81 |
+
* This function is not parsed by language parser, because as input should be used e.g. texts loaded from database
|
82 |
+
*
|
83 |
+
* @param string $message String to translate
|
84 |
+
* @return string Translated text
|
85 |
+
*/
|
86 |
+
public function _localize($message) {
|
87 |
+
return La_Lang::_localizeRuntime($message);
|
88 |
+
}
|
89 |
+
|
90 |
+
/**
|
91 |
+
* Translate input message into default language defined in language settings for account.
|
92 |
+
* This function should be used in case message should be translated to default language (e.g. log messages written to event log)
|
93 |
+
*
|
94 |
+
* @param string $message
|
95 |
+
* @return string
|
96 |
+
*/
|
97 |
+
public function _sys($message) {
|
98 |
+
$args = func_get_args();
|
99 |
+
return La_Lang::_sys($message, $args);
|
100 |
+
}
|
101 |
+
}
|
102 |
+
|
103 |
+
} //end La_Object
|
104 |
+
|
105 |
+
if (!interface_exists('La_Controller', false)) {
|
106 |
+
interface La_Controller {
|
107 |
+
/**
|
108 |
+
* @throws La_Controller_Exception_UnsupportedRequest
|
109 |
+
*/
|
110 |
+
public function execute();
|
111 |
+
}
|
112 |
+
|
113 |
+
} //end La_Controller
|
114 |
+
|
115 |
+
if (!interface_exists('La_Rpc_Serializable', false)) {
|
116 |
+
interface La_Rpc_Serializable {
|
117 |
+
|
118 |
+
public function toObject();
|
119 |
+
|
120 |
+
public function toText();
|
121 |
+
}
|
122 |
+
|
123 |
+
} //end La_Rpc_Serializable
|
124 |
+
|
125 |
+
if (!interface_exists('La_Rpc_DataEncoder', false)) {
|
126 |
+
interface La_Rpc_DataEncoder {
|
127 |
+
function encodeResponse(La_Rpc_Serializable $response);
|
128 |
+
}
|
129 |
+
|
130 |
+
|
131 |
+
|
132 |
+
} //end La_Rpc_DataEncoder
|
133 |
+
|
134 |
+
if (!interface_exists('La_Rpc_DataDecoder', false)) {
|
135 |
+
interface La_Rpc_DataDecoder {
|
136 |
+
/**
|
137 |
+
* @param string $str
|
138 |
+
* @return StdClass
|
139 |
+
*/
|
140 |
+
function decode($str);
|
141 |
+
}
|
142 |
+
|
143 |
+
|
144 |
+
|
145 |
+
} //end La_Rpc_DataDecoder
|
146 |
+
|
147 |
+
if (!class_exists('La_Rpc_Array', false)) {
|
148 |
+
class La_Rpc_Array extends La_Object implements La_Rpc_Serializable, IteratorAggregate {
|
149 |
+
|
150 |
+
private $array;
|
151 |
+
|
152 |
+
function __construct(array $array = null){
|
153 |
+
if($array === null){
|
154 |
+
$this->array = array();
|
155 |
+
}else{
|
156 |
+
$this->array = $array;
|
157 |
+
}
|
158 |
+
}
|
159 |
+
|
160 |
+
public function add($response) {
|
161 |
+
if(is_scalar($response) || $response instanceof La_Rpc_Serializable) {
|
162 |
+
$this->array[] = $response;
|
163 |
+
return;
|
164 |
+
}
|
165 |
+
throw new La_Exception("Value of type " . gettype($response) . " is not scalar or La_Rpc_Serializable");
|
166 |
+
}
|
167 |
+
|
168 |
+
public function toObject() {
|
169 |
+
$array = array();
|
170 |
+
foreach ($this->array as $response) {
|
171 |
+
if($response instanceof La_Rpc_Serializable) {
|
172 |
+
$array[] = $response->toObject();
|
173 |
+
} else {
|
174 |
+
$array[] = $response;
|
175 |
+
}
|
176 |
+
}
|
177 |
+
return $array;
|
178 |
+
}
|
179 |
+
|
180 |
+
public function toText() {
|
181 |
+
return var_dump($this->array);
|
182 |
+
}
|
183 |
+
|
184 |
+
public function getCount() {
|
185 |
+
return count($this->array);
|
186 |
+
}
|
187 |
+
|
188 |
+
public function get($index) {
|
189 |
+
return $this->array[$index];
|
190 |
+
}
|
191 |
+
|
192 |
+
/**
|
193 |
+
*
|
194 |
+
* @return ArrayIterator
|
195 |
+
*/
|
196 |
+
public function getIterator() {
|
197 |
+
return new ArrayIterator($this->array);
|
198 |
+
}
|
199 |
+
}
|
200 |
+
|
201 |
+
} //end La_Rpc_Array
|
202 |
+
|
203 |
+
if (!class_exists('La_Rpc_Server', false)) {
|
204 |
+
class La_Rpc_Server extends La_Object implements La_Controller {
|
205 |
+
const REQUESTS = 'R';
|
206 |
+
const RUN_METHOD = 'run';
|
207 |
+
const FORM_REQUEST = 'FormRequest';
|
208 |
+
const FORM_RESPONSE = 'FormResponse';
|
209 |
+
const BODY_DATA_NAME = 'D';
|
210 |
+
|
211 |
+
|
212 |
+
const HANDLER_FORM = 'Y';
|
213 |
+
const HANDLER_JASON = 'N';
|
214 |
+
const HANDLER_WINDOW_NAME = 'W';
|
215 |
+
|
216 |
+
/**
|
217 |
+
* @var La_Rpc_DataEncoder
|
218 |
+
*/
|
219 |
+
private $dataEncoder;
|
220 |
+
/**
|
221 |
+
* @var La_Rpc_DataDecoder
|
222 |
+
*/
|
223 |
+
private $dataDecoder;
|
224 |
+
|
225 |
+
public function __construct() {
|
226 |
+
}
|
227 |
+
|
228 |
+
private function initDatabaseLogger() {
|
229 |
+
$logger = La_Log_Logger::getInstance();
|
230 |
+
|
231 |
+
if(!$logger->checkLoggerTypeExists(La_Log_LoggerDatabase::TYPE)) {
|
232 |
+
$logger->setGroup(La_Common_String::generateId(10));
|
233 |
+
$logLevel = La_Settings::get(La_Settings_Gpf::LOG_LEVEL_SETTING_NAME);
|
234 |
+
$logger->add(La_Log_LoggerDatabase::TYPE, $logLevel);
|
235 |
+
}
|
236 |
+
}
|
237 |
+
|
238 |
+
/**
|
239 |
+
* Return response to standard output
|
240 |
+
*/
|
241 |
+
public function execute($request = '') {
|
242 |
+
$response = $this->encodeResponse($this->executeRequest($request));
|
243 |
+
La_Http::output($response);
|
244 |
+
}
|
245 |
+
|
246 |
+
/**
|
247 |
+
* @return La_Rpc_Serializable
|
248 |
+
*/
|
249 |
+
public function executeRequest($request = '') {
|
250 |
+
try {
|
251 |
+
if(isset($_REQUEST[self::BODY_DATA_NAME])) {
|
252 |
+
$request = $this->parseRequestDataFromPost($_REQUEST[self::BODY_DATA_NAME]);
|
253 |
+
}
|
254 |
+
if($this->isStandardRequestUsed($_REQUEST)) {
|
255 |
+
$request = $this->setStandardRequest();
|
256 |
+
}
|
257 |
+
|
258 |
+
$this->setDecoder($request);
|
259 |
+
$params = new La_Rpc_Params($this->decodeRequest($request));
|
260 |
+
if ($params->getClass() == '' || $params->getMethod() == '') {
|
261 |
+
throw new La_Controller_Exception_UnsupportedRequest();
|
262 |
+
}
|
263 |
+
$this->setEncoder($params);
|
264 |
+
$response = $this->executeRequestParams($params);
|
265 |
+
} catch (La_Controller_Exception_UnsupportedRequest $e) {
|
266 |
+
throw $e;
|
267 |
+
} catch (Exception $e) {
|
268 |
+
return new La_Rpc_ExceptionResponse($e);
|
269 |
+
}
|
270 |
+
return $response;
|
271 |
+
}
|
272 |
+
|
273 |
+
private function parseRequestDataFromPost($data) {
|
274 |
+
if(get_magic_quotes_gpc()) {
|
275 |
+
return stripslashes($data);
|
276 |
+
}
|
277 |
+
return $data;
|
278 |
+
}
|
279 |
+
|
280 |
+
/**
|
281 |
+
*
|
282 |
+
* @param unknown_type $requestObj
|
283 |
+
* @return La_Rpc_Serializable
|
284 |
+
*/
|
285 |
+
private function executeRequestParams(La_Rpc_Params $params) {
|
286 |
+
if (La_Application::getInstance()->isInMaintenanceMode()
|
287 |
+
&& !La_Paths::getInstance()->isInstallModeActive()) {
|
288 |
+
return new La_Rpc_MaintenenceModeResponse();
|
289 |
+
}
|
290 |
+
try {
|
291 |
+
La_Db_LoginHistory::logRequest();
|
292 |
+
return $this->callServiceMethod($params);
|
293 |
+
} catch (La_Session_Exception_SessionExpired $e) {
|
294 |
+
return new La_Rpc_SessionExpiredResponse($e);
|
295 |
+
} catch (Exception $e) {
|
296 |
+
return new La_Rpc_ExceptionResponse($e);
|
297 |
+
}
|
298 |
+
}
|
299 |
+
|
300 |
+
/**
|
301 |
+
* @throws La_Session_Exception_SessionExpired
|
302 |
+
*/
|
303 |
+
protected function callServiceMethod(La_Rpc_Params $params) {
|
304 |
+
$method = new La_Rpc_ServiceMethod($params);
|
305 |
+
return $method->invoke($params);
|
306 |
+
}
|
307 |
+
|
308 |
+
/**
|
309 |
+
* Compute correct handler type for server response
|
310 |
+
*
|
311 |
+
* @param array $requestData
|
312 |
+
* @param string $type
|
313 |
+
* @return string
|
314 |
+
*/
|
315 |
+
private function getEncoderHandlerType($requestData) {
|
316 |
+
if ($this->isFormHandler($requestData, self::FORM_RESPONSE, self::HANDLER_FORM)) {
|
317 |
+
return self::HANDLER_FORM;
|
318 |
+
}
|
319 |
+
if ($this->isFormHandler($requestData, self::FORM_RESPONSE, self::HANDLER_WINDOW_NAME)) {
|
320 |
+
return self::HANDLER_WINDOW_NAME;
|
321 |
+
}
|
322 |
+
return self::HANDLER_JASON;
|
323 |
+
}
|
324 |
+
|
325 |
+
|
326 |
+
private function isFormHandler($requestData, $type, $handler) {
|
327 |
+
return (isset($_REQUEST[$type]) && $_REQUEST[$type] == $handler) ||
|
328 |
+
(isset($requestData) && isset($requestData[$type]) && $requestData[$type] == $handler);
|
329 |
+
}
|
330 |
+
|
331 |
+
private function decodeRequest($requestData) {
|
332 |
+
return $this->dataDecoder->decode($requestData);
|
333 |
+
}
|
334 |
+
|
335 |
+
private function isStandardRequestUsed($requestArray) {
|
336 |
+
return is_array($requestArray) && array_key_exists(La_Rpc_Params::CLASS_NAME, $requestArray);
|
337 |
+
}
|
338 |
+
|
339 |
+
private function setStandardRequest() {
|
340 |
+
return array_merge($_POST, $_GET);
|
341 |
+
}
|
342 |
+
|
343 |
+
private function isFormRequest($request) {
|
344 |
+
return $this->isFormHandler($request, self::FORM_REQUEST, self::HANDLER_FORM);
|
345 |
+
}
|
346 |
+
|
347 |
+
private function encodeResponse(La_Rpc_Serializable $response) {
|
348 |
+
return $this->dataEncoder->encodeResponse($response);
|
349 |
+
}
|
350 |
+
|
351 |
+
|
352 |
+
private function setDecoder($request) {
|
353 |
+
if ($this->isFormRequest($request)) {
|
354 |
+
$this->dataDecoder = new La_Rpc_FormHandler();
|
355 |
+
} else {
|
356 |
+
$this->dataDecoder = new La_Rpc_Json();
|
357 |
+
}
|
358 |
+
}
|
359 |
+
|
360 |
+
private function setEncoder(La_Rpc_Params $params) {
|
361 |
+
switch ($params->get(self::FORM_RESPONSE)) {
|
362 |
+
case self::HANDLER_FORM:
|
363 |
+
$this->dataEncoder = new La_Rpc_FormHandler();
|
364 |
+
break;
|
365 |
+
case self::HANDLER_WINDOW_NAME:
|
366 |
+
$this->dataEncoder = new La_Rpc_WindowNameHandler();
|
367 |
+
break;
|
368 |
+
default:
|
369 |
+
$this->dataEncoder = new La_Rpc_Json();
|
370 |
+
break;
|
371 |
+
}
|
372 |
+
}
|
373 |
+
|
374 |
+
/**
|
375 |
+
* Executes multi request
|
376 |
+
*
|
377 |
+
* @service
|
378 |
+
* @anonym
|
379 |
+
* @return La_Rpc_Serializable
|
380 |
+
*/
|
381 |
+
public function run(La_Rpc_Params $params) {
|
382 |
+
$requestArray = $params->get(self::REQUESTS);
|
383 |
+
|
384 |
+
$response = new La_Rpc_Array();
|
385 |
+
foreach ($requestArray as $request) {
|
386 |
+
$response->add($this->executeRequestParams(new La_Rpc_Params($request)));
|
387 |
+
}
|
388 |
+
return $response;
|
389 |
+
}
|
390 |
+
|
391 |
+
/**
|
392 |
+
* Set time offset between client and server and store it to session
|
393 |
+
* Offset is computed as client time - server time
|
394 |
+
*
|
395 |
+
* @anonym
|
396 |
+
* @service
|
397 |
+
* @param La_Rpc_Params $params
|
398 |
+
* @return La_Rpc_Action
|
399 |
+
*/
|
400 |
+
public function syncTime(La_Rpc_Params $params) {
|
401 |
+
$action = new La_Rpc_Action($params);
|
402 |
+
La_Module::getProperties()->setTimeOffset($action->getParam('offset')/1000);
|
403 |
+
$action->addOk();
|
404 |
+
return $action;
|
405 |
+
}
|
406 |
+
}
|
407 |
+
|
408 |
+
} //end La_Rpc_Server
|
409 |
+
|
410 |
+
if (!class_exists('La_Rpc_MultiRequest', false)) {
|
411 |
+
class La_Rpc_MultiRequest extends La_Object {
|
412 |
+
private $url = '';
|
413 |
+
/**
|
414 |
+
*
|
415 |
+
* @var La_Rpc_Array
|
416 |
+
*/
|
417 |
+
private $requests;
|
418 |
+
/**
|
419 |
+
* @var La_Rpc_Json
|
420 |
+
*/
|
421 |
+
private $json;
|
422 |
+
protected $serverClassName = 'Gpf_Rpc_Server';
|
423 |
+
|
424 |
+
private $sessionId = null;
|
425 |
+
|
426 |
+
private $debugRequests = false;
|
427 |
+
|
428 |
+
/**
|
429 |
+
* @var La_Rpc_MultiRequest
|
430 |
+
*/
|
431 |
+
private static $instance;
|
432 |
+
|
433 |
+
public function __construct() {
|
434 |
+
$this->json = new La_Rpc_Json();
|
435 |
+
$this->requests = new La_Rpc_Array();
|
436 |
+
}
|
437 |
+
|
438 |
+
/**
|
439 |
+
* @return La_Rpc_MultiRequest
|
440 |
+
*/
|
441 |
+
public static function getInstance() {
|
442 |
+
if(self::$instance === null) {
|
443 |
+
self::$instance = new La_Rpc_MultiRequest();
|
444 |
+
}
|
445 |
+
return self::$instance;
|
446 |
+
}
|
447 |
+
|
448 |
+
public static function setInstance(La_Rpc_MultiRequest $instance) {
|
449 |
+
self::$instance = $instance;
|
450 |
+
}
|
451 |
+
|
452 |
+
public function add(La_Rpc_Request $request) {
|
453 |
+
$this->requests->add($request);
|
454 |
+
}
|
455 |
+
|
456 |
+
protected function sendRequest($requestBody) {
|
457 |
+
$request = new La_Net_Http_Request();
|
458 |
+
|
459 |
+
$request->setMethod('POST');
|
460 |
+
$request->setBody(La_Rpc_Server::BODY_DATA_NAME . '=' . urlencode($requestBody));
|
461 |
+
$request->setUrl($this->url);
|
462 |
+
|
463 |
+
$client = new La_Net_Http_Client();
|
464 |
+
$response = $client->execute($request);
|
465 |
+
return $response->getBody();
|
466 |
+
}
|
467 |
+
|
468 |
+
public function setSessionId($sessionId) {
|
469 |
+
$this->sessionId = $sessionId;
|
470 |
+
}
|
471 |
+
|
472 |
+
public function setDebugRequests($debug) {
|
473 |
+
$this->debugRequests = $debug;
|
474 |
+
}
|
475 |
+
|
476 |
+
public function send() {
|
477 |
+
$request = new La_Rpc_Request($this->serverClassName, La_Rpc_Server::RUN_METHOD);
|
478 |
+
$request->addParam(La_Rpc_Server::REQUESTS, $this->requests);
|
479 |
+
if($this->sessionId != null) {
|
480 |
+
$request->addParam("S", $this->sessionId);
|
481 |
+
}
|
482 |
+
$requestBody = $this->json->encodeResponse($request);
|
483 |
+
$responseText = $this->sendRequest($requestBody);
|
484 |
+
$responseArray = $this->json->decode($responseText);
|
485 |
+
if (!is_array($responseArray)) {
|
486 |
+
throw new La_Exception("Response decoding failed: not array. Received text: $responseText");
|
487 |
+
}
|
488 |
+
|
489 |
+
if (count($responseArray) != $this->requests->getCount()) {
|
490 |
+
throw new La_Exception("Response decoding failed: Number of responses is not same as number of requests");
|
491 |
+
}
|
492 |
+
|
493 |
+
$exception = false;
|
494 |
+
foreach ($responseArray as $index => $response) {
|
495 |
+
if (is_object($response) && isset($response->e)) {
|
496 |
+
$exception = true;
|
497 |
+
$this->requests->get($index)->setResponseError($response->e);
|
498 |
+
} else {
|
499 |
+
$this->requests->get($index)->setResponse($response);
|
500 |
+
}
|
501 |
+
}
|
502 |
+
if($exception) {
|
503 |
+
$messages = '';
|
504 |
+
foreach ($this->requests as $request) {
|
505 |
+
$messages .= $request->getResponseError() . "|";
|
506 |
+
}
|
507 |
+
}
|
508 |
+
$this->requests = new La_Rpc_Array();
|
509 |
+
if($exception) {
|
510 |
+
throw new La_Rpc_ExecutionException($messages);
|
511 |
+
}
|
512 |
+
}
|
513 |
+
|
514 |
+
public function setUrl($url) {
|
515 |
+
$this->url = $url;
|
516 |
+
}
|
517 |
+
|
518 |
+
public function getUrl() {
|
519 |
+
return $this->url;
|
520 |
+
}
|
521 |
+
|
522 |
+
private function getCookies() {
|
523 |
+
$cookiesString = '';
|
524 |
+
foreach ($_COOKIE as $name => $value) {
|
525 |
+
$cookiesString .= "$name=$value;";
|
526 |
+
}
|
527 |
+
return $cookiesString;
|
528 |
+
}
|
529 |
+
}
|
530 |
+
|
531 |
+
|
532 |
+
} //end La_Rpc_MultiRequest
|
533 |
+
|
534 |
+
if (!class_exists('La_Rpc_Params', false)) {
|
535 |
+
class La_Rpc_Params extends La_Object implements La_Rpc_Serializable {
|
536 |
+
private $params;
|
537 |
+
const CLASS_NAME = 'C';
|
538 |
+
const METHOD_NAME = 'M';
|
539 |
+
const SESSION_ID = 'S';
|
540 |
+
const ACCOUNT_ID = 'aid';
|
541 |
+
|
542 |
+
function __construct($params = null) {
|
543 |
+
if($params === null) {
|
544 |
+
$this->params = new stdClass();
|
545 |
+
return;
|
546 |
+
}
|
547 |
+
$this->params = $params;
|
548 |
+
}
|
549 |
+
|
550 |
+
public static function createGetRequest($className, $methodName = 'execute', $formRequest = false, $formResponse = false) {
|
551 |
+
$requestData = array();
|
552 |
+
$requestData[self::CLASS_NAME] = $className;
|
553 |
+
$requestData[self::METHOD_NAME] = $methodName;
|
554 |
+
$requestData[La_Rpc_Server::FORM_REQUEST] = $formRequest ? Gpf::YES : '';
|
555 |
+
$requestData[La_Rpc_Server::FORM_RESPONSE] = $formResponse ? Gpf::YES : '';
|
556 |
+
return $requestData;
|
557 |
+
}
|
558 |
+
|
559 |
+
/**
|
560 |
+
*
|
561 |
+
* @param unknown_type $className
|
562 |
+
* @param unknown_type $methodName
|
563 |
+
* @param unknown_type $formRequest
|
564 |
+
* @param unknown_type $formResponse
|
565 |
+
* @return La_Rpc_Params
|
566 |
+
*/
|
567 |
+
public static function create($className, $methodName = 'execute', $formRequest = false, $formResponse = false) {
|
568 |
+
$params = new La_Rpc_Params();
|
569 |
+
$obj = new stdClass();
|
570 |
+
foreach (self::createGetRequest($className, $methodName, $formRequest, $formResponse) as $name => $value) {
|
571 |
+
$params->add($name,$value);
|
572 |
+
}
|
573 |
+
return $params;
|
574 |
+
}
|
575 |
+
|
576 |
+
public function setArrayParams(array $params) {
|
577 |
+
foreach ($params as $name => $value) {
|
578 |
+
$this->add($name, $value);
|
579 |
+
}
|
580 |
+
}
|
581 |
+
|
582 |
+
public function exists($name) {
|
583 |
+
if(!is_object($this->params) || !array_key_exists($name, $this->params)) {
|
584 |
+
return false;
|
585 |
+
}
|
586 |
+
return true;
|
587 |
+
}
|
588 |
+
|
589 |
+
/**
|
590 |
+
*
|
591 |
+
* @param unknown_type $name
|
592 |
+
* @return mixed Return null if $name does not exist.
|
593 |
+
*/
|
594 |
+
public function get($name) {
|
595 |
+
if(!$this->exists($name)) {
|
596 |
+
return null;
|
597 |
+
}
|
598 |
+
return $this->params->{$name};
|
599 |
+
}
|
600 |
+
|
601 |
+
public function set($name, $value) {
|
602 |
+
if(!$this->exists($name)) {
|
603 |
+
return;
|
604 |
+
}
|
605 |
+
$this->params->{$name} = $value;
|
606 |
+
}
|
607 |
+
|
608 |
+
public function add($name, $value) {
|
609 |
+
$this->params->{$name} = $value;
|
610 |
+
}
|
611 |
+
|
612 |
+
public function getClass() {
|
613 |
+
return $this->get(self::CLASS_NAME);
|
614 |
+
}
|
615 |
+
|
616 |
+
public function getMethod() {
|
617 |
+
return $this->get(self::METHOD_NAME);
|
618 |
+
}
|
619 |
+
|
620 |
+
public function getSessionId() {
|
621 |
+
return $this->get(self::SESSION_ID);
|
622 |
+
}
|
623 |
+
|
624 |
+
public function clearSessionId() {
|
625 |
+
$this->set(self::SESSION_ID, null);
|
626 |
+
}
|
627 |
+
|
628 |
+
public function getAccountId() {
|
629 |
+
return $this->get(self::ACCOUNT_ID);
|
630 |
+
}
|
631 |
+
|
632 |
+
public function toObject() {
|
633 |
+
return $this->params;
|
634 |
+
}
|
635 |
+
|
636 |
+
public function toText() {
|
637 |
+
throw new La_Exception("Unimplemented");
|
638 |
+
}
|
639 |
+
}
|
640 |
+
|
641 |
+
|
642 |
+
} //end La_Rpc_Params
|
643 |
+
|
644 |
+
if (!class_exists('La_Exception', false)) {
|
645 |
+
class La_Exception extends Exception {
|
646 |
+
|
647 |
+
private $id;
|
648 |
+
|
649 |
+
public function __construct($message = '',$code = null) {
|
650 |
+
$trace = '';
|
651 |
+
foreach (debug_backtrace(false) as $i => $traceStep) {
|
652 |
+
$trace .= sprintf("#%s - %s::%s() at line %s<br>\n", $i, @$traceStep['class'], @$traceStep['function'], @$traceStep['line']);
|
653 |
+
}
|
654 |
+
$message .= "<br>\nTRACE:<br>\n" . $trace;
|
655 |
+
parent::__construct($message, $code);
|
656 |
+
}
|
657 |
+
|
658 |
+
protected function logException() {
|
659 |
+
La_Log::error($this->getMessage());
|
660 |
+
}
|
661 |
+
|
662 |
+
public function setId($id) {
|
663 |
+
$this->id = $id;
|
664 |
+
}
|
665 |
+
|
666 |
+
public function getId() {
|
667 |
+
return $this->id;
|
668 |
+
}
|
669 |
+
|
670 |
+
}
|
671 |
+
|
672 |
+
} //end La_Exception
|
673 |
+
|
674 |
+
if (!class_exists('La_Data_RecordSetNoRowException', false)) {
|
675 |
+
class La_Data_RecordSetNoRowException extends La_Exception {
|
676 |
+
public function __construct($keyValue) {
|
677 |
+
parent::__construct("'Row $keyValue does not exist");
|
678 |
+
}
|
679 |
+
|
680 |
+
protected function logException() {
|
681 |
+
}
|
682 |
+
}
|
683 |
+
|
684 |
+
} //end La_Data_RecordSetNoRowException
|
685 |
+
|
686 |
+
if (!class_exists('La_Rpc_ExecutionException', false)) {
|
687 |
+
class La_Rpc_ExecutionException extends La_Exception {
|
688 |
+
|
689 |
+
function __construct($message) {
|
690 |
+
parent::__construct('RPC Execution exception: ' . $message);
|
691 |
+
}
|
692 |
+
}
|
693 |
+
|
694 |
+
} //end La_Rpc_ExecutionException
|
695 |
+
|
696 |
+
if (!class_exists('La_Rpc_Object', false)) {
|
697 |
+
class La_Rpc_Object extends La_Object implements La_Rpc_Serializable {
|
698 |
+
|
699 |
+
private $object;
|
700 |
+
|
701 |
+
public function __construct($object = null) {
|
702 |
+
$this->object = $object;
|
703 |
+
}
|
704 |
+
|
705 |
+
public function toObject() {
|
706 |
+
if ($this->object != null) {
|
707 |
+
return $this->object;
|
708 |
+
}
|
709 |
+
return $this;
|
710 |
+
}
|
711 |
+
|
712 |
+
public function toText() {
|
713 |
+
return var_dump($this);
|
714 |
+
}
|
715 |
+
}
|
716 |
+
|
717 |
+
|
718 |
+
} //end La_Rpc_Object
|
719 |
+
|
720 |
+
if (!class_exists('La_Rpc_Request', false)) {
|
721 |
+
class La_Rpc_Request extends La_Object implements La_Rpc_Serializable {
|
722 |
+
protected $className;
|
723 |
+
protected $methodName;
|
724 |
+
private $responseError;
|
725 |
+
protected $response;
|
726 |
+
protected $apiSessionObject = null;
|
727 |
+
|
728 |
+
/**
|
729 |
+
* @var La_Rpc_MultiRequest
|
730 |
+
*/
|
731 |
+
private $multiRequest;
|
732 |
+
|
733 |
+
/**
|
734 |
+
* @var La_Rpc_Params
|
735 |
+
*/
|
736 |
+
protected $params;
|
737 |
+
private $accountId = null;
|
738 |
+
|
739 |
+
public function __construct($className, $methodName, La_Api_Session $apiSessionObject = null) {
|
740 |
+
$this->className = $className;
|
741 |
+
$this->methodName = $methodName;
|
742 |
+
$this->params = new La_Rpc_Params();
|
743 |
+
$this->setRequiredParams($this->className, $this->methodName);
|
744 |
+
if($apiSessionObject != null) {
|
745 |
+
$this->apiSessionObject = $apiSessionObject;
|
746 |
+
}
|
747 |
+
}
|
748 |
+
|
749 |
+
public function setAccountId($accountId) {
|
750 |
+
$this->accountId = $accountId;
|
751 |
+
}
|
752 |
+
|
753 |
+
public function addParam($name, $value) {
|
754 |
+
if(is_scalar($value) || is_null($value)) {
|
755 |
+
$this->params->add($name, $value);
|
756 |
+
return;
|
757 |
+
}
|
758 |
+
if($value instanceof La_Rpc_Serializable) {
|
759 |
+
$this->params->add($name, $value->toObject());
|
760 |
+
return;
|
761 |
+
}
|
762 |
+
throw new La_Exception("Cannot add request param: Value ($name=$value) is not scalar or La_Rpc_Serializable");
|
763 |
+
}
|
764 |
+
|
765 |
+
/**
|
766 |
+
*
|
767 |
+
* @return La_Rpc_MultiRequest
|
768 |
+
*/
|
769 |
+
private function getMultiRequest() {
|
770 |
+
if($this->multiRequest === null) {
|
771 |
+
return La_Rpc_MultiRequest::getInstance();
|
772 |
+
}
|
773 |
+
return $this->multiRequest;
|
774 |
+
}
|
775 |
+
|
776 |
+
public function setUrl($url) {
|
777 |
+
$this->multiRequest = new La_Rpc_MultiRequest();
|
778 |
+
$this->multiRequest->setUrl($url);
|
779 |
+
}
|
780 |
+
|
781 |
+
public function send() {
|
782 |
+
if($this->apiSessionObject != null) {
|
783 |
+
$this->multiRequest = new La_Rpc_MultiRequest();
|
784 |
+
$this->multiRequest->setUrl($this->apiSessionObject->getUrl());
|
785 |
+
$this->multiRequest->setSessionId($this->apiSessionObject->getSessionId());
|
786 |
+
$this->multiRequest->setDebugRequests($this->apiSessionObject->getDebug());
|
787 |
+
}
|
788 |
+
|
789 |
+
$multiRequest = $this->getMultiRequest();
|
790 |
+
$multiRequest->add($this);
|
791 |
+
}
|
792 |
+
|
793 |
+
public function sendNow() {
|
794 |
+
$this->send();
|
795 |
+
$this->getMultiRequest()->send();
|
796 |
+
}
|
797 |
+
|
798 |
+
public function setResponseError($message) {
|
799 |
+
$this->responseError = $message;
|
800 |
+
}
|
801 |
+
|
802 |
+
public function getResponseError() {
|
803 |
+
return $this->responseError;
|
804 |
+
}
|
805 |
+
|
806 |
+
public function setResponse($response) {
|
807 |
+
$this->response = $response;
|
808 |
+
}
|
809 |
+
|
810 |
+
public function toObject() {
|
811 |
+
return $this->params->toObject();
|
812 |
+
}
|
813 |
+
|
814 |
+
public function toText() {
|
815 |
+
throw new La_Exception("Unimplemented");
|
816 |
+
}
|
817 |
+
|
818 |
+
/**
|
819 |
+
*
|
820 |
+
* @return stdClass
|
821 |
+
*/
|
822 |
+
final public function getStdResponse() {
|
823 |
+
if(isset($this->responseError)) {
|
824 |
+
throw new La_Rpc_ExecutionException($this->responseError);
|
825 |
+
}
|
826 |
+
if($this->response === null) {
|
827 |
+
throw new La_Exception("Request not executed yet.");
|
828 |
+
}
|
829 |
+
return $this->response;
|
830 |
+
}
|
831 |
+
|
832 |
+
final public function getResponseObject() {
|
833 |
+
return new La_Rpc_Object($this->getStdResponse());
|
834 |
+
}
|
835 |
+
|
836 |
+
private function setRequiredParams($className, $methodName) {
|
837 |
+
$this->addParam(La_Rpc_Params::CLASS_NAME, $className);
|
838 |
+
$this->addParam(La_Rpc_Params::METHOD_NAME, $methodName);
|
839 |
+
}
|
840 |
+
|
841 |
+
/**
|
842 |
+
* @param La_Rpc_Params $params
|
843 |
+
*/
|
844 |
+
public function setParams(La_Rpc_Params $params) {
|
845 |
+
$originalParams = $this->params;
|
846 |
+
$this->params = $params;
|
847 |
+
$this->setRequiredParams($originalParams->getClass(), $originalParams->getMethod());
|
848 |
+
}
|
849 |
+
}
|
850 |
+
|
851 |
+
|
852 |
+
} //end La_Rpc_Request
|
853 |
+
|
854 |
+
if (!interface_exists('La_HttpResponse', false)) {
|
855 |
+
interface La_HttpResponse {
|
856 |
+
public function setCookieValue($name, $value = null, $expire = null, $path = null, $domain = null, $secure = null, $httpOnly = null);
|
857 |
+
|
858 |
+
public function setHeaderValue($name, $value, $replace = true, $httpResponseCode = null);
|
859 |
+
|
860 |
+
public function outputText($text);
|
861 |
+
}
|
862 |
+
|
863 |
+
} //end La_HttpResponse
|
864 |
+
|
865 |
+
if (!class_exists('La_Http', false)) {
|
866 |
+
class La_Http extends La_Object implements La_HttpResponse {
|
867 |
+
/**
|
868 |
+
*
|
869 |
+
* @var La_HttpResponse
|
870 |
+
*/
|
871 |
+
private static $instance = null;
|
872 |
+
|
873 |
+
/**
|
874 |
+
* @return La_Http
|
875 |
+
*/
|
876 |
+
private static function getInstance() {
|
877 |
+
if(self::$instance === null) {
|
878 |
+
self::$instance = new La_Http();
|
879 |
+
}
|
880 |
+
return self::$instance;
|
881 |
+
}
|
882 |
+
|
883 |
+
public static function setInstance(La_HttpResponse $instance) {
|
884 |
+
self::$instance = $instance;
|
885 |
+
}
|
886 |
+
|
887 |
+
public static function setCookie($name, $value = null, $expire = null, $path = null, $domain = null, $secure = null, $httpOnly = null) {
|
888 |
+
self::getInstance()->setCookieValue($name, $value, $expire, $path, $domain, $secure, $httpOnly);
|
889 |
+
}
|
890 |
+
|
891 |
+
public static function setHeader($name, $value, $httpResponseCode = null) {
|
892 |
+
self::getInstance()->setHeaderValue($name, $value, true, $httpResponseCode);
|
893 |
+
}
|
894 |
+
|
895 |
+
public static function output($text) {
|
896 |
+
self::getInstance()->outputText($text);
|
897 |
+
}
|
898 |
+
|
899 |
+
public function outputText($text) {
|
900 |
+
echo $text;
|
901 |
+
}
|
902 |
+
|
903 |
+
public function setHeaderValue($name, $value, $replace = true, $httpResponseCode = null) {
|
904 |
+
$fileName = '';
|
905 |
+
$line = '';
|
906 |
+
if(headers_sent($fileName, $line)) {
|
907 |
+
throw new La_Exception("Headers already sent in $fileName line $line while setting header $name: $value");
|
908 |
+
}
|
909 |
+
header($name . ': ' . $value, $replace, $httpResponseCode);
|
910 |
+
}
|
911 |
+
|
912 |
+
public function setCookieValue($name, $value = null, $expire = null, $path = null, $domain = null, $secure = null, $httpOnly = null) {
|
913 |
+
setcookie($name, $value, $expire, $path, $domain, $secure, $httpOnly);
|
914 |
+
}
|
915 |
+
|
916 |
+
public static function getCookie($name) {
|
917 |
+
if (!array_key_exists($name, $_COOKIE)) {
|
918 |
+
return null;
|
919 |
+
}
|
920 |
+
return $_COOKIE[$name];
|
921 |
+
}
|
922 |
+
|
923 |
+
public static function getRemoteIp() {
|
924 |
+
if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
|
925 |
+
return $_SERVER['HTTP_X_FORWARDED_FOR'];
|
926 |
+
}
|
927 |
+
if (isset($_SERVER['REMOTE_ADDR'])) {
|
928 |
+
return $_SERVER['REMOTE_ADDR'];
|
929 |
+
}
|
930 |
+
return '';
|
931 |
+
}
|
932 |
+
|
933 |
+
public static function getRemoteHost(){
|
934 |
+
return @gethostbyaddr(self::getRemoteIp());
|
935 |
+
}
|
936 |
+
}
|
937 |
+
|
938 |
+
} //end La_Http
|
939 |
+
|
940 |
+
if (!interface_exists('La_Templates_HasAttributes', false)) {
|
941 |
+
interface La_Templates_HasAttributes {
|
942 |
+
function getAttributes();
|
943 |
+
}
|
944 |
+
|
945 |
+
} //end La_Templates_HasAttributes
|
946 |
+
|
947 |
+
if (!class_exists('La_Data_RecordHeader', false)) {
|
948 |
+
class La_Data_RecordHeader extends La_Object {
|
949 |
+
private $ids = array();
|
950 |
+
|
951 |
+
/**
|
952 |
+
* Create Record header object
|
953 |
+
*
|
954 |
+
* @param array $headerArray
|
955 |
+
*/
|
956 |
+
public function __construct($headerArray = null) {
|
957 |
+
if($headerArray === null) {
|
958 |
+
return;
|
959 |
+
}
|
960 |
+
|
961 |
+
foreach ($headerArray as $id) {
|
962 |
+
$this->add($id);
|
963 |
+
}
|
964 |
+
}
|
965 |
+
|
966 |
+
public function contains($id) {
|
967 |
+
return array_key_exists($id, $this->ids);
|
968 |
+
}
|
969 |
+
|
970 |
+
public function add($id) {
|
971 |
+
if($this->contains($id)) {
|
972 |
+
return;
|
973 |
+
}
|
974 |
+
|
975 |
+
$this->ids[$id] = count($this->ids);
|
976 |
+
}
|
977 |
+
|
978 |
+
public function getIds() {
|
979 |
+
return array_keys($this->ids);
|
980 |
+
}
|
981 |
+
|
982 |
+
public function getIndex($id) {
|
983 |
+
if(!$this->contains($id)) {
|
984 |
+
throw new La_Exception("Unknown column '" . $id ."'");
|
985 |
+
}
|
986 |
+
return $this->ids[$id];
|
987 |
+
}
|
988 |
+
|
989 |
+
public function getSize() {
|
990 |
+
return count($this->ids);
|
991 |
+
}
|
992 |
+
|
993 |
+
public function toArray() {
|
994 |
+
$response = array();
|
995 |
+
foreach ($this->ids as $columnId => $columnIndex) {
|
996 |
+
$response[] = $columnId;
|
997 |
+
}
|
998 |
+
return $response;
|
999 |
+
}
|
1000 |
+
|
1001 |
+
public function toObject() {
|
1002 |
+
$result = array();
|
1003 |
+
foreach ($this->ids as $columnId => $columnIndex) {
|
1004 |
+
$result[] = $columnId;
|
1005 |
+
}
|
1006 |
+
return $result;
|
1007 |
+
}
|
1008 |
+
}
|
1009 |
+
|
1010 |
+
|
1011 |
+
} //end La_Data_RecordHeader
|
1012 |
+
|
1013 |
+
if (!interface_exists('La_Data_Row', false)) {
|
1014 |
+
interface La_Data_Row {
|
1015 |
+
public function get($name);
|
1016 |
+
|
1017 |
+
public function set($name, $value);
|
1018 |
+
}
|
1019 |
+
|
1020 |
+
} //end La_Data_Row
|
1021 |
+
|
1022 |
+
if (!class_exists('La_Data_Record', false)) {
|
1023 |
+
class La_Data_Record extends La_Object implements Iterator, La_Rpc_Serializable,
|
1024 |
+
La_Templates_HasAttributes, La_Data_Row {
|
1025 |
+
private $record;
|
1026 |
+
/**
|
1027 |
+
*
|
1028 |
+
* @var La_Data_RecordHeader
|
1029 |
+
*/
|
1030 |
+
private $header;
|
1031 |
+
private $position;
|
1032 |
+
|
1033 |
+
/**
|
1034 |
+
* Create record
|
1035 |
+
*
|
1036 |
+
* @param array $header
|
1037 |
+
* @param array $array values of record from array
|
1038 |
+
*/
|
1039 |
+
public function __construct($header, $array = array()) {
|
1040 |
+
if (is_array($header)) {
|
1041 |
+
$header = new La_Data_RecordHeader($header);
|
1042 |
+
}
|
1043 |
+
$this->header = $header;
|
1044 |
+
$this->record = array_values($array);
|
1045 |
+
while(count($this->record) < $this->header->getSize()) {
|
1046 |
+
$this->record[] = null;
|
1047 |
+
}
|
1048 |
+
}
|
1049 |
+
|
1050 |
+
function getAttributes() {
|
1051 |
+
$ret = array();
|
1052 |
+
foreach ($this as $name => $value) {
|
1053 |
+
$ret[$name] = $value;
|
1054 |
+
}
|
1055 |
+
return $ret;
|
1056 |
+
}
|
1057 |
+
|
1058 |
+
public function contains($id) {
|
1059 |
+
return $this->header->contains($id);
|
1060 |
+
}
|
1061 |
+
|
1062 |
+
public function get($id) {
|
1063 |
+
$index = $this->header->getIndex($id);
|
1064 |
+
return $this->record[$index];
|
1065 |
+
}
|
1066 |
+
|
1067 |
+
public function set($id, $value) {
|
1068 |
+
$index = $this->header->getIndex($id);
|
1069 |
+
$this->record[$index] = $value;
|
1070 |
+
}
|
1071 |
+
|
1072 |
+
public function add($id, $value) {
|
1073 |
+
$this->header->add($id);
|
1074 |
+
$this->set($id, $value);
|
1075 |
+
}
|
1076 |
+
|
1077 |
+
public function toObject() {
|
1078 |
+
return $this->record;
|
1079 |
+
}
|
1080 |
+
|
1081 |
+
public function loadFromObject(array $array) {
|
1082 |
+
$this->record = $array;
|
1083 |
+
}
|
1084 |
+
|
1085 |
+
public function toText() {
|
1086 |
+
return implode('-', $this->record);
|
1087 |
+
}
|
1088 |
+
|
1089 |
+
public function current() {
|
1090 |
+
if(!isset($this->record[$this->position])) {
|
1091 |
+
return null;
|
1092 |
+
}
|
1093 |
+
return $this->record[$this->position];
|
1094 |
+
}
|
1095 |
+
|
1096 |
+
public function key() {
|
1097 |
+
$ids = $this->header->getIds();
|
1098 |
+
return $ids[$this->position];
|
1099 |
+
}
|
1100 |
+
|
1101 |
+
public function next() {
|
1102 |
+
$this->position++;
|
1103 |
+
}
|
1104 |
+
|
1105 |
+
public function rewind() {
|
1106 |
+
$this->position = 0;
|
1107 |
+
}
|
1108 |
+
|
1109 |
+
public function valid() {
|
1110 |
+
return $this->position < $this->header->getSize();
|
1111 |
+
}
|
1112 |
+
}
|
1113 |
+
|
1114 |
+
|
1115 |
+
} //end La_Data_Record
|
1116 |
+
|
1117 |
+
if (!class_exists('La_Data_Grid', false)) {
|
1118 |
+
class La_Data_Grid extends La_Object {
|
1119 |
+
/**
|
1120 |
+
* @var La_Data_RecordSet
|
1121 |
+
*/
|
1122 |
+
private $recordset;
|
1123 |
+
private $totalCount;
|
1124 |
+
|
1125 |
+
public function loadFromObject(stdClass $object) {
|
1126 |
+
$this->recordset = new La_Data_RecordSet();
|
1127 |
+
$this->recordset->loadFromObject($object->R);
|
1128 |
+
$this->totalCount = $object->C;
|
1129 |
+
}
|
1130 |
+
|
1131 |
+
/**
|
1132 |
+
* @return La_Data_RecordSet
|
1133 |
+
*/
|
1134 |
+
public function getRecordset() {
|
1135 |
+
return $this->recordset;
|
1136 |
+
}
|
1137 |
+
|
1138 |
+
public function getTotalCount() {
|
1139 |
+
return $this->totalCount;
|
1140 |
+
}
|
1141 |
+
}
|
1142 |
+
|
1143 |
+
|
1144 |
+
} //end La_Data_Grid
|
1145 |
+
|
1146 |
+
if (!class_exists('La_Data_Filter', false)) {
|
1147 |
+
class La_Data_Filter extends La_Object implements La_Rpc_Serializable {
|
1148 |
+
const LIKE = "L";
|
1149 |
+
const NOT_LIKE = "NL";
|
1150 |
+
const EQUALS = "E";
|
1151 |
+
const NOT_EQUALS = "NE";
|
1152 |
+
|
1153 |
+
const DATE_EQUALS = "D=";
|
1154 |
+
const DATE_GREATER = "D>";
|
1155 |
+
const DATE_LOWER = "D<";
|
1156 |
+
const DATE_EQUALS_GREATER = "D>=";
|
1157 |
+
const DATE_EQUALS_LOWER = "D<=";
|
1158 |
+
const DATERANGE_IS = "DP";
|
1159 |
+
const TIME_EQUALS = "T=";
|
1160 |
+
const TIME_GREATER = "T>";
|
1161 |
+
const TIME_LOWER = "T<";
|
1162 |
+
const TIME_EQUALS_GREATER = "T>=";
|
1163 |
+
const TIME_EQUALS_LOWER = "T<=";
|
1164 |
+
|
1165 |
+
const RANGE_TODAY = 'T';
|
1166 |
+
const RANGE_YESTERDAY = 'Y';
|
1167 |
+
const RANGE_LAST_7_DAYS = 'L7D';
|
1168 |
+
const RANGE_LAST_30_DAYS = 'L30D';
|
1169 |
+
const RANGE_LAST_90_DAYS = 'L90D';
|
1170 |
+
const RANGE_THIS_WEEK = 'TW';
|
1171 |
+
const RANGE_LAST_WEEK = 'LW';
|
1172 |
+
const RANGE_LAST_2WEEKS = 'L2W';
|
1173 |
+
const RANGE_LAST_WORKING_WEEK = 'LWW';
|
1174 |
+
const RANGE_THIS_MONTH = 'TM';
|
1175 |
+
const RANGE_LAST_MONTH = 'LM';
|
1176 |
+
const RANGE_THIS_YEAR = 'TY';
|
1177 |
+
const RANGE_LAST_YEAR = 'LY';
|
1178 |
+
|
1179 |
+
private $code;
|
1180 |
+
private $operator;
|
1181 |
+
private $value;
|
1182 |
+
|
1183 |
+
public function __construct($code, $operator, $value) {
|
1184 |
+
$this->code = $code;
|
1185 |
+
$this->operator = $operator;
|
1186 |
+
$this->value = $value;
|
1187 |
+
}
|
1188 |
+
|
1189 |
+
public function toObject() {
|
1190 |
+
return array($this->code, $this->operator, $this->value);
|
1191 |
+
}
|
1192 |
+
|
1193 |
+
public function toText() {
|
1194 |
+
throw new La_Exception("Unsupported");
|
1195 |
+
}
|
1196 |
+
}
|
1197 |
+
|
1198 |
+
|
1199 |
+
} //end La_Data_Filter
|
1200 |
+
|
1201 |
+
if (!class_exists('La_Rpc_GridRequest', false)) {
|
1202 |
+
class La_Rpc_GridRequest extends La_Rpc_Request {
|
1203 |
+
|
1204 |
+
private $filters = array();
|
1205 |
+
|
1206 |
+
private $limit = '';
|
1207 |
+
private $offset = '';
|
1208 |
+
|
1209 |
+
private $sortColumn = '';
|
1210 |
+
private $sortAscending = false;
|
1211 |
+
|
1212 |
+
/**
|
1213 |
+
* @return La_Data_Grid
|
1214 |
+
*/
|
1215 |
+
public function getGrid() {
|
1216 |
+
$response = new La_Data_Grid();
|
1217 |
+
$response->loadFromObject($this->getStdResponse());
|
1218 |
+
return $response;
|
1219 |
+
}
|
1220 |
+
|
1221 |
+
public function getFilters() {
|
1222 |
+
return $this->filters;
|
1223 |
+
}
|
1224 |
+
|
1225 |
+
/**
|
1226 |
+
* adds filter to grid
|
1227 |
+
*
|
1228 |
+
* @param unknown_type $code
|
1229 |
+
* @param unknown_type $operator
|
1230 |
+
* @param unknown_type $value
|
1231 |
+
*/
|
1232 |
+
public function addFilter($code, $operator, $value) {
|
1233 |
+
$this->filters[] = new La_Data_Filter($code, $operator, $value);
|
1234 |
+
}
|
1235 |
+
|
1236 |
+
public function setLimit($offset, $limit) {
|
1237 |
+
$this->offset = $offset;
|
1238 |
+
$this->limit = $limit;
|
1239 |
+
}
|
1240 |
+
|
1241 |
+
public function setSorting($sortColumn, $sortAscending = false) {
|
1242 |
+
$this->sortColumn = $sortColumn;
|
1243 |
+
$this->sortAscending = $sortAscending;
|
1244 |
+
}
|
1245 |
+
|
1246 |
+
public function send() {
|
1247 |
+
if(count($this->filters) > 0) {
|
1248 |
+
$this->addParam("filters", $this->addFiltersParameter());
|
1249 |
+
}
|
1250 |
+
if($this->sortColumn !== '') {
|
1251 |
+
$this->addParam("sort_col", $this->sortColumn);
|
1252 |
+
$this->addParam("sort_asc", ($this->sortAscending ? 'true' : 'false'));
|
1253 |
+
}
|
1254 |
+
if($this->offset !== '') {
|
1255 |
+
$this->addParam("offset", $this->offset);
|
1256 |
+
}
|
1257 |
+
if($this->limit !== '') {
|
1258 |
+
$this->addParam("limit", $this->limit);
|
1259 |
+
}
|
1260 |
+
|
1261 |
+
parent::send();
|
1262 |
+
}
|
1263 |
+
|
1264 |
+
private function addFiltersParameter() {
|
1265 |
+
$filters = new La_Rpc_Array();
|
1266 |
+
|
1267 |
+
foreach($this->filters as $filter) {
|
1268 |
+
$filters->add($filter);
|
1269 |
+
}
|
1270 |
+
|
1271 |
+
return $filters;
|
1272 |
+
}
|
1273 |
+
}
|
1274 |
+
|
1275 |
+
|
1276 |
+
|
1277 |
+
} //end La_Rpc_GridRequest
|
1278 |
+
|
1279 |
+
if (!class_exists('La_Data_RecordSet', false)) {
|
1280 |
+
class La_Data_RecordSet extends La_Object implements IteratorAggregate, La_Rpc_Serializable {
|
1281 |
+
|
1282 |
+
const SORT_ASC = 'ASC';
|
1283 |
+
const SORT_DESC = 'DESC';
|
1284 |
+
|
1285 |
+
protected $_array;
|
1286 |
+
/**
|
1287 |
+
* @var La_Data_RecordHeader
|
1288 |
+
*/
|
1289 |
+
private $_header;
|
1290 |
+
|
1291 |
+
function __construct() {
|
1292 |
+
$this->init();
|
1293 |
+
}
|
1294 |
+
|
1295 |
+
public function loadFromArray($rows) {
|
1296 |
+
$this->setHeader($rows[0]);
|
1297 |
+
|
1298 |
+
for ($i = 1; $i < count($rows); $i++) {
|
1299 |
+
$this->add($rows[$i]);
|
1300 |
+
}
|
1301 |
+
}
|
1302 |
+
|
1303 |
+
public function setHeader($header) {
|
1304 |
+
if($header instanceof La_Data_RecordHeader) {
|
1305 |
+
$this->_header = $header;
|
1306 |
+
return;
|
1307 |
+
}
|
1308 |
+
$this->_header = new La_Data_RecordHeader($header);
|
1309 |
+
}
|
1310 |
+
|
1311 |
+
/**
|
1312 |
+
* @return La_Data_RecordHeader
|
1313 |
+
*/
|
1314 |
+
public function getHeader() {
|
1315 |
+
return $this->_header;
|
1316 |
+
}
|
1317 |
+
|
1318 |
+
public function addRecordAtStart(La_Data_Record $record) {
|
1319 |
+
array_unshift($this->_array, $record);
|
1320 |
+
}
|
1321 |
+
|
1322 |
+
public function addRecord(La_Data_Record $record) {
|
1323 |
+
$this->_array[] = $record;
|
1324 |
+
}
|
1325 |
+
|
1326 |
+
/**
|
1327 |
+
* Adds new row to RecordSet
|
1328 |
+
*
|
1329 |
+
* @param array $record array of data for all columns in record
|
1330 |
+
*/
|
1331 |
+
public function add($record) {
|
1332 |
+
$this->addRecord($this->getRecordObject($record));
|
1333 |
+
}
|
1334 |
+
|
1335 |
+
/**
|
1336 |
+
* @return La_Data_Record
|
1337 |
+
*/
|
1338 |
+
public function createRecord() {
|
1339 |
+
return new La_Data_Record($this->_header);
|
1340 |
+
}
|
1341 |
+
|
1342 |
+
public function toObject() {
|
1343 |
+
$response = array();
|
1344 |
+
$response[] = $this->_header->toObject();
|
1345 |
+
foreach ($this->_array as $record) {
|
1346 |
+
$response[] = $record->toObject();
|
1347 |
+
}
|
1348 |
+
return $response;
|
1349 |
+
}
|
1350 |
+
|
1351 |
+
public function loadFromObject(array $array) {
|
1352 |
+
$this->_header = new La_Data_RecordHeader($array[0]);
|
1353 |
+
for($i = 1; $i < count($array);$i++) {
|
1354 |
+
$record = new La_Data_Record($this->_header);
|
1355 |
+
$record->loadFromObject($array[$i]);
|
1356 |
+
$this->loadRecordFromObject($record);
|
1357 |
+
}
|
1358 |
+
}
|
1359 |
+
|
1360 |
+
public function sort($column, $sortType = 'ASC') {
|
1361 |
+
if (!$this->_header->contains($column)) {
|
1362 |
+
throw new La_Exception('Undefined column');
|
1363 |
+
}
|
1364 |
+
$sorter = new La_Data_RecordSet_Sorter($column, $sortType);
|
1365 |
+
$this->_array = $sorter->sort($this->_array);
|
1366 |
+
}
|
1367 |
+
|
1368 |
+
protected function loadRecordFromObject(La_Data_Record $record) {
|
1369 |
+
$this->_array[] = $record;
|
1370 |
+
}
|
1371 |
+
|
1372 |
+
public function toArray() {
|
1373 |
+
$response = array();
|
1374 |
+
foreach ($this->_array as $record) {
|
1375 |
+
$response[] = $record->getAttributes();
|
1376 |
+
}
|
1377 |
+
return $response;
|
1378 |
+
}
|
1379 |
+
|
1380 |
+
public function toText() {
|
1381 |
+
$text = '';
|
1382 |
+
foreach ($this->_array as $record) {
|
1383 |
+
$text .= $record->toText() . "<br>\n";
|
1384 |
+
}
|
1385 |
+
return $text;
|
1386 |
+
}
|
1387 |
+
|
1388 |
+
/**
|
1389 |
+
* Return number of rows in recordset
|
1390 |
+
*
|
1391 |
+
* @return integer
|
1392 |
+
*/
|
1393 |
+
public function getSize() {
|
1394 |
+
return count($this->_array);
|
1395 |
+
}
|
1396 |
+
|
1397 |
+
/**
|
1398 |
+
* @return La_Data_Record
|
1399 |
+
*/
|
1400 |
+
public function get($i) {
|
1401 |
+
return $this->_array[$i];
|
1402 |
+
}
|
1403 |
+
|
1404 |
+
/**
|
1405 |
+
* @param array/La_Data_Record $record
|
1406 |
+
* @return La_Data_Record
|
1407 |
+
*/
|
1408 |
+
private function getRecordObject($record) {
|
1409 |
+
if(!($record instanceof La_Data_Record)) {
|
1410 |
+
$record = new La_Data_Record($this->_header->toArray(), $record);
|
1411 |
+
}
|
1412 |
+
return $record;
|
1413 |
+
}
|
1414 |
+
|
1415 |
+
private function init() {
|
1416 |
+
$this->_array = array();
|
1417 |
+
$this->_header = new La_Data_RecordHeader();
|
1418 |
+
}
|
1419 |
+
|
1420 |
+
public function clear() {
|
1421 |
+
$this->init();
|
1422 |
+
}
|
1423 |
+
|
1424 |
+
public function load(La_SqlBuilder_SelectBuilder $select) {
|
1425 |
+
}
|
1426 |
+
|
1427 |
+
/**
|
1428 |
+
*
|
1429 |
+
* @return ArrayIterator
|
1430 |
+
*/
|
1431 |
+
public function getIterator() {
|
1432 |
+
return new ArrayIterator($this->_array);
|
1433 |
+
}
|
1434 |
+
|
1435 |
+
public function getRecord($keyValue = null) {
|
1436 |
+
if(!array_key_exists($keyValue, $this->_array)) {
|
1437 |
+
return $this->createRecord();
|
1438 |
+
}
|
1439 |
+
return $this->_array[$keyValue];
|
1440 |
+
}
|
1441 |
+
|
1442 |
+
public function addColumn($id, $defaultValue = "") {
|
1443 |
+
$this->_header->add($id);
|
1444 |
+
foreach ($this->_array as $record) {
|
1445 |
+
$record->add($id, $defaultValue);
|
1446 |
+
}
|
1447 |
+
}
|
1448 |
+
|
1449 |
+
/**
|
1450 |
+
* Creates shalow copy of recordset containing only headers
|
1451 |
+
*
|
1452 |
+
* @return La_Data_RecordSet
|
1453 |
+
*/
|
1454 |
+
public function toShalowRecordSet() {
|
1455 |
+
$copy = new La_Data_RecordSet();
|
1456 |
+
$copy->setHeader($this->_header->toArray());
|
1457 |
+
return $copy;
|
1458 |
+
}
|
1459 |
+
}
|
1460 |
+
|
1461 |
+
class La_Data_RecordSet_Sorter {
|
1462 |
+
|
1463 |
+
private $sortColumn;
|
1464 |
+
private $sortType;
|
1465 |
+
|
1466 |
+
function __construct($column, $sortType) {
|
1467 |
+
$this->sortColumn = $column;
|
1468 |
+
$this->sortType = $sortType;
|
1469 |
+
}
|
1470 |
+
|
1471 |
+
public function sort(array $sortedArray) {
|
1472 |
+
usort($sortedArray, array($this, 'compareRecords'));
|
1473 |
+
return $sortedArray;
|
1474 |
+
}
|
1475 |
+
|
1476 |
+
private function compareRecords($record1, $record2) {
|
1477 |
+
if ($record1->get($this->sortColumn) == $record2->get($this->sortColumn)) {
|
1478 |
+
return 0;
|
1479 |
+
}
|
1480 |
+
return $this->compare($record1->get($this->sortColumn), $record2->get($this->sortColumn));
|
1481 |
+
}
|
1482 |
+
|
1483 |
+
private function compare($value1, $value2) {
|
1484 |
+
if ($this->sortType == La_Data_RecordSet::SORT_ASC) {
|
1485 |
+
return ($value1 < $value2) ? -1 : 1;
|
1486 |
+
}
|
1487 |
+
return ($value1 < $value2) ? 1 : -1;
|
1488 |
+
}
|
1489 |
+
}
|
1490 |
+
|
1491 |
+
} //end La_Data_RecordSet
|
1492 |
+
|
1493 |
+
if (!class_exists('La_Data_IndexedRecordSet', false)) {
|
1494 |
+
class La_Data_IndexedRecordSet extends La_Data_RecordSet {
|
1495 |
+
private $key;
|
1496 |
+
|
1497 |
+
/**
|
1498 |
+
*
|
1499 |
+
* @param int $keyIndex specifies which column should be used as a key
|
1500 |
+
*/
|
1501 |
+
function __construct($key) {
|
1502 |
+
parent::__construct();
|
1503 |
+
$this->key = $key;
|
1504 |
+
}
|
1505 |
+
|
1506 |
+
public function addRecord(La_Data_Record $record) {
|
1507 |
+
$this->_array[$record->get($this->key)] = $record;
|
1508 |
+
}
|
1509 |
+
|
1510 |
+
/**
|
1511 |
+
* @param String $keyValue
|
1512 |
+
* @return La_Data_Record
|
1513 |
+
*/
|
1514 |
+
public function createRecord($keyValue = null) {
|
1515 |
+
if($keyValue === null) {
|
1516 |
+
return parent::createRecord();
|
1517 |
+
}
|
1518 |
+
if(!array_key_exists($keyValue, $this->_array)) {
|
1519 |
+
$record = $this->createRecord();
|
1520 |
+
$record->set($this->key, $keyValue);
|
1521 |
+
$this->addRecord($record);
|
1522 |
+
}
|
1523 |
+
return $this->_array[$keyValue];
|
1524 |
+
}
|
1525 |
+
|
1526 |
+
protected function loadRecordFromObject(La_Data_Record $record) {
|
1527 |
+
$this->_array[$record->get($this->key)] = $record;
|
1528 |
+
}
|
1529 |
+
|
1530 |
+
/**
|
1531 |
+
* @param String $keyValue
|
1532 |
+
* @return La_Data_Record
|
1533 |
+
*/
|
1534 |
+
public function getRecord($keyValue = null) {
|
1535 |
+
if (!isset($this->_array[$keyValue])) {
|
1536 |
+
throw new La_Data_RecordSetNoRowException($keyValue);
|
1537 |
+
}
|
1538 |
+
return $this->_array[$keyValue];
|
1539 |
+
}
|
1540 |
+
|
1541 |
+
/**
|
1542 |
+
* @param String $keyValue
|
1543 |
+
* @return boolean
|
1544 |
+
*/
|
1545 |
+
public function existsRecord($keyValue) {
|
1546 |
+
return isset($this->_array[$keyValue]);
|
1547 |
+
}
|
1548 |
+
|
1549 |
+
/**
|
1550 |
+
* @param String $sortOptions (SORT_ASC, SORT_DESC, SORT_REGULAR, SORT_NUMERIC, SORT_STRING)
|
1551 |
+
* @return boolean
|
1552 |
+
*/
|
1553 |
+
public function sortByKeyValue($sortOptions) {
|
1554 |
+
return array_multisort($this->_array, $sortOptions);
|
1555 |
+
}
|
1556 |
+
}
|
1557 |
+
|
1558 |
+
|
1559 |
+
} //end La_Data_IndexedRecordSet
|
1560 |
+
|
1561 |
+
if (!class_exists('La_Net_Http_Request', false)) {
|
1562 |
+
class La_Net_Http_Request extends La_Object {
|
1563 |
+
const CRLF = "\r\n";
|
1564 |
+
|
1565 |
+
private $method = 'GET';
|
1566 |
+
private $url;
|
1567 |
+
|
1568 |
+
//proxy server
|
1569 |
+
private $proxyServer = '';
|
1570 |
+
private $proxyPort = '';
|
1571 |
+
private $proxyUser = '';
|
1572 |
+
private $proxyPassword = '';
|
1573 |
+
|
1574 |
+
//URL components
|
1575 |
+
private $scheme = 'http';
|
1576 |
+
private $host = '';
|
1577 |
+
private $port = 80;
|
1578 |
+
private $http_user = '';
|
1579 |
+
private $http_password = '';
|
1580 |
+
private $path = '';
|
1581 |
+
private $query = '';
|
1582 |
+
private $fragment = '';
|
1583 |
+
private $cookies = '';
|
1584 |
+
|
1585 |
+
private $body = '';
|
1586 |
+
private $headers = array();
|
1587 |
+
|
1588 |
+
public function setCookies($cookies) {
|
1589 |
+
$this->cookies = $cookies;
|
1590 |
+
}
|
1591 |
+
|
1592 |
+
public function getCookies() {
|
1593 |
+
return $this->cookies;
|
1594 |
+
}
|
1595 |
+
|
1596 |
+
public function getCookiesHeader() {
|
1597 |
+
return "Cookie: " . $this->cookies;
|
1598 |
+
}
|
1599 |
+
|
1600 |
+
public function setUrl($url) {
|
1601 |
+
$this->url = $url;
|
1602 |
+
$this->parseUrl();
|
1603 |
+
}
|
1604 |
+
|
1605 |
+
public function getUrl() {
|
1606 |
+
return $this->url;
|
1607 |
+
}
|
1608 |
+
|
1609 |
+
private function parseUrl() {
|
1610 |
+
$components = @parse_url($this->url);
|
1611 |
+
if (!$components) {
|
1612 |
+
return;
|
1613 |
+
}
|
1614 |
+
if (array_key_exists('scheme', $components)) {
|
1615 |
+
$this->scheme = $components['scheme'];
|
1616 |
+
}
|
1617 |
+
if (array_key_exists('host', $components)) {
|
1618 |
+
$this->host = $components['host'];
|
1619 |
+
}
|
1620 |
+
if (array_key_exists('port', $components)) {
|
1621 |
+
$this->port = $components['port'];
|
1622 |
+
}
|
1623 |
+
if (array_key_exists('user', $components)) {
|
1624 |
+
$this->http_user = $components['user'];
|
1625 |
+
}
|
1626 |
+
if (array_key_exists('pass', $components)) {
|
1627 |
+
$this->http_password = $components['pass'];
|
1628 |
+
}
|
1629 |
+
if (array_key_exists('path', $components)) {
|
1630 |
+
$this->path = $components['path'];
|
1631 |
+
}
|
1632 |
+
if (array_key_exists('query', $components)) {
|
1633 |
+
$this->query = $components['query'];
|
1634 |
+
}
|
1635 |
+
if (array_key_exists('fragment', $components)) {
|
1636 |
+
$this->fragement = $components['fragment'];
|
1637 |
+
}
|
1638 |
+
}
|
1639 |
+
|
1640 |
+
public function getScheme() {
|
1641 |
+
return $this->scheme;
|
1642 |
+
}
|
1643 |
+
|
1644 |
+
public function getHost() {
|
1645 |
+
if (strlen($this->proxyServer)) {
|
1646 |
+
return $this->proxyServer;
|
1647 |
+
}
|
1648 |
+
return $this->host;
|
1649 |
+
}
|
1650 |
+
|
1651 |
+
public function getPort() {
|
1652 |
+
if (strlen($this->proxyServer)) {
|
1653 |
+
return $this->proxyPort;
|
1654 |
+
}
|
1655 |
+
|
1656 |
+
if (strlen($this->port)) {
|
1657 |
+
return $this->port;
|
1658 |
+
}
|
1659 |
+
return 80;
|
1660 |
+
}
|
1661 |
+
|
1662 |
+
public function getHttpUser() {
|
1663 |
+
return $this->http_user;
|
1664 |
+
}
|
1665 |
+
|
1666 |
+
public function setHttpUser($user) {
|
1667 |
+
$this->http_user = $user;
|
1668 |
+
}
|
1669 |
+
|
1670 |
+
public function getHttpPassword() {
|
1671 |
+
return $this->http_password;
|
1672 |
+
}
|
1673 |
+
|
1674 |
+
public function setHttpPassword($pass) {
|
1675 |
+
$this->http_password = $pass;
|
1676 |
+
}
|
1677 |
+
|
1678 |
+
public function getPath() {
|
1679 |
+
return $this->path;
|
1680 |
+
}
|
1681 |
+
|
1682 |
+
public function getQuery() {
|
1683 |
+
return $this->query;
|
1684 |
+
}
|
1685 |
+
|
1686 |
+
public function addQueryParam($name, $value) {
|
1687 |
+
if (is_array($value)) {
|
1688 |
+
foreach($value as $key => $subValue) {
|
1689 |
+
$this->addQueryParam($name."[".$key."]", $subValue);
|
1690 |
+
}
|
1691 |
+
return;
|
1692 |
+
}
|
1693 |
+
$this->query .= ($this->query == '') ? '?' : '&';
|
1694 |
+
$this->query .= $name.'='.urlencode($value);
|
1695 |
+
}
|
1696 |
+
|
1697 |
+
public function getFragemnt() {
|
1698 |
+
return $this->fragment;
|
1699 |
+
}
|
1700 |
+
|
1701 |
+
/**
|
1702 |
+
* Set if request method is GET or POST
|
1703 |
+
*
|
1704 |
+
* @param string $method possible values are POST or GET
|
1705 |
+
*/
|
1706 |
+
public function setMethod($method) {
|
1707 |
+
$method = strtoupper($method);
|
1708 |
+
if ($method != 'GET' && $method != 'POST') {
|
1709 |
+
throw new La_Exception('Unsupported HTTP method: ' . $method);
|
1710 |
+
}
|
1711 |
+
$this->method = $method;
|
1712 |
+
}
|
1713 |
+
|
1714 |
+
/**
|
1715 |
+
* get the request method
|
1716 |
+
*
|
1717 |
+
* @access public
|
1718 |
+
* @return string
|
1719 |
+
*/
|
1720 |
+
public function getMethod() {
|
1721 |
+
return $this->method;
|
1722 |
+
}
|
1723 |
+
|
1724 |
+
/**
|
1725 |
+
* In case request should be redirected through proxy server, set proxy server settings
|
1726 |
+
* This function should be called after function setHost !!!
|
1727 |
+
*
|
1728 |
+
* @param string $server
|
1729 |
+
* @param string $port
|
1730 |
+
* @param string $user
|
1731 |
+
* @param string $password
|
1732 |
+
*/
|
1733 |
+
public function setProxyServer($server, $port, $user, $password) {
|
1734 |
+
$this->proxyServer = $server;
|
1735 |
+
$this->proxyPort = $port;
|
1736 |
+
$this->proxyUser = $user;
|
1737 |
+
$this->proxyPassword = $password;
|
1738 |
+
}
|
1739 |
+
|
1740 |
+
public function getProxyServer() {
|
1741 |
+
return $this->proxyServer;
|
1742 |
+
}
|
1743 |
+
|
1744 |
+
public function getProxyPort() {
|
1745 |
+
return $this->proxyPort;
|
1746 |
+
}
|
1747 |
+
|
1748 |
+
public function getProxyUser() {
|
1749 |
+
return $this->proxyUser;
|
1750 |
+
}
|
1751 |
+
|
1752 |
+
public function getProxyPassword() {
|
1753 |
+
return $this->proxyPassword;
|
1754 |
+
}
|
1755 |
+
|
1756 |
+
public function setBody($body) {
|
1757 |
+
$this->body = $body;
|
1758 |
+
}
|
1759 |
+
|
1760 |
+
public function getBody() {
|
1761 |
+
return $this->body;
|
1762 |
+
}
|
1763 |
+
|
1764 |
+
/**
|
1765 |
+
* Set header value
|
1766 |
+
*
|
1767 |
+
* @param string $name
|
1768 |
+
* @param string $value
|
1769 |
+
*/
|
1770 |
+
public function setHeader($name, $value) {
|
1771 |
+
$this->headers[$name] = $value;
|
1772 |
+
}
|
1773 |
+
|
1774 |
+
/**
|
1775 |
+
* Get header value
|
1776 |
+
*
|
1777 |
+
* @param string $name
|
1778 |
+
* @return string
|
1779 |
+
*/
|
1780 |
+
public function getHeader($name) {
|
1781 |
+
if (array_key_exists($name, $this->headers)) {
|
1782 |
+
return $this->headers[$name];
|
1783 |
+
}
|
1784 |
+
return null;
|
1785 |
+
}
|
1786 |
+
|
1787 |
+
/**
|
1788 |
+
* Return array of headers
|
1789 |
+
*
|
1790 |
+
* @return array
|
1791 |
+
*/
|
1792 |
+
public function getHeaders() {
|
1793 |
+
$headers = array();
|
1794 |
+
foreach ($this->headers as $headerName => $headerValue) {
|
1795 |
+
$headers[] = "$headerName: $headerValue";
|
1796 |
+
}
|
1797 |
+
return $headers;
|
1798 |
+
}
|
1799 |
+
|
1800 |
+
private function initHeaders() {
|
1801 |
+
if ($this->getPort() == '80') {
|
1802 |
+
$this->setHeader('Host', $this->getHost());
|
1803 |
+
} else {
|
1804 |
+
$this->setHeader('Host', $this->getHost() . ':' . $this->getPort());
|
1805 |
+
}
|
1806 |
+
if (isset($_SERVER['HTTP_USER_AGENT'])) {
|
1807 |
+
$this->setHeader('User-Agent', $_SERVER['HTTP_USER_AGENT']);
|
1808 |
+
}
|
1809 |
+
if (isset($_SERVER['HTTP_ACCEPT'])) {
|
1810 |
+
$this->setHeader('Accept', $_SERVER['HTTP_ACCEPT']);
|
1811 |
+
}
|
1812 |
+
if (isset($_SERVER['HTTP_ACCEPT_CHARSET'])) {
|
1813 |
+
$this->setHeader('Accept-Charset', $_SERVER['HTTP_ACCEPT_CHARSET']);
|
1814 |
+
}
|
1815 |
+
if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
|
1816 |
+
$this->setHeader('Accept-Language', $_SERVER['HTTP_ACCEPT_LANGUAGE']);
|
1817 |
+
}
|
1818 |
+
if (isset($_SERVER['HTTP_REFERER'])) {
|
1819 |
+
$this->setHeader('Referer', $_SERVER['HTTP_REFERER']);
|
1820 |
+
}
|
1821 |
+
if ($this->getMethod() == 'POST' && !strlen($this->getHeader("Content-Type"))) {
|
1822 |
+
$this->setHeader("Content-Type", "application/x-www-form-urlencoded");
|
1823 |
+
}
|
1824 |
+
|
1825 |
+
$this->setHeader('Content-Length', strlen($this->getBody()));
|
1826 |
+
$this->setHeader('Connection', 'close');
|
1827 |
+
|
1828 |
+
if (strlen($this->proxyUser)) {
|
1829 |
+
$this->setHeader('Proxy-Authorization',
|
1830 |
+
'Basic ' . base64_encode ($this->proxyUser . ':' . $this->proxyPassword));
|
1831 |
+
}
|
1832 |
+
|
1833 |
+
}
|
1834 |
+
|
1835 |
+
public function getUri() {
|
1836 |
+
$uri = $this->getPath();
|
1837 |
+
if (strlen($this->getQuery())) {
|
1838 |
+
$uri .= '?' . $this->getQuery();
|
1839 |
+
}
|
1840 |
+
return $uri;
|
1841 |
+
}
|
1842 |
+
|
1843 |
+
public function toString() {
|
1844 |
+
$this->initHeaders();
|
1845 |
+
$out = sprintf('%s %s HTTP/1.0' . self::CRLF, $this->getMethod(), $this->getUri());
|
1846 |
+
$out .= implode(self::CRLF, $this->getHeaders()) . self::CRLF . $this->getCookiesHeader() . self::CRLF;
|
1847 |
+
$out .= self::CRLF . $this->getBody();
|
1848 |
+
return $out;
|
1849 |
+
}
|
1850 |
+
|
1851 |
+
}
|
1852 |
+
|
1853 |
+
} //end La_Net_Http_Request
|
1854 |
+
|
1855 |
+
if (!class_exists('La_Net_Http_ClientBase', false)) {
|
1856 |
+
abstract class La_Net_Http_ClientBase extends La_Object {
|
1857 |
+
const CONNECTION_TIMEOUT = 20;
|
1858 |
+
|
1859 |
+
//TODO: rename this method to "send()"
|
1860 |
+
/**
|
1861 |
+
* @param La_Net_Http_Request $request
|
1862 |
+
* @return La_Net_Http_Response
|
1863 |
+
*/
|
1864 |
+
public function execute(La_Net_Http_Request $request) {
|
1865 |
+
|
1866 |
+
if (!$this->isNetworkingEnabled()) {
|
1867 |
+
throw new La_Exception($this->_('Network connections are disabled'));
|
1868 |
+
}
|
1869 |
+
|
1870 |
+
if (!strlen($request->getUrl())) {
|
1871 |
+
throw new La_Exception('No URL defined.');
|
1872 |
+
}
|
1873 |
+
|
1874 |
+
$this->setProxyServer($request);
|
1875 |
+
if (La_Php::isFunctionEnabled('curl_init')) {
|
1876 |
+
return $this->executeWithCurl($request);
|
1877 |
+
} else {
|
1878 |
+
return $this->executeWithSocketOpen($request);
|
1879 |
+
}
|
1880 |
+
}
|
1881 |
+
|
1882 |
+
protected abstract function isNetworkingEnabled();
|
1883 |
+
|
1884 |
+
/**
|
1885 |
+
* @param La_Net_Http_Request $request
|
1886 |
+
* @return La_Net_Http_Response
|
1887 |
+
*/
|
1888 |
+
private function executeWithSocketOpen(La_Net_Http_Request $request) {
|
1889 |
+
$scheme = ($request->getScheme() == 'ssl' || $request->getScheme() == 'https') ? 'ssl://' : '';
|
1890 |
+
$proxySocket = @fsockopen($scheme . $request->getHost(), $request->getPort(), $errorNr,
|
1891 |
+
$errorMessage, self::CONNECTION_TIMEOUT);
|
1892 |
+
|
1893 |
+
if($proxySocket === false) {
|
1894 |
+
$gpfErrorMessage = $this->_sys('Could not connect to server: %s:%s, Failed with error: %s', $request->getHost(), $request->getPort(), $errorMessage);
|
1895 |
+
La_Log::error($gpfErrorMessage);
|
1896 |
+
throw new La_Exception($gpfErrorMessage);
|
1897 |
+
}
|
1898 |
+
|
1899 |
+
$requestText = $request->toString();
|
1900 |
+
|
1901 |
+
$result = @fwrite($proxySocket, $requestText);
|
1902 |
+
if($result === false || $result != strlen($requestText)) {
|
1903 |
+
@fclose($proxySocket);
|
1904 |
+
$gpfErrorMessage = $this->_sys('Could not send request to server %s:%s', $request->getHost(), $request->getPort());
|
1905 |
+
La_Log::error($gpfErrorMessage);
|
1906 |
+
throw new La_Exception($gpfErrorMessage);
|
1907 |
+
}
|
1908 |
+
|
1909 |
+
$result = '';
|
1910 |
+
while (false === @feof($proxySocket)) {
|
1911 |
+
try {
|
1912 |
+
if(false === ($data = @fread($proxySocket, 8192))) {
|
1913 |
+
La_Log::error($this->_sys('Could not read from proxy socket'));
|
1914 |
+
throw new La_Exception("could not read from proxy socket");
|
1915 |
+
}
|
1916 |
+
$result .= $data;
|
1917 |
+
} catch (Exception $e) {
|
1918 |
+
La_Log::error($this->_sys('Proxy failed: %s', $e->getMessage()));
|
1919 |
+
@fclose($proxySocket);
|
1920 |
+
throw new La_Exception($this->_('Proxy failed: %s', $e->getMessage()));
|
1921 |
+
}
|
1922 |
+
}
|
1923 |
+
@fclose($proxySocket);
|
1924 |
+
|
1925 |
+
$response = new La_Net_Http_Response();
|
1926 |
+
$response->setResponseText($result);
|
1927 |
+
|
1928 |
+
return $response;
|
1929 |
+
}
|
1930 |
+
|
1931 |
+
|
1932 |
+
/**
|
1933 |
+
* @param La_Net_Http_Request $request
|
1934 |
+
* @return La_Net_Http_Response
|
1935 |
+
* */
|
1936 |
+
private function executeWithCurl(La_Net_Http_Request $request) {
|
1937 |
+
$session = curl_init($request->getUrl());
|
1938 |
+
|
1939 |
+
if ($request->getMethod() == 'POST') {
|
1940 |
+
@curl_setopt ($session, CURLOPT_POST, true);
|
1941 |
+
@curl_setopt ($session, CURLOPT_POSTFIELDS, $request->getBody());
|
1942 |
+
}
|
1943 |
+
|
1944 |
+
$cookies = $request->getCookies();
|
1945 |
+
if($cookies) {
|
1946 |
+
@curl_setopt($session, CURLOPT_COOKIE, $cookies);
|
1947 |
+
}
|
1948 |
+
|
1949 |
+
@curl_setopt($session, CURLOPT_HEADER, true);
|
1950 |
+
@curl_setopt($session, CURLOPT_CONNECTTIMEOUT, self::CONNECTION_TIMEOUT);
|
1951 |
+
@curl_setopt($session, CURLOPT_HTTPHEADER, $request->getHeaders());
|
1952 |
+
@curl_setopt($session, CURLOPT_FOLLOWLOCATION, true);
|
1953 |
+
@curl_setopt($session, CURLOPT_RETURNTRANSFER, true);
|
1954 |
+
if ($request->getHttpPassword() != '' && $request->getHttpUser() != '') {
|
1955 |
+
@curl_setopt($session, CURLOPT_USERPWD, $request->getHttpUser() . ":" . $request->getHttpPassword());
|
1956 |
+
@curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
|
1957 |
+
}
|
1958 |
+
@curl_setopt ($session, CURLOPT_SSL_VERIFYHOST, 0);
|
1959 |
+
@curl_setopt ($session, CURLOPT_SSL_VERIFYPEER, 0);
|
1960 |
+
|
1961 |
+
$this->setupCurlProxyServer($session, $request);
|
1962 |
+
|
1963 |
+
// Make the call
|
1964 |
+
$result = curl_exec($session);
|
1965 |
+
$error = curl_error($session);
|
1966 |
+
|
1967 |
+
curl_close($session);
|
1968 |
+
|
1969 |
+
if (strlen($error)) {
|
1970 |
+
throw new La_Exception("Curl error: " . $error);
|
1971 |
+
}
|
1972 |
+
|
1973 |
+
$response = new La_Net_Http_Response();
|
1974 |
+
$response->setResponseText($result);
|
1975 |
+
|
1976 |
+
return $response;
|
1977 |
+
}
|
1978 |
+
|
1979 |
+
protected function setProxyServer(La_Net_Http_Request $request) {
|
1980 |
+
$request->setProxyServer('', '', '', '');
|
1981 |
+
}
|
1982 |
+
|
1983 |
+
private function setupCurlProxyServer($curlSession, La_Net_Http_Request $request) {
|
1984 |
+
if (strlen($request->getProxyServer()) && strlen($request->getProxyPort())) {
|
1985 |
+
@curl_setopt($curlSession, CURLOPT_PROXY, $request->getProxyServer() . ':' . $request->getProxyPort());
|
1986 |
+
if (strlen($request->getProxyUser())) {
|
1987 |
+
@curl_setopt($curlSession, CURLOPT_PROXYUSERPWD, $request->getProxyUser() . ':' . $request->getProxyPassword());
|
1988 |
+
}
|
1989 |
+
}
|
1990 |
+
}
|
1991 |
+
}
|
1992 |
+
|
1993 |
+
} //end La_Net_Http_ClientBase
|
1994 |
+
|
1995 |
+
if (!class_exists('La_Net_Http_Response', false)) {
|
1996 |
+
class La_Net_Http_Response extends La_Object {
|
1997 |
+
|
1998 |
+
private $responseText = '';
|
1999 |
+
private $header = '';
|
2000 |
+
private $body = '';
|
2001 |
+
|
2002 |
+
public function setResponseText($responseText) {
|
2003 |
+
$this->responseText = $responseText;
|
2004 |
+
$this->parse();
|
2005 |
+
}
|
2006 |
+
|
2007 |
+
public function getHeadersText() {
|
2008 |
+
return $this->header;
|
2009 |
+
}
|
2010 |
+
|
2011 |
+
private function getHeaderPosition($pos) {
|
2012 |
+
return strpos($this->responseText, "\r\n\r\nHTTP", $pos);
|
2013 |
+
}
|
2014 |
+
|
2015 |
+
public function getBody() {
|
2016 |
+
return $this->body;
|
2017 |
+
}
|
2018 |
+
|
2019 |
+
private function parse() {
|
2020 |
+
$offset = 0;
|
2021 |
+
while ($this->getHeaderPosition($offset)) {
|
2022 |
+
$offset = $this->getHeaderPosition($offset) + 4;
|
2023 |
+
}
|
2024 |
+
if (($pos = strpos($this->responseText, "\r\n\r\n", $offset)) > 0) {
|
2025 |
+
$this->body = substr($this->responseText, $pos + 4);
|
2026 |
+
$this->header = substr($this->responseText, $offset, $pos - $offset);
|
2027 |
+
return;
|
2028 |
+
}
|
2029 |
+
$this->body = '';
|
2030 |
+
$this->header = '';
|
2031 |
+
}
|
2032 |
+
}
|
2033 |
+
|
2034 |
+
} //end La_Net_Http_Response
|
2035 |
+
|
2036 |
+
if (!class_exists('La_Rpc_Form', false)) {
|
2037 |
+
class La_Rpc_Form extends La_Object implements La_Rpc_Serializable, IteratorAggregate {
|
2038 |
+
const FIELD_NAME = "name";
|
2039 |
+
const FIELD_VALUE = "value";
|
2040 |
+
const FIELD_ERROR = "error";
|
2041 |
+
const FIELD_VALUES = "values";
|
2042 |
+
|
2043 |
+
private $isError = false;
|
2044 |
+
private $errorMessage = "";
|
2045 |
+
private $infoMessage = "";
|
2046 |
+
private $status;
|
2047 |
+
/**
|
2048 |
+
* @var La_Data_IndexedRecordSet
|
2049 |
+
*/
|
2050 |
+
private $fields;
|
2051 |
+
/**
|
2052 |
+
* @var La_Rpc_Form_Validator_FormValidatorCollection
|
2053 |
+
*/
|
2054 |
+
private $validators;
|
2055 |
+
|
2056 |
+
public function __construct(La_Rpc_Params $params = null) {
|
2057 |
+
$this->fields = new La_Data_IndexedRecordSet(self::FIELD_NAME);
|
2058 |
+
|
2059 |
+
$header = new La_Data_RecordHeader();
|
2060 |
+
$header->add(self::FIELD_NAME);
|
2061 |
+
$header->add(self::FIELD_VALUE);
|
2062 |
+
$header->add(self::FIELD_VALUES);
|
2063 |
+
$header->add(self::FIELD_ERROR);
|
2064 |
+
$this->fields->setHeader($header);
|
2065 |
+
|
2066 |
+
$this->validator = new La_Rpc_Form_Validator_FormValidatorCollection($this);
|
2067 |
+
|
2068 |
+
if($params) {
|
2069 |
+
$this->loadFieldsFromArray($params->get("fields"));
|
2070 |
+
}
|
2071 |
+
}
|
2072 |
+
|
2073 |
+
/**
|
2074 |
+
* @param $validator
|
2075 |
+
* @param $fieldName
|
2076 |
+
* @param $fieldLabel
|
2077 |
+
*/
|
2078 |
+
public function addValidator(La_Rpc_Form_Validator_Validator $validator, $fieldName, $fieldLabel = null) {
|
2079 |
+
$this->validator->addValidator($validator, $fieldName, $fieldLabel);
|
2080 |
+
}
|
2081 |
+
|
2082 |
+
/**
|
2083 |
+
* @return boolean
|
2084 |
+
*/
|
2085 |
+
public function validate() {
|
2086 |
+
return $this->validator->validate();
|
2087 |
+
}
|
2088 |
+
|
2089 |
+
public function loadFieldsFromArray($fields) {
|
2090 |
+
for ($i = 1; $i < count($fields); $i++) {
|
2091 |
+
$field = $fields[$i];
|
2092 |
+
$this->fields->add($field);
|
2093 |
+
}
|
2094 |
+
}
|
2095 |
+
|
2096 |
+
/**
|
2097 |
+
*
|
2098 |
+
* @return ArrayIterator
|
2099 |
+
*/
|
2100 |
+
public function getIterator() {
|
2101 |
+
return $this->fields->getIterator();
|
2102 |
+
}
|
2103 |
+
|
2104 |
+
public function addField($name, $value) {
|
2105 |
+
$record = $this->fields->createRecord($name);
|
2106 |
+
$record->set(self::FIELD_VALUE, $value);
|
2107 |
+
}
|
2108 |
+
|
2109 |
+
public function setField($name, $value, $values = null, $error = "") {
|
2110 |
+
$record = $this->fields->createRecord($name);
|
2111 |
+
$record->set(self::FIELD_VALUE, $value);
|
2112 |
+
$record->set(self::FIELD_VALUES, $values);
|
2113 |
+
$record->set(self::FIELD_ERROR, $error);
|
2114 |
+
}
|
2115 |
+
|
2116 |
+
public function setFieldError($name, $error) {
|
2117 |
+
$this->isError = true;
|
2118 |
+
$record = $this->fields->getRecord($name);
|
2119 |
+
$record->set(self::FIELD_ERROR, $error);
|
2120 |
+
}
|
2121 |
+
|
2122 |
+
public function getFieldValue($name) {
|
2123 |
+
$record = $this->fields->getRecord($name);
|
2124 |
+
return $record->get(self::FIELD_VALUE);
|
2125 |
+
}
|
2126 |
+
|
2127 |
+
public function getFieldError($name) {
|
2128 |
+
$record = $this->fields->getRecord($name);
|
2129 |
+
return $record->get(self::FIELD_ERROR);
|
2130 |
+
}
|
2131 |
+
|
2132 |
+
public function existsField($name) {
|
2133 |
+
return $this->fields->existsRecord($name);
|
2134 |
+
}
|
2135 |
+
|
2136 |
+
public function load(La_Data_Row $row) {
|
2137 |
+
foreach($row as $columnName => $columnValue) {
|
2138 |
+
$this->setField($columnName, $row->get($columnName));
|
2139 |
+
}
|
2140 |
+
}
|
2141 |
+
|
2142 |
+
/**
|
2143 |
+
* @return La_Data_IndexedRecordSet
|
2144 |
+
*/
|
2145 |
+
public function getFields() {
|
2146 |
+
return $this->fields;
|
2147 |
+
}
|
2148 |
+
|
2149 |
+
public function fill(La_Data_Row $row) {
|
2150 |
+
foreach ($this->fields as $field) {
|
2151 |
+
try {
|
2152 |
+
$row->set($field->get(self::FIELD_NAME), $field->get(self::FIELD_VALUE));
|
2153 |
+
} catch (Exception $e) {
|
2154 |
+
}
|
2155 |
+
}
|
2156 |
+
}
|
2157 |
+
|
2158 |
+
public function toObject() {
|
2159 |
+
$response = new stdClass();
|
2160 |
+
$response->F = $this->fields->toObject();
|
2161 |
+
if ($this->isSuccessful()) {
|
2162 |
+
$response->S = Gpf::YES;
|
2163 |
+
$response->M = $this->infoMessage;
|
2164 |
+
} else {
|
2165 |
+
$response->S = Gpf::NO;
|
2166 |
+
$response->M = $this->errorMessage;
|
2167 |
+
}
|
2168 |
+
if (!strlen($response->M)) {
|
2169 |
+
unset($response->M);
|
2170 |
+
}
|
2171 |
+
return $response;
|
2172 |
+
}
|
2173 |
+
|
2174 |
+
public function loadFromObject(stdClass $object) {
|
2175 |
+
if ($object->success == Gpf::YES) {
|
2176 |
+
$this->setInfoMessage($object->message);
|
2177 |
+
} else {
|
2178 |
+
$this->setErrorMessage($object->message);
|
2179 |
+
}
|
2180 |
+
|
2181 |
+
$this->fields = new La_Data_IndexedRecordSet(self::FIELD_NAME);
|
2182 |
+
$this->fields->loadFromObject($object->fields);
|
2183 |
+
}
|
2184 |
+
|
2185 |
+
public function toText() {
|
2186 |
+
return var_dump($this->toObject());
|
2187 |
+
}
|
2188 |
+
|
2189 |
+
public function setErrorMessage($message) {
|
2190 |
+
$this->isError = true;
|
2191 |
+
$this->errorMessage = $message;
|
2192 |
+
}
|
2193 |
+
|
2194 |
+
public function getErrorMessage() {
|
2195 |
+
if ($this->isError) {
|
2196 |
+
return $this->errorMessage;
|
2197 |
+
}
|
2198 |
+
return "";
|
2199 |
+
}
|
2200 |
+
|
2201 |
+
public function setInfoMessage($message) {
|
2202 |
+
$this->infoMessage = $message;
|
2203 |
+
}
|
2204 |
+
|
2205 |
+
public function setSuccessful() {
|
2206 |
+
$this->isError = false;
|
2207 |
+
}
|
2208 |
+
|
2209 |
+
public function getInfoMessage() {
|
2210 |
+
if ($this->isError) {
|
2211 |
+
return "";
|
2212 |
+
}
|
2213 |
+
return $this->infoMessage;
|
2214 |
+
}
|
2215 |
+
|
2216 |
+
|
2217 |
+
/**
|
2218 |
+
* @return boolean
|
2219 |
+
*/
|
2220 |
+
public function isSuccessful() {
|
2221 |
+
return !$this->isError;
|
2222 |
+
}
|
2223 |
+
|
2224 |
+
/**
|
2225 |
+
* @return boolean
|
2226 |
+
*/
|
2227 |
+
public function isError() {
|
2228 |
+
return $this->isError;
|
2229 |
+
}
|
2230 |
+
|
2231 |
+
public function getDefaultErrorMessage() {
|
2232 |
+
return $this->_('There were errors, please check highlighted fields');
|
2233 |
+
}
|
2234 |
+
}
|
2235 |
+
|
2236 |
+
|
2237 |
+
} //end La_Rpc_Form
|
2238 |
+
|
2239 |
+
if (!class_exists('La_Rpc_Form_Validator_FormValidatorCollection', false)) {
|
2240 |
+
class La_Rpc_Form_Validator_FormValidatorCollection extends La_Object {
|
2241 |
+
|
2242 |
+
/**
|
2243 |
+
* @var array<La_Rpc_Form_Validator_FieldValidator>
|
2244 |
+
*/
|
2245 |
+
private $validators;
|
2246 |
+
/**
|
2247 |
+
* @var La_Rpc_Form
|
2248 |
+
*/
|
2249 |
+
private $form;
|
2250 |
+
|
2251 |
+
public function __construct(La_Rpc_Form $form) {
|
2252 |
+
$this->form = $form;
|
2253 |
+
$this->validators = array();
|
2254 |
+
}
|
2255 |
+
|
2256 |
+
/**
|
2257 |
+
* @param $fieldName
|
2258 |
+
* @param $validator
|
2259 |
+
*/
|
2260 |
+
public function addValidator(La_Rpc_Form_Validator_Validator $validator, $fieldName, $fieldLabel = null) {
|
2261 |
+
if (!array_key_exists($fieldName, $this->validators)) {
|
2262 |
+
$this->validators[$fieldName] = new La_Rpc_Form_Validator_FieldValidator(($fieldLabel === null ? $fieldName : $fieldLabel));
|
2263 |
+
}
|
2264 |
+
$this->validators[$fieldName]->addValidator($validator);
|
2265 |
+
}
|
2266 |
+
|
2267 |
+
/**
|
2268 |
+
* @return boolean
|
2269 |
+
*/
|
2270 |
+
public function validate() {
|
2271 |
+
$errorMsg = false;
|
2272 |
+
foreach ($this->validators as $fieldName => $fieldValidator) {
|
2273 |
+
if (!$fieldValidator->validate($this->form->getFieldValue($fieldName))) {
|
2274 |
+
$errorMsg = true;
|
2275 |
+
$this->form->setFieldError($fieldName, $fieldValidator->getMessage());
|
2276 |
+
}
|
2277 |
+
}
|
2278 |
+
if ($errorMsg) {
|
2279 |
+
$this->form->setErrorMessage($this->form->getDefaultErrorMessage());
|
2280 |
+
}
|
2281 |
+
return !$errorMsg;
|
2282 |
+
}
|
2283 |
+
}
|
2284 |
+
|
2285 |
+
} //end La_Rpc_Form_Validator_FormValidatorCollection
|
2286 |
+
|
2287 |
+
if (!class_exists('La_Rpc_FormRequest', false)) {
|
2288 |
+
class La_Rpc_FormRequest extends La_Rpc_Request {
|
2289 |
+
/**
|
2290 |
+
* @var La_Rpc_Form
|
2291 |
+
*/
|
2292 |
+
private $fields;
|
2293 |
+
|
2294 |
+
public function __construct($className, $methodName, La_Api_Session $apiSessionObject = null) {
|
2295 |
+
parent::__construct($className, $methodName, $apiSessionObject);
|
2296 |
+
$this->fields = new La_Rpc_Form();
|
2297 |
+
}
|
2298 |
+
|
2299 |
+
public function send() {
|
2300 |
+
$this->addParam('fields', $this->fields->getFields());
|
2301 |
+
parent::send();
|
2302 |
+
}
|
2303 |
+
|
2304 |
+
/**
|
2305 |
+
* @return La_Rpc_Form
|
2306 |
+
*/
|
2307 |
+
public function getForm() {
|
2308 |
+
$response = new La_Rpc_Form();
|
2309 |
+
$response->loadFromObject($this->getStdResponse());
|
2310 |
+
return $response;
|
2311 |
+
}
|
2312 |
+
|
2313 |
+
public function setField($name, $value) {
|
2314 |
+
if (is_scalar($value) || $value instanceof La_Rpc_Serializable) {
|
2315 |
+
$this->fields->setField($name, $value);
|
2316 |
+
} else {
|
2317 |
+
throw new La_Exception("Not supported value");
|
2318 |
+
}
|
2319 |
+
}
|
2320 |
+
|
2321 |
+
public function setFields(La_Data_IndexedRecordSet $fields) {
|
2322 |
+
$this->fields->loadFieldsFromArray($fields->toArray());
|
2323 |
+
}
|
2324 |
+
}
|
2325 |
+
|
2326 |
+
} //end La_Rpc_FormRequest
|
2327 |
+
|
2328 |
+
if (!class_exists('La_Rpc_RecordSetRequest', false)) {
|
2329 |
+
class La_Rpc_RecordSetRequest extends La_Rpc_Request {
|
2330 |
+
|
2331 |
+
/**
|
2332 |
+
* @return La_Data_IndexedRecordSet
|
2333 |
+
*/
|
2334 |
+
public function getIndexedRecordSet($key) {
|
2335 |
+
$response = new La_Data_IndexedRecordSet($key);
|
2336 |
+
$response->loadFromObject($this->getStdResponse());
|
2337 |
+
return $response;
|
2338 |
+
}
|
2339 |
+
|
2340 |
+
|
2341 |
+
/**
|
2342 |
+
* @return La_Data_RecordSet
|
2343 |
+
*/
|
2344 |
+
public function getRecordSet() {
|
2345 |
+
$response = new La_Data_RecordSet();
|
2346 |
+
$response->loadFromObject($this->getStdResponse());
|
2347 |
+
return $response;
|
2348 |
+
}
|
2349 |
+
}
|
2350 |
+
|
2351 |
+
|
2352 |
+
} //end La_Rpc_RecordSetRequest
|
2353 |
+
|
2354 |
+
if (!class_exists('La_Rpc_DataRequest', false)) {
|
2355 |
+
class La_Rpc_DataRequest extends La_Rpc_Request {
|
2356 |
+
/**
|
2357 |
+
* @var La_Rpc_Data
|
2358 |
+
*/
|
2359 |
+
private $data;
|
2360 |
+
|
2361 |
+
private $filters = array();
|
2362 |
+
|
2363 |
+
public function __construct($className, $methodName, La_Api_Session $apiSessionObject = null) {
|
2364 |
+
parent::__construct($className, $methodName, $apiSessionObject);
|
2365 |
+
$this->data = new La_Rpc_Data();
|
2366 |
+
}
|
2367 |
+
|
2368 |
+
/**
|
2369 |
+
* @return La_Rpc_Data
|
2370 |
+
*/
|
2371 |
+
public function getData() {
|
2372 |
+
$response = new La_Rpc_Data();
|
2373 |
+
$response->loadFromObject($this->getStdResponse());
|
2374 |
+
return $response;
|
2375 |
+
}
|
2376 |
+
|
2377 |
+
public function setField($name, $value) {
|
2378 |
+
if (is_scalar($value) || $value instanceof La_Rpc_Serializable) {
|
2379 |
+
$this->data->setParam($name, $value);
|
2380 |
+
} else {
|
2381 |
+
throw new La_Exception("Not supported value");
|
2382 |
+
}
|
2383 |
+
}
|
2384 |
+
|
2385 |
+
/**
|
2386 |
+
* adds filter to grid
|
2387 |
+
*
|
2388 |
+
* @param unknown_type $code
|
2389 |
+
* @param unknown_type $operator
|
2390 |
+
* @param unknown_type $value
|
2391 |
+
*/
|
2392 |
+
public function addFilter($code, $operator, $value) {
|
2393 |
+
$this->filters[] = new La_Data_Filter($code, $operator, $value);
|
2394 |
+
}
|
2395 |
+
|
2396 |
+
public function send() {
|
2397 |
+
$this->addParam('data', $this->data->getParams());
|
2398 |
+
|
2399 |
+
if(count($this->filters) > 0) {
|
2400 |
+
$this->addParam("filters", $this->addFiltersParameter());
|
2401 |
+
}
|
2402 |
+
parent::send();
|
2403 |
+
}
|
2404 |
+
|
2405 |
+
private function addFiltersParameter() {
|
2406 |
+
$filters = new La_Rpc_Array();
|
2407 |
+
|
2408 |
+
foreach($this->filters as $filter) {
|
2409 |
+
$filters->add($filter);
|
2410 |
+
}
|
2411 |
+
|
2412 |
+
return $filters;
|
2413 |
+
}
|
2414 |
+
}
|
2415 |
+
|
2416 |
+
} //end La_Rpc_DataRequest
|
2417 |
+
|
2418 |
+
if (!class_exists('La_Rpc_Data', false)) {
|
2419 |
+
class La_Rpc_Data extends La_Object implements La_Rpc_Serializable {
|
2420 |
+
const NAME = "name";
|
2421 |
+
const VALUE = "value";
|
2422 |
+
const DATA = "data";
|
2423 |
+
const ID = "id";
|
2424 |
+
|
2425 |
+
/**
|
2426 |
+
* @var La_Data_IndexedRecordSet
|
2427 |
+
*/
|
2428 |
+
private $params;
|
2429 |
+
|
2430 |
+
/**
|
2431 |
+
* @var string
|
2432 |
+
*/
|
2433 |
+
private $id;
|
2434 |
+
|
2435 |
+
|
2436 |
+
/**
|
2437 |
+
* @var La_Rpc_FilterCollection
|
2438 |
+
*/
|
2439 |
+
private $filters;
|
2440 |
+
|
2441 |
+
/**
|
2442 |
+
* @var La_Data_IndexedRecordSet
|
2443 |
+
*/
|
2444 |
+
private $response;
|
2445 |
+
|
2446 |
+
/**
|
2447 |
+
*
|
2448 |
+
* @return La_Data_IndexedRecordSet
|
2449 |
+
*/
|
2450 |
+
public function getParams() {
|
2451 |
+
return $this->params;
|
2452 |
+
}
|
2453 |
+
|
2454 |
+
/**
|
2455 |
+
* Create instance to handle DataRequest
|
2456 |
+
*
|
2457 |
+
* @param La_Rpc_Params $params
|
2458 |
+
*/
|
2459 |
+
public function __construct(La_Rpc_Params $params = null) {
|
2460 |
+
if($params === null) {
|
2461 |
+
$params = new La_Rpc_Params();
|
2462 |
+
}
|
2463 |
+
|
2464 |
+
$this->filters = new La_Rpc_FilterCollection($params);
|
2465 |
+
|
2466 |
+
$this->params = new La_Data_IndexedRecordSet(self::NAME);
|
2467 |
+
$this->params->setHeader(array(self::NAME, self::VALUE));
|
2468 |
+
|
2469 |
+
if ($params->exists(self::DATA) !== null) {
|
2470 |
+
$this->loadParamsFromArray($params->get(self::DATA));
|
2471 |
+
}
|
2472 |
+
|
2473 |
+
$this->id = $params->get(self::ID);
|
2474 |
+
|
2475 |
+
$this->response = new La_Data_IndexedRecordSet(self::NAME);
|
2476 |
+
$this->response->setHeader(array(self::NAME, self::VALUE));
|
2477 |
+
}
|
2478 |
+
|
2479 |
+
public function addValues(array $values) {
|
2480 |
+
foreach ($values as $key => $value) {
|
2481 |
+
$this->setValue($key, $value);
|
2482 |
+
}
|
2483 |
+
}
|
2484 |
+
|
2485 |
+
/**
|
2486 |
+
* Return id
|
2487 |
+
*
|
2488 |
+
* @return string
|
2489 |
+
*/
|
2490 |
+
public function getId() {
|
2491 |
+
return $this->id;
|
2492 |
+
}
|
2493 |
+
|
2494 |
+
/**
|
2495 |
+
* Return parameter value
|
2496 |
+
*
|
2497 |
+
* @param String $name
|
2498 |
+
* @return unknown
|
2499 |
+
*/
|
2500 |
+
public function getParam($name) {
|
2501 |
+
try {
|
2502 |
+
return $this->params->getRecord($name)->get(self::VALUE);
|
2503 |
+
} catch (La_Data_RecordSetNoRowException $e) {
|
2504 |
+
return null;
|
2505 |
+
}
|
2506 |
+
}
|
2507 |
+
|
2508 |
+
public function setParam($name, $value) {
|
2509 |
+
self::setValueToRecordset($this->params, $name, $value);
|
2510 |
+
}
|
2511 |
+
|
2512 |
+
public function loadFromObject(array $object) {
|
2513 |
+
$this->response->loadFromObject($object);
|
2514 |
+
$this->params->loadFromObject($object);
|
2515 |
+
}
|
2516 |
+
|
2517 |
+
/**
|
2518 |
+
* @return La_Rpc_FilterCollection
|
2519 |
+
*/
|
2520 |
+
public function getFilters() {
|
2521 |
+
return $this->filters;
|
2522 |
+
}
|
2523 |
+
|
2524 |
+
private static function setValueToRecordset(La_Data_IndexedRecordSet $recordset, $name, $value) {
|
2525 |
+
try {
|
2526 |
+
$record = $recordset->getRecord($name);
|
2527 |
+
} catch (La_Data_RecordSetNoRowException $e) {
|
2528 |
+
$record = $recordset->createRecord();
|
2529 |
+
$record->set(self::NAME, $name);
|
2530 |
+
$recordset->addRecord($record);
|
2531 |
+
}
|
2532 |
+
$record->set(self::VALUE, $value);
|
2533 |
+
}
|
2534 |
+
|
2535 |
+
public function setValue($name, $value) {
|
2536 |
+
self::setValueToRecordset($this->response, $name, $value);
|
2537 |
+
}
|
2538 |
+
|
2539 |
+
public function getSize() {
|
2540 |
+
return $this->response->getSize();
|
2541 |
+
}
|
2542 |
+
|
2543 |
+
public function getValue($name) {
|
2544 |
+
return $this->response->getRecord($name)->get(self::VALUE);
|
2545 |
+
}
|
2546 |
+
|
2547 |
+
public function toObject() {
|
2548 |
+
return $this->response->toObject();
|
2549 |
+
}
|
2550 |
+
|
2551 |
+
public function toText() {
|
2552 |
+
return $this->response->toText();
|
2553 |
+
}
|
2554 |
+
|
2555 |
+
private function loadParamsFromArray($data) {
|
2556 |
+
for ($i = 1; $i < count($data); $i++) {
|
2557 |
+
$this->params->add($data[$i]);
|
2558 |
+
}
|
2559 |
+
}
|
2560 |
+
}
|
2561 |
+
|
2562 |
+
} //end La_Rpc_Data
|
2563 |
+
|
2564 |
+
if (!class_exists('La_Rpc_FilterCollection', false)) {
|
2565 |
+
class La_Rpc_FilterCollection extends La_Object implements IteratorAggregate {
|
2566 |
+
|
2567 |
+
/**
|
2568 |
+
* @var array of La_Filter
|
2569 |
+
*/
|
2570 |
+
private $filters;
|
2571 |
+
|
2572 |
+
public function __construct(La_Rpc_Params $params = null) {
|
2573 |
+
$this->filters = array();
|
2574 |
+
if ($params != null) {
|
2575 |
+
$this->init($params);
|
2576 |
+
}
|
2577 |
+
}
|
2578 |
+
|
2579 |
+
/**
|
2580 |
+
* @return La_Rpc_FilterCollection
|
2581 |
+
*/
|
2582 |
+
public static function fromJson($json){
|
2583 |
+
$instance = new La_Rpc_FilterCollection();
|
2584 |
+
$filters = La_Rpc_Json::decodeStatic($json);
|
2585 |
+
foreach ($filters as $filter){
|
2586 |
+
$instance->add($filter);
|
2587 |
+
}
|
2588 |
+
return $instance;
|
2589 |
+
}
|
2590 |
+
|
2591 |
+
public function add(array $filterArray) {
|
2592 |
+
$this->filters[] = new La_Filter($filterArray);
|
2593 |
+
}
|
2594 |
+
|
2595 |
+
private function init(La_Rpc_Params $params) {
|
2596 |
+
$filtersArray = $params->get("filters");
|
2597 |
+
if (!is_array($filtersArray)) {
|
2598 |
+
return;
|
2599 |
+
}
|
2600 |
+
foreach ($filtersArray as $filterArray) {
|
2601 |
+
$this->add($filterArray);
|
2602 |
+
}
|
2603 |
+
}
|
2604 |
+
|
2605 |
+
/**
|
2606 |
+
*
|
2607 |
+
* @return ArrayIterator
|
2608 |
+
*/
|
2609 |
+
public function getIterator() {
|
2610 |
+
return new ArrayIterator($this->filters);
|
2611 |
+
}
|
2612 |
+
|
2613 |
+
public function addTo(La_SqlBuilder_WhereClause $whereClause) {
|
2614 |
+
foreach ($this->filters as $filter) {
|
2615 |
+
$filter->addTo($whereClause);
|
2616 |
+
}
|
2617 |
+
}
|
2618 |
+
|
2619 |
+
public function addSelectedFilterTo(La_SqlBuilder_WhereClause $whereClause, $filterCode, $columnCode = null) {
|
2620 |
+
if ($columnCode == null) {
|
2621 |
+
$columnCode = $filterCode;
|
2622 |
+
}
|
2623 |
+
foreach ($this->filters as $filter) {
|
2624 |
+
if ($filter->getCode() == $filterCode) {
|
2625 |
+
$oldCode = $filter->getCode();
|
2626 |
+
$filter->setCode($columnCode);
|
2627 |
+
$filter->addTo($whereClause);
|
2628 |
+
$filter->setCode($oldCode);
|
2629 |
+
}
|
2630 |
+
}
|
2631 |
+
}
|
2632 |
+
|
2633 |
+
/**
|
2634 |
+
* Returns first filter with specified code.
|
2635 |
+
* If filter with specified code does not exists null is returned.
|
2636 |
+
*
|
2637 |
+
* @param string $code
|
2638 |
+
* @return array<La_Filter>
|
2639 |
+
*/
|
2640 |
+
public function getFilter($code) {
|
2641 |
+
$filters = array();
|
2642 |
+
foreach ($this->filters as $filter) {
|
2643 |
+
if ($filter->getCode() == $code) {
|
2644 |
+
$filters[] = $filter;
|
2645 |
+
}
|
2646 |
+
}
|
2647 |
+
return $filters;
|
2648 |
+
}
|
2649 |
+
|
2650 |
+
public function isFilter($code) {
|
2651 |
+
foreach ($this->filters as $filter) {
|
2652 |
+
if ($filter->getCode() == $code) {
|
2653 |
+
return true;
|
2654 |
+
}
|
2655 |
+
}
|
2656 |
+
return false;
|
2657 |
+
}
|
2658 |
+
|
2659 |
+
public function getFilterValue($code) {
|
2660 |
+
$filters = $this->getFilter($code);
|
2661 |
+
if (count($filters) == 1) {
|
2662 |
+
return $filters[0]->getValue();
|
2663 |
+
}
|
2664 |
+
return "";
|
2665 |
+
}
|
2666 |
+
|
2667 |
+
public function matches(La_Data_Record $row) {
|
2668 |
+
foreach ($this->filters as $filter) {
|
2669 |
+
if (!$filter->matches($row)) {
|
2670 |
+
return false;
|
2671 |
+
}
|
2672 |
+
}
|
2673 |
+
return true;
|
2674 |
+
}
|
2675 |
+
|
2676 |
+
public function getSize() {
|
2677 |
+
return count($this->filters);
|
2678 |
+
}
|
2679 |
+
}
|
2680 |
+
|
2681 |
+
} //end La_Rpc_FilterCollection
|
2682 |
+
|
2683 |
+
if (!class_exists('La_Php', false)) {
|
2684 |
+
class La_Php {
|
2685 |
+
|
2686 |
+
/**
|
2687 |
+
* Check if function is enabled and exists in php
|
2688 |
+
*
|
2689 |
+
* @param $functionName
|
2690 |
+
* @return boolean Returns true if function exists and is enabled
|
2691 |
+
*/
|
2692 |
+
public static function isFunctionEnabled($functionName) {
|
2693 |
+
if (function_exists($functionName) && strstr(ini_get("disable_functions"), $functionName) === false) {
|
2694 |
+
return true;
|
2695 |
+
}
|
2696 |
+
return false;
|
2697 |
+
}
|
2698 |
+
|
2699 |
+
/**
|
2700 |
+
* Check if extension is loaded
|
2701 |
+
*
|
2702 |
+
* @param $extensionName
|
2703 |
+
* @return boolean Returns true if extension is loaded
|
2704 |
+
*/
|
2705 |
+
public static function isExtensionLoaded($extensionName) {
|
2706 |
+
return extension_loaded($extensionName);
|
2707 |
+
}
|
2708 |
+
|
2709 |
+
}
|
2710 |
+
|
2711 |
+
} //end La_Php
|
2712 |
+
|
2713 |
+
if (!class_exists('La_Rpc_ActionRequest', false)) {
|
2714 |
+
class La_Rpc_ActionRequest extends La_Rpc_Request {
|
2715 |
+
|
2716 |
+
/**
|
2717 |
+
* @return La_Rpc_Action
|
2718 |
+
*/
|
2719 |
+
public function getAction() {
|
2720 |
+
$action = new La_Rpc_Action(new La_Rpc_Params());
|
2721 |
+
$action->loadFromObject($this->getStdResponse());
|
2722 |
+
return $action;
|
2723 |
+
}
|
2724 |
+
}
|
2725 |
+
|
2726 |
+
|
2727 |
+
} //end La_Rpc_ActionRequest
|
2728 |
+
|
2729 |
+
if (!class_exists('La_Rpc_Action', false)) {
|
2730 |
+
class La_Rpc_Action extends La_Object implements La_Rpc_Serializable {
|
2731 |
+
private $errorMessage = "";
|
2732 |
+
private $infoMessage = "";
|
2733 |
+
private $successCount = 0;
|
2734 |
+
private $errorCount = 0;
|
2735 |
+
/**
|
2736 |
+
* @var La_Rpc_Params
|
2737 |
+
*/
|
2738 |
+
private $params;
|
2739 |
+
|
2740 |
+
public function __construct(La_Rpc_Params $params, $infoMessage = '', $errorMessage = '') {
|
2741 |
+
$this->params = $params;
|
2742 |
+
$this->infoMessage = $infoMessage;
|
2743 |
+
$this->errorMessage = $errorMessage;
|
2744 |
+
}
|
2745 |
+
|
2746 |
+
/**
|
2747 |
+
* @return Iterator
|
2748 |
+
*/
|
2749 |
+
public function getIds() {
|
2750 |
+
$massHandler = new La_Rpc_MassHandler($this->params);
|
2751 |
+
return $massHandler->getIds();
|
2752 |
+
}
|
2753 |
+
|
2754 |
+
public function getParam($name) {
|
2755 |
+
return $this->params->get($name);
|
2756 |
+
}
|
2757 |
+
|
2758 |
+
public function existsParam($name) {
|
2759 |
+
return $this->params->exists($name);
|
2760 |
+
}
|
2761 |
+
|
2762 |
+
/**
|
2763 |
+
* Parameter OK is mandatory
|
2764 |
+
* Parameter I and E is optional and only if there is value it is sent to client (empty values are not transferred)
|
2765 |
+
*
|
2766 |
+
* (non-PHPdoc)
|
2767 |
+
* @see include/Gpf/Rpc/La_Rpc_Serializable#toObject()
|
2768 |
+
*/
|
2769 |
+
public function toObject() {
|
2770 |
+
$response = new stdClass();
|
2771 |
+
$response->S = Gpf::YES;
|
2772 |
+
|
2773 |
+
if ($this->errorCount > 0) {
|
2774 |
+
$response->S = Gpf::NO;
|
2775 |
+
$response->E = $this->_($this->errorMessage, $this->errorCount);
|
2776 |
+
if (!strlen($response->E)) {
|
2777 |
+
unset($response->E);
|
2778 |
+
}
|
2779 |
+
}
|
2780 |
+
|
2781 |
+
if ($this->successCount > 0) {
|
2782 |
+
$response->I = $this->_($this->infoMessage, $this->successCount);
|
2783 |
+
if (!strlen($response->I)) {
|
2784 |
+
unset($response->I);
|
2785 |
+
}
|
2786 |
+
}
|
2787 |
+
|
2788 |
+
return $response;
|
2789 |
+
}
|
2790 |
+
|
2791 |
+
public function loadFromObject(stdClass $object) {
|
2792 |
+
$this->errorMessage = $object->errorMessage;
|
2793 |
+
$this->infoMessage = $object->infoMessage;
|
2794 |
+
|
2795 |
+
if($object->success == Gpf::NO) {
|
2796 |
+
$this->addError();
|
2797 |
+
}
|
2798 |
+
}
|
2799 |
+
|
2800 |
+
public function isError() {
|
2801 |
+
return $this->errorCount > 0;
|
2802 |
+
}
|
2803 |
+
|
2804 |
+
public function toText() {
|
2805 |
+
if ($this->isError()) {
|
2806 |
+
return $this->_($this->errorMessage, $this->errorCount);
|
2807 |
+
} else {
|
2808 |
+
return $this->_($this->infoMessage, $this->successCount);
|
2809 |
+
}
|
2810 |
+
}
|
2811 |
+
|
2812 |
+
public function setErrorMessage($message) {
|
2813 |
+
$this->errorMessage = $message;
|
2814 |
+
}
|
2815 |
+
|
2816 |
+
public function getErrorMessage() {
|
2817 |
+
return $this->errorMessage;
|
2818 |
+
}
|
2819 |
+
|
2820 |
+
public function setInfoMessage($message) {
|
2821 |
+
$this->infoMessage = $message;
|
2822 |
+
}
|
2823 |
+
|
2824 |
+
public function addOk() {
|
2825 |
+
$this->successCount++;
|
2826 |
+
}
|
2827 |
+
|
2828 |
+
public function addError() {
|
2829 |
+
$this->errorCount++;
|
2830 |
+
}
|
2831 |
+
|
2832 |
+
}
|
2833 |
+
|
2834 |
+
|
2835 |
+
} //end La_Rpc_Action
|
2836 |
+
|
2837 |
+
if (!class_exists('La_Rpc_Map', false)) {
|
2838 |
+
class La_Rpc_Map extends La_Object implements La_Rpc_Serializable {
|
2839 |
+
|
2840 |
+
function __construct(array $array){
|
2841 |
+
$this->array = $array;
|
2842 |
+
}
|
2843 |
+
|
2844 |
+
public function toObject() {
|
2845 |
+
return $this->array;
|
2846 |
+
}
|
2847 |
+
|
2848 |
+
public function toText() {
|
2849 |
+
return var_dump($this->array);
|
2850 |
+
}
|
2851 |
+
}
|
2852 |
+
|
2853 |
+
|
2854 |
+
} //end La_Rpc_Map
|
2855 |
+
|
2856 |
+
if (!class_exists('La_Log', false)) {
|
2857 |
+
class La_Log {
|
2858 |
+
const CRITICAL = 50;
|
2859 |
+
const ERROR = 40;
|
2860 |
+
const WARNING = 30;
|
2861 |
+
const INFO = 20;
|
2862 |
+
const DEBUG = 10;
|
2863 |
+
|
2864 |
+
/**
|
2865 |
+
* @var La_Log_Logger
|
2866 |
+
*/
|
2867 |
+
private static $logger;
|
2868 |
+
|
2869 |
+
/**
|
2870 |
+
* @return La_Log_Logger
|
2871 |
+
*/
|
2872 |
+
private static function getLogger() {
|
2873 |
+
if (self::$logger == null) {
|
2874 |
+
self::$logger = La_Log_Logger::getInstance();
|
2875 |
+
}
|
2876 |
+
return self::$logger;
|
2877 |
+
}
|
2878 |
+
|
2879 |
+
private function __construct() {
|
2880 |
+
}
|
2881 |
+
|
2882 |
+
public static function disableType($type) {
|
2883 |
+
self::getLogger()->disableType($type);
|
2884 |
+
}
|
2885 |
+
|
2886 |
+
public static function enableAllTypes() {
|
2887 |
+
self::getLogger()->enableAllTypes();
|
2888 |
+
}
|
2889 |
+
|
2890 |
+
/**
|
2891 |
+
* logs message
|
2892 |
+
*
|
2893 |
+
* @param string $message
|
2894 |
+
* @param string $logLevel
|
2895 |
+
* @param string $logGroup
|
2896 |
+
*/
|
2897 |
+
public static function log($message, $logLevel, $logGroup = null) {
|
2898 |
+
self::getLogger()->log($message, $logLevel, $logGroup);
|
2899 |
+
}
|
2900 |
+
|
2901 |
+
/**
|
2902 |
+
* logs debug message
|
2903 |
+
*
|
2904 |
+
* @param string $message
|
2905 |
+
* @param string $logGroup
|
2906 |
+
*/
|
2907 |
+
public static function debug($message, $logGroup = null) {
|
2908 |
+
self::getLogger()->debug($message, $logGroup);
|
2909 |
+
}
|
2910 |
+
|
2911 |
+
/**
|
2912 |
+
* logs info message
|
2913 |
+
*
|
2914 |
+
* @param string $message
|
2915 |
+
* @param string $logGroup
|
2916 |
+
*/
|
2917 |
+
public static function info($message, $logGroup = null) {
|
2918 |
+
self::getLogger()->info($message, $logGroup);
|
2919 |
+
}
|
2920 |
+
|
2921 |
+
/**
|
2922 |
+
* logs warning message
|
2923 |
+
*
|
2924 |
+
* @param string $message
|
2925 |
+
* @param string $logGroup
|
2926 |
+
*/
|
2927 |
+
public static function warning($message, $logGroup = null) {
|
2928 |
+
self::getLogger()->warning($message, $logGroup);
|
2929 |
+
}
|
2930 |
+
|
2931 |
+
/**
|
2932 |
+
* logs error message
|
2933 |
+
*
|
2934 |
+
* @param string $message
|
2935 |
+
* @param string $logGroup
|
2936 |
+
*/
|
2937 |
+
public static function error($message, $logGroup = null) {
|
2938 |
+
self::getLogger()->error($message, $logGroup);
|
2939 |
+
}
|
2940 |
+
|
2941 |
+
/**
|
2942 |
+
* logs critical error message
|
2943 |
+
*
|
2944 |
+
* @param string $message
|
2945 |
+
* @param string $logGroup
|
2946 |
+
*/
|
2947 |
+
public static function critical($message, $logGroup = null) {
|
2948 |
+
self::getLogger()->critical($message, $logGroup);
|
2949 |
+
}
|
2950 |
+
|
2951 |
+
/**
|
2952 |
+
* Attach new log system
|
2953 |
+
*
|
2954 |
+
* @param string $type
|
2955 |
+
* La_Log_LoggerDisplay::TYPE
|
2956 |
+
* La_Log_LoggerFile::TYPE
|
2957 |
+
* La_Log_LoggerDatabase::TYPE
|
2958 |
+
* @param string $logLevel
|
2959 |
+
* La_Log::CRITICAL
|
2960 |
+
* La_Log::ERROR
|
2961 |
+
* La_Log::WARNING
|
2962 |
+
* La_Log::INFO
|
2963 |
+
* La_Log::DEBUG
|
2964 |
+
* @return La_Log_LoggerBase
|
2965 |
+
*/
|
2966 |
+
public static function addLogger($type, $logLevel) {
|
2967 |
+
if($type instanceof La_Log_LoggerBase) {
|
2968 |
+
return self::getLogger()->addLogger($type, $logLevel);
|
2969 |
+
}
|
2970 |
+
return self::getLogger()->add($type, $logLevel);
|
2971 |
+
}
|
2972 |
+
|
2973 |
+
public static function removeAll() {
|
2974 |
+
self::getLogger()->removeAll();
|
2975 |
+
}
|
2976 |
+
}
|
2977 |
+
|
2978 |
+
} //end La_Log
|
2979 |
+
|
2980 |
+
if (!class_exists('La_Log_Logger', false)) {
|
2981 |
+
class La_Log_Logger extends La_Object {
|
2982 |
+
/**
|
2983 |
+
* @var array
|
2984 |
+
*/
|
2985 |
+
static private $instances = array();
|
2986 |
+
/**
|
2987 |
+
* @var array
|
2988 |
+
*/
|
2989 |
+
private $loggers = array();
|
2990 |
+
|
2991 |
+
/**
|
2992 |
+
* array of custom parameters
|
2993 |
+
*/
|
2994 |
+
private $customParameters = array();
|
2995 |
+
|
2996 |
+
private $disabledTypes = array();
|
2997 |
+
|
2998 |
+
private $group = null;
|
2999 |
+
private $type = null;
|
3000 |
+
private $logToDisplay = false;
|
3001 |
+
|
3002 |
+
/**
|
3003 |
+
* returns instance of logger class.
|
3004 |
+
* You can add instance name, if you want to have multiple independent instances of logger
|
3005 |
+
*
|
3006 |
+
* @param string $instanceName
|
3007 |
+
* @return La_Log_Logger
|
3008 |
+
*/
|
3009 |
+
public static function getInstance($instanceName = '_') {
|
3010 |
+
if($instanceName == '') {
|
3011 |
+
$instanceName = '_';
|
3012 |
+
}
|
3013 |
+
|
3014 |
+
if (!array_key_exists($instanceName, self::$instances)) {
|
3015 |
+
self::$instances[$instanceName] = new La_Log_Logger();
|
3016 |
+
}
|
3017 |
+
$instance = self::$instances[$instanceName];
|
3018 |
+
return $instance;
|
3019 |
+
}
|
3020 |
+
|
3021 |
+
public static function isLoggerInsert($sqlString) {
|
3022 |
+
return strpos($sqlString, 'INSERT INTO ' . La_Db_Table_Logs::getName()) !== false;
|
3023 |
+
}
|
3024 |
+
|
3025 |
+
/**
|
3026 |
+
* attachs new log system
|
3027 |
+
*
|
3028 |
+
* @param unknown_type $system
|
3029 |
+
* @return La_Log_LoggerBase
|
3030 |
+
*/
|
3031 |
+
public function add($type, $logLevel) {
|
3032 |
+
if($type == La_Log_LoggerDisplay::TYPE) {
|
3033 |
+
$this->logToDisplay = true;
|
3034 |
+
}
|
3035 |
+
return $this->addLogger($this->create($type), $logLevel);
|
3036 |
+
}
|
3037 |
+
|
3038 |
+
/**
|
3039 |
+
* Checks if logger with te specified type was already initialized
|
3040 |
+
*
|
3041 |
+
* @param unknown_type $type
|
3042 |
+
* @return unknown
|
3043 |
+
*/
|
3044 |
+
public function checkLoggerTypeExists($type) {
|
3045 |
+
if(array_key_exists($type, $this->loggers)) {
|
3046 |
+
return true;
|
3047 |
+
}
|
3048 |
+
|
3049 |
+
return false;
|
3050 |
+
}
|
3051 |
+
|
3052 |
+
/**
|
3053 |
+
* returns true if debugging writes log to display
|
3054 |
+
*
|
3055 |
+
* @return boolean
|
3056 |
+
*/
|
3057 |
+
public function isLogToDisplay() {
|
3058 |
+
return $this->logToDisplay;
|
3059 |
+
}
|
3060 |
+
|
3061 |
+
public function removeAll() {
|
3062 |
+
$this->loggers = array();
|
3063 |
+
$this->customParameters = array();
|
3064 |
+
$this->disabledTypes = array();
|
3065 |
+
$this->group = null;
|
3066 |
+
}
|
3067 |
+
|
3068 |
+
/**
|
3069 |
+
*
|
3070 |
+
* @param La_Log_LoggerBase $logger
|
3071 |
+
* @param int $logLevel
|
3072 |
+
* @return La_Log_LoggerBase
|
3073 |
+
*/
|
3074 |
+
public function addLogger(La_Log_LoggerBase $logger, $logLevel) {
|
3075 |
+
if(!$this->checkLoggerTypeExists($logger->getType())) {
|
3076 |
+
$logger->setLogLevel($logLevel);
|
3077 |
+
$this->loggers[$logger->getType()] = $logger;
|
3078 |
+
return $logger;
|
3079 |
+
} else {
|
3080 |
+
$ll = new La_Log_LoggerDatabase();
|
3081 |
+
$existingLogger = $this->loggers[$logger->getType()];
|
3082 |
+
if($existingLogger->getLogLevel() > $logLevel) {
|
3083 |
+
$existingLogger->setLogLevel($logLevel);
|
3084 |
+
}
|
3085 |
+
return $existingLogger;
|
3086 |
+
}
|
3087 |
+
}
|
3088 |
+
|
3089 |
+
public function getGroup() {
|
3090 |
+
return $this->group;
|
3091 |
+
}
|
3092 |
+
|
3093 |
+
public function setGroup($group = null) {
|
3094 |
+
$this->group = $group;
|
3095 |
+
if($group === null) {
|
3096 |
+
$this->group = La_Common_String::generateId(10);
|
3097 |
+
}
|
3098 |
+
}
|
3099 |
+
|
3100 |
+
public function setType($type) {
|
3101 |
+
$this->type = $type;
|
3102 |
+
}
|
3103 |
+
|
3104 |
+
/**
|
3105 |
+
* function sets custom parameter for the logger
|
3106 |
+
*
|
3107 |
+
* @param string $name
|
3108 |
+
* @param string $value
|
3109 |
+
*/
|
3110 |
+
public function setCustomParameter($name, $value) {
|
3111 |
+
$this->customParameters[$name] = $value;
|
3112 |
+
}
|
3113 |
+
|
3114 |
+
/**
|
3115 |
+
* returns custom parameter
|
3116 |
+
*
|
3117 |
+
* @param string $name
|
3118 |
+
* @return string
|
3119 |
+
*/
|
3120 |
+
public function getCustomParameter($name) {
|
3121 |
+
if(isset($this->customParameters[$name])) {
|
3122 |
+
return $this->customParameters[$name];
|
3123 |
+
}
|
3124 |
+
return '';
|
3125 |
+
}
|
3126 |
+
|
3127 |
+
/**
|
3128 |
+
* logs message
|
3129 |
+
*
|
3130 |
+
* @param string $message
|
3131 |
+
* @param string $logLevel
|
3132 |
+
* @param string $logGroup
|
3133 |
+
*/
|
3134 |
+
public function log($message, $logLevel, $logGroup = null) {
|
3135 |
+
$time = time();
|
3136 |
+
$backArr = debug_backtrace();
|
3137 |
+
$group = $logGroup;
|
3138 |
+
if($this->group !== null) {
|
3139 |
+
$group = $this->group;
|
3140 |
+
if($logGroup !== null) {
|
3141 |
+
$group .= ' ' . $logGroup;
|
3142 |
+
}
|
3143 |
+
}
|
3144 |
+
|
3145 |
+
$callingFile = $this->findLogFile();
|
3146 |
+
$file = $callingFile['file'];
|
3147 |
+
if(isset($callingFile['classVariables'])) {
|
3148 |
+
$file .= ' '.$callingFile['classVariables'];
|
3149 |
+
}
|
3150 |
+
$line = $callingFile['line'];
|
3151 |
+
|
3152 |
+
$ip = La_Http::getRemoteIp();
|
3153 |
+
if ($ip = '') {
|
3154 |
+
$ip = '127.0.0.1';
|
3155 |
+
}
|
3156 |
+
|
3157 |
+
foreach ($this->loggers as $logger) {
|
3158 |
+
if(!in_array($logger->getType(), $this->disabledTypes)) {
|
3159 |
+
$logger->logMessage($time, $message, $logLevel, $group, $ip, $file, $line, $this->type);
|
3160 |
+
}
|
3161 |
+
}
|
3162 |
+
}
|
3163 |
+
|
3164 |
+
/**
|
3165 |
+
* logs debug message
|
3166 |
+
*
|
3167 |
+
* @param string $message
|
3168 |
+
* @param string $logGroup
|
3169 |
+
*/
|
3170 |
+
public function debug($message, $logGroup = null) {
|
3171 |
+
$this->log($message, La_Log::DEBUG, $logGroup);
|
3172 |
+
}
|
3173 |
+
|
3174 |
+
/**
|
3175 |
+
* logs info message
|
3176 |
+
*
|
3177 |
+
* @param string $message
|
3178 |
+
* @param string $logGroup
|
3179 |
+
*/
|
3180 |
+
public function info($message, $logGroup = null) {
|
3181 |
+
$this->log($message, La_Log::INFO, $logGroup);
|
3182 |
+
}
|
3183 |
+
|
3184 |
+
/**
|
3185 |
+
* logs warning message
|
3186 |
+
*
|
3187 |
+
* @param string $message
|
3188 |
+
* @param string $logGroup
|
3189 |
+
*/
|
3190 |
+
public function warning($message, $logGroup = null) {
|
3191 |
+
$this->log($message, La_Log::WARNING, $logGroup);
|
3192 |
+
}
|
3193 |
+
|
3194 |
+
/**
|
3195 |
+
* logs error message
|
3196 |
+
*
|
3197 |
+
* @param string $message
|
3198 |
+
* @param string $logGroup
|
3199 |
+
*/
|
3200 |
+
public function error($message, $logGroup = null) {
|
3201 |
+
$this->log($message, La_Log::ERROR, $logGroup);
|
3202 |
+
}
|
3203 |
+
|
3204 |
+
/**
|
3205 |
+
* logs critical error message
|
3206 |
+
*
|
3207 |
+
* @param string $message
|
3208 |
+
* @param string $logGroup
|
3209 |
+
*/
|
3210 |
+
public function critical($message, $logGroup = null) {
|
3211 |
+
$this->log($message, La_Log::CRITICAL, $logGroup);
|
3212 |
+
}
|
3213 |
+
|
3214 |
+
public function disableType($type) {
|
3215 |
+
$this->disabledTypes[$type] =$type;
|
3216 |
+
}
|
3217 |
+
|
3218 |
+
public function enableAllTypes() {
|
3219 |
+
$this->disabledTypes = array();
|
3220 |
+
}
|
3221 |
+
|
3222 |
+
/**
|
3223 |
+
*
|
3224 |
+
* @return La_Log_LoggerBase
|
3225 |
+
*/
|
3226 |
+
private function create($type) {
|
3227 |
+
switch($type) {
|
3228 |
+
case La_Log_LoggerDisplay::TYPE:
|
3229 |
+
return new La_Log_LoggerDisplay();
|
3230 |
+
case La_Log_LoggerFile::TYPE:
|
3231 |
+
return new La_Log_LoggerFile();
|
3232 |
+
case La_Log_LoggerDatabase::TYPE:
|
3233 |
+
case 'db':
|
3234 |
+
return new La_Log_LoggerDatabase();
|
3235 |
+
}
|
3236 |
+
throw new La_Log_Exception("Log system '$type' does not exist");
|
3237 |
+
}
|
3238 |
+
|
3239 |
+
private function findLogFile() {
|
3240 |
+
$calls = debug_backtrace();
|
3241 |
+
|
3242 |
+
$foundObject = null;
|
3243 |
+
|
3244 |
+
// special handling for sql benchmarks
|
3245 |
+
if($this->sqlBenchmarkFound($calls)) {
|
3246 |
+
$foundObject = $this->findFileBySqlBenchmark();
|
3247 |
+
}
|
3248 |
+
|
3249 |
+
if($foundObject == null) {
|
3250 |
+
$foundObject = $this->findFileByCallingMethod($calls);
|
3251 |
+
}
|
3252 |
+
if($foundObject == null) {
|
3253 |
+
$foundObject = $this->findLatestObjectBeforeString("Logger.class.php");
|
3254 |
+
}
|
3255 |
+
if($foundObject == null) {
|
3256 |
+
$last = count($calls);
|
3257 |
+
$last -= 1;
|
3258 |
+
if($last <0) {
|
3259 |
+
$last = 0;
|
3260 |
+
}
|
3261 |
+
|
3262 |
+
$foundObject = $calls[$last];
|
3263 |
+
}
|
3264 |
+
|
3265 |
+
return $foundObject;
|
3266 |
+
}
|
3267 |
+
|
3268 |
+
private function sqlBenchmarkFound($calls) {
|
3269 |
+
foreach($calls as $obj) {
|
3270 |
+
if(isset($obj['function']) && $obj['function'] == "sqlBenchmarkEnd") {
|
3271 |
+
return true;
|
3272 |
+
}
|
3273 |
+
}
|
3274 |
+
return false;
|
3275 |
+
}
|
3276 |
+
|
3277 |
+
private function findFileBySqlBenchmark() {
|
3278 |
+
$foundFile = $this->findLatestObjectBeforeString("DbEngine");
|
3279 |
+
if($foundFile != null && is_object($foundFile['object'])) {
|
3280 |
+
$foundFile['classVariables'] = $this->getObjectVariables($foundFile['object']);
|
3281 |
+
}
|
3282 |
+
return $foundFile;
|
3283 |
+
}
|
3284 |
+
|
3285 |
+
private function getObjectVariables($object) {
|
3286 |
+
if(is_object($object)) {
|
3287 |
+
$class = get_class($object);
|
3288 |
+
$methods = get_class_methods($class);
|
3289 |
+
if(in_array("__toString", $methods)) {
|
3290 |
+
return $object->__toString();
|
3291 |
+
}
|
3292 |
+
}
|
3293 |
+
return '';
|
3294 |
+
}
|
3295 |
+
|
3296 |
+
private function findFileByCallingMethod($calls) {
|
3297 |
+
$functionNames = array('debug', 'info', 'warning', 'error', 'critical', 'log');
|
3298 |
+
$foundObject = null;
|
3299 |
+
foreach($functionNames as $name) {
|
3300 |
+
$foundObject = $this->findCallingFile($calls, $name);
|
3301 |
+
if($foundObject != null) {
|
3302 |
+
return $foundObject;
|
3303 |
+
}
|
3304 |
+
}
|
3305 |
+
|
3306 |
+
return null;
|
3307 |
+
}
|
3308 |
+
|
3309 |
+
private function findCallingFile($calls, $functionName) {
|
3310 |
+
foreach($calls as $obj) {
|
3311 |
+
if(isset($obj['function']) && $obj['function'] == $functionName) {
|
3312 |
+
return $obj;
|
3313 |
+
}
|
3314 |
+
}
|
3315 |
+
|
3316 |
+
return null;
|
3317 |
+
}
|
3318 |
+
|
3319 |
+
private function findLatestObjectBeforeString($text) {
|
3320 |
+
$callsReversed = array_reverse( debug_backtrace() );
|
3321 |
+
|
3322 |
+
$lastObject = null;
|
3323 |
+
foreach($callsReversed as $obj) {
|
3324 |
+
if(!isset($obj['file'])) {
|
3325 |
+
continue;
|
3326 |
+
}
|
3327 |
+
$pos = strpos($obj['file'], $text);
|
3328 |
+
if($pos !== false && $lastObject != null) {
|
3329 |
+
return $lastObject;
|
3330 |
+
}
|
3331 |
+
$lastObject = $obj;
|
3332 |
+
}
|
3333 |
+
return null;
|
3334 |
+
}
|
3335 |
+
}
|
3336 |
+
|
3337 |
+
} //end La_Log_Logger
|
3338 |
+
|
3339 |
+
if (!class_exists('La_Api_IncompatibleVersionException', false)) {
|
3340 |
+
class La_Api_IncompatibleVersionException extends Exception {
|
3341 |
+
|
3342 |
+
private $apiLink;
|
3343 |
+
|
3344 |
+
public function __construct($url) {
|
3345 |
+
$this->apiLink = $url. '?C=La_Api_DownloadAPI&M=download&FormRequest=Y&FormResponse=Y';
|
3346 |
+
parent::__construct('Version of API not corresponds to the Application version. Please <a href="' . $this->apiLink . '">download latest version of API</a>.', 0);
|
3347 |
+
}
|
3348 |
+
|
3349 |
+
public function getApiDownloadLink() {
|
3350 |
+
return $this->apiLink;
|
3351 |
+
}
|
3352 |
+
|
3353 |
+
}
|
3354 |
+
|
3355 |
+
} //end La_Api_IncompatibleVersionException
|
3356 |
+
|
3357 |
+
if (!class_exists('La_Api_Session', false)) {
|
3358 |
+
class La_Api_Session extends La_Object {
|
3359 |
+
const MERCHANT = 'M';
|
3360 |
+
const AFFILIATE = 'A';
|
3361 |
+
|
3362 |
+
private $url;
|
3363 |
+
private $sessionId = '';
|
3364 |
+
private $debug = false;
|
3365 |
+
private $message = '';
|
3366 |
+
private $roleType = '';
|
3367 |
+
|
3368 |
+
public function __construct($url) {
|
3369 |
+
$this->url = $url;
|
3370 |
+
}
|
3371 |
+
/**
|
3372 |
+
*
|
3373 |
+
* @param $username
|
3374 |
+
* @param $password
|
3375 |
+
* @param $roleType La_Api_Session::MERCHANT or La_Api_Session::AFFILIATE
|
3376 |
+
* @param $languageCode language code (e.g. en-US, de-DE, sk, cz, du, ...)
|
3377 |
+
* @return boolean true if user was sucesfully logged
|
3378 |
+
* @throws La_Api_IncompatibleVersionException
|
3379 |
+
*/
|
3380 |
+
public function login($username, $password, $roleType = self::MERCHANT, $languageCode = null) {
|
3381 |
+
$request = new La_Rpc_FormRequest("La_Api_AuthService", "authenticate");
|
3382 |
+
$request->setUrl($this->url);
|
3383 |
+
$request->setField("username", $username);
|
3384 |
+
$request->setField("password", $password);
|
3385 |
+
$request->setField("roleType", $roleType);
|
3386 |
+
$request->setField('apiVersion', self::getAPIVersion());
|
3387 |
+
if($languageCode != null) {
|
3388 |
+
$request->setField("language", $languageCode);
|
3389 |
+
}
|
3390 |
+
|
3391 |
+
$this->roleType = $roleType;
|
3392 |
+
|
3393 |
+
try {
|
3394 |
+
$request->sendNow();
|
3395 |
+
} catch(Exception $e) {
|
3396 |
+
$this->setMessage("Connection error: ".$e->getMessage());
|
3397 |
+
return false;
|
3398 |
+
}
|
3399 |
+
|
3400 |
+
$form = $request->getForm();
|
3401 |
+
$this->checkApiVersion($form);
|
3402 |
+
|
3403 |
+
$this->message = $form->getInfoMessage();
|
3404 |
+
|
3405 |
+
if($form->isSuccessful() && $form->existsField("S")) {
|
3406 |
+
$this->sessionId = $form->getFieldValue("S");
|
3407 |
+
$this->setMessage($form->getInfoMessage());
|
3408 |
+
return true;
|
3409 |
+
}
|
3410 |
+
|
3411 |
+
$this->setMessage($form->getErrorMessage());
|
3412 |
+
return false;
|
3413 |
+
}
|
3414 |
+
|
3415 |
+
/**
|
3416 |
+
* Get version of installed application
|
3417 |
+
*
|
3418 |
+
* @return string version of installed application
|
3419 |
+
*/
|
3420 |
+
public function getAppVersion() {
|
3421 |
+
$request = new La_Rpc_FormRequest("La_Api_AuthService", "getAppVersion");
|
3422 |
+
$request->setUrl($this->url);
|
3423 |
+
|
3424 |
+
try {
|
3425 |
+
$request->sendNow();
|
3426 |
+
} catch(Exception $e) {
|
3427 |
+
$this->setMessage("Connection error: ".$e->getMessage());
|
3428 |
+
return false;
|
3429 |
+
}
|
3430 |
+
|
3431 |
+
$form = $request->getForm();
|
3432 |
+
return $form->getFieldValue('version');
|
3433 |
+
}
|
3434 |
+
|
3435 |
+
|
3436 |
+
public function getMessage() {
|
3437 |
+
return $this->message;
|
3438 |
+
}
|
3439 |
+
|
3440 |
+
private function setMessage($msg) {
|
3441 |
+
$this->message = $msg;
|
3442 |
+
}
|
3443 |
+
|
3444 |
+
public function getDebug() {
|
3445 |
+
return $this->debug;
|
3446 |
+
}
|
3447 |
+
|
3448 |
+
public function setDebug($debug = true) {
|
3449 |
+
$this->debug = $debug;
|
3450 |
+
}
|
3451 |
+
|
3452 |
+
public function getSessionId() {
|
3453 |
+
return $this->sessionId;
|
3454 |
+
}
|
3455 |
+
|
3456 |
+
public function setSessionId($id) {
|
3457 |
+
$this->sessionId = $id;
|
3458 |
+
}
|
3459 |
+
|
3460 |
+
public function getRoleType() {
|
3461 |
+
return $this->roleType;
|
3462 |
+
}
|
3463 |
+
|
3464 |
+
public function getUrl() {
|
3465 |
+
return $this->url;
|
3466 |
+
}
|
3467 |
+
|
3468 |
+
public function getUrlWithSessionInfo($url) {
|
3469 |
+
if (strpos($url, '?') === false) {
|
3470 |
+
return $url . '?S=' . $this->getSessionId();
|
3471 |
+
}
|
3472 |
+
return $url . '&S=' . $this->getSessionId();
|
3473 |
+
}
|
3474 |
+
|
3475 |
+
/**
|
3476 |
+
* @param $latestVersion
|
3477 |
+
* @throws La_Api_IncompatibleVersionException
|
3478 |
+
*/
|
3479 |
+
private function checkApiVersion(La_Rpc_Form $form) {
|
3480 |
+
if ($form->getFieldValue('correspondsApi') === Gpf::NO) {
|
3481 |
+
throw new La_Api_IncompatibleVersionException($this->url);
|
3482 |
+
}
|
3483 |
+
}
|
3484 |
+
|
3485 |
+
/**
|
3486 |
+
* @return String
|
3487 |
+
*/
|
3488 |
+
public static function getAPIVersion($fileName = __FILE__) {
|
3489 |
+
$fileHandler = fopen($fileName, 'r');
|
3490 |
+
fseek($fileHandler, -6 -32, SEEK_END);
|
3491 |
+
$hash = fgets($fileHandler);
|
3492 |
+
return substr($hash, 0, -1);
|
3493 |
+
}
|
3494 |
+
}
|
3495 |
+
|
3496 |
+
} //end La_Api_Session
|
3497 |
+
|
3498 |
+
if (!class_exists('La_Rpc_Json', false)) {
|
3499 |
+
class La_Rpc_Json implements La_Rpc_DataEncoder, La_Rpc_DataDecoder {
|
3500 |
+
/**
|
3501 |
+
* Marker constant for Services_JSON::decode(), used to flag stack state
|
3502 |
+
*/
|
3503 |
+
const SERVICES_JSON_SLICE = 1;
|
3504 |
+
|
3505 |
+
/**
|
3506 |
+
* Marker constant for Services_JSON::decode(), used to flag stack state
|
3507 |
+
*/
|
3508 |
+
const SERVICES_JSON_IN_STR = 2;
|
3509 |
+
|
3510 |
+
/**
|
3511 |
+
* Marker constant for Services_JSON::decode(), used to flag stack state
|
3512 |
+
*/
|
3513 |
+
const SERVICES_JSON_IN_ARR = 3;
|
3514 |
+
|
3515 |
+
/**
|
3516 |
+
* Marker constant for Services_JSON::decode(), used to flag stack state
|
3517 |
+
*/
|
3518 |
+
const SERVICES_JSON_IN_OBJ = 4;
|
3519 |
+
|
3520 |
+
/**
|
3521 |
+
* Marker constant for Services_JSON::decode(), used to flag stack state
|
3522 |
+
*/
|
3523 |
+
const SERVICES_JSON_IN_CMT = 5;
|
3524 |
+
|
3525 |
+
/**
|
3526 |
+
* Behavior switch for Services_JSON::decode()
|
3527 |
+
*/
|
3528 |
+
const SERVICES_JSON_LOOSE_TYPE = 16;
|
3529 |
+
|
3530 |
+
/**
|
3531 |
+
* Behavior switch for Services_JSON::decode()
|
3532 |
+
*/
|
3533 |
+
const SERVICES_JSON_SUPPRESS_ERRORS = 32;
|
3534 |
+
|
3535 |
+
/**
|
3536 |
+
* constructs a new JSON instance
|
3537 |
+
*
|
3538 |
+
* @param int $use object behavior flags; combine with boolean-OR
|
3539 |
+
*
|
3540 |
+
* possible values:
|
3541 |
+
* - SERVICES_JSON_LOOSE_TYPE: loose typing.
|
3542 |
+
* "{...}" syntax creates associative arrays
|
3543 |
+
* instead of objects in decode().
|
3544 |
+
* - SERVICES_JSON_SUPPRESS_ERRORS: error suppression.
|
3545 |
+
* Values which can't be encoded (e.g. resources)
|
3546 |
+
* appear as NULL instead of throwing errors.
|
3547 |
+
* By default, a deeply-nested resource will
|
3548 |
+
* bubble up with an error, so all return values
|
3549 |
+
* from encode() should be checked with isError()
|
3550 |
+
*/
|
3551 |
+
function __construct($use = 0)
|
3552 |
+
{
|
3553 |
+
$this->use = $use;
|
3554 |
+
}
|
3555 |
+
|
3556 |
+
/**
|
3557 |
+
* @var La_Rpc_Json
|
3558 |
+
*/
|
3559 |
+
private static $instance;
|
3560 |
+
|
3561 |
+
/**
|
3562 |
+
*
|
3563 |
+
* @return La_Rpc_Json
|
3564 |
+
*/
|
3565 |
+
private function getInstance() {
|
3566 |
+
if (self::$instance === null) {
|
3567 |
+
self::$instance = new self;
|
3568 |
+
}
|
3569 |
+
return self::$instance;
|
3570 |
+
}
|
3571 |
+
|
3572 |
+
public static function encodeStatic($var) {
|
3573 |
+
return self::getInstance()->encode($var);
|
3574 |
+
}
|
3575 |
+
|
3576 |
+
public static function decodeStatic($var) {
|
3577 |
+
return self::getInstance()->decode($var);
|
3578 |
+
}
|
3579 |
+
|
3580 |
+
/**
|
3581 |
+
* convert a string from one UTF-16 char to one UTF-8 char
|
3582 |
+
*
|
3583 |
+
* Normally should be handled by mb_convert_encoding, but
|
3584 |
+
* provides a slower PHP-only method for installations
|
3585 |
+
* that lack the multibye string extension.
|
3586 |
+
*
|
3587 |
+
* @param string $utf16 UTF-16 character
|
3588 |
+
* @return string UTF-8 character
|
3589 |
+
* @access private
|
3590 |
+
*/
|
3591 |
+
function utf162utf8($utf16)
|
3592 |
+
{
|
3593 |
+
// oh please oh please oh please oh please oh please
|
3594 |
+
if(La_Php::isFunctionEnabled('mb_convert_encoding')) {
|
3595 |
+
return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16');
|
3596 |
+
}
|
3597 |
+
|
3598 |
+
$bytes = (ord($utf16{0}) << 8) | ord($utf16{1});
|
3599 |
+
|
3600 |
+
switch(true) {
|
3601 |
+
case ((0x7F & $bytes) == $bytes):
|
3602 |
+
// this case should never be reached, because we are in ASCII range
|
3603 |
+
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
3604 |
+
return chr(0x7F & $bytes);
|
3605 |
+
|
3606 |
+
case (0x07FF & $bytes) == $bytes:
|
3607 |
+
// return a 2-byte UTF-8 character
|
3608 |
+
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
3609 |
+
return chr(0xC0 | (($bytes >> 6) & 0x1F))
|
3610 |
+
. chr(0x80 | ($bytes & 0x3F));
|
3611 |
+
|
3612 |
+
case (0xFFFF & $bytes) == $bytes:
|
3613 |
+
// return a 3-byte UTF-8 character
|
3614 |
+
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
3615 |
+
return chr(0xE0 | (($bytes >> 12) & 0x0F))
|
3616 |
+
. chr(0x80 | (($bytes >> 6) & 0x3F))
|
3617 |
+
. chr(0x80 | ($bytes & 0x3F));
|
3618 |
+
}
|
3619 |
+
|
3620 |
+
// ignoring UTF-32 for now, sorry
|
3621 |
+
return '';
|
3622 |
+
}
|
3623 |
+
|
3624 |
+
/**
|
3625 |
+
* convert a string from one UTF-8 char to one UTF-16 char
|
3626 |
+
*
|
3627 |
+
* Normally should be handled by mb_convert_encoding, but
|
3628 |
+
* provides a slower PHP-only method for installations
|
3629 |
+
* that lack the multibye string extension.
|
3630 |
+
*
|
3631 |
+
* @param string $utf8 UTF-8 character
|
3632 |
+
* @return string UTF-16 character
|
3633 |
+
* @access private
|
3634 |
+
*/
|
3635 |
+
function utf82utf16($utf8)
|
3636 |
+
{
|
3637 |
+
// oh please oh please oh please oh please oh please
|
3638 |
+
if(La_Php::isFunctionEnabled('mb_convert_encoding')) {
|
3639 |
+
return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8');
|
3640 |
+
}
|
3641 |
+
|
3642 |
+
switch(strlen($utf8)) {
|
3643 |
+
case 1:
|
3644 |
+
// this case should never be reached, because we are in ASCII range
|
3645 |
+
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
3646 |
+
return $utf8;
|
3647 |
+
|
3648 |
+
case 2:
|
3649 |
+
// return a UTF-16 character from a 2-byte UTF-8 char
|
3650 |
+
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
3651 |
+
return chr(0x07 & (ord($utf8{0}) >> 2))
|
3652 |
+
. chr((0xC0 & (ord($utf8{0}) << 6))
|
3653 |
+
| (0x3F & ord($utf8{1})));
|
3654 |
+
|
3655 |
+
case 3:
|
3656 |
+
// return a UTF-16 character from a 3-byte UTF-8 char
|
3657 |
+
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
3658 |
+
return chr((0xF0 & (ord($utf8{0}) << 4))
|
3659 |
+
| (0x0F & (ord($utf8{1}) >> 2)))
|
3660 |
+
. chr((0xC0 & (ord($utf8{1}) << 6))
|
3661 |
+
| (0x7F & ord($utf8{2})));
|
3662 |
+
}
|
3663 |
+
|
3664 |
+
// ignoring UTF-32 for now, sorry
|
3665 |
+
return '';
|
3666 |
+
}
|
3667 |
+
|
3668 |
+
public function encodeResponse(La_Rpc_Serializable $response) {
|
3669 |
+
return $this->encode($response->toObject());
|
3670 |
+
}
|
3671 |
+
|
3672 |
+
/**
|
3673 |
+
* encodes an arbitrary variable into JSON format
|
3674 |
+
*
|
3675 |
+
* @param mixed $var any number, boolean, string, array, or object to be encoded.
|
3676 |
+
* see argument 1 to Services_JSON() above for array-parsing behavior.
|
3677 |
+
* if var is a strng, note that encode() always expects it
|
3678 |
+
* to be in ASCII or UTF-8 format!
|
3679 |
+
*
|
3680 |
+
* @return mixed JSON string representation of input var or an error if a problem occurs
|
3681 |
+
* @access public
|
3682 |
+
*/
|
3683 |
+
public function encode($var) {
|
3684 |
+
if ($this->isJsonEncodeEnabled()) {
|
3685 |
+
return @json_encode($var);
|
3686 |
+
}
|
3687 |
+
switch (gettype($var)) {
|
3688 |
+
case 'boolean':
|
3689 |
+
return $var ? 'true' : 'false';
|
3690 |
+
|
3691 |
+
case 'NULL':
|
3692 |
+
return 'null';
|
3693 |
+
|
3694 |
+
case 'integer':
|
3695 |
+
return (int) $var;
|
3696 |
+
|
3697 |
+
case 'double':
|
3698 |
+
case 'float':
|
3699 |
+
return (float) $var;
|
3700 |
+
|
3701 |
+
case 'string':
|
3702 |
+
// STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT
|
3703 |
+
$ascii = '';
|
3704 |
+
$strlen_var = strlen($var);
|
3705 |
+
|
3706 |
+
/*
|
3707 |
+
* Iterate over every character in the string,
|
3708 |
+
* escaping with a slash or encoding to UTF-8 where necessary
|
3709 |
+
*/
|
3710 |
+
for ($c = 0; $c < $strlen_var; ++$c) {
|
3711 |
+
|
3712 |
+
$ord_var_c = ord($var{$c});
|
3713 |
+
|
3714 |
+
switch (true) {
|
3715 |
+
case $ord_var_c == 0x08:
|
3716 |
+
$ascii .= '\b';
|
3717 |
+
break;
|
3718 |
+
case $ord_var_c == 0x09:
|
3719 |
+
$ascii .= '\t';
|
3720 |
+
break;
|
3721 |
+
case $ord_var_c == 0x0A:
|
3722 |
+
$ascii .= '\n';
|
3723 |
+
break;
|
3724 |
+
case $ord_var_c == 0x0C:
|
3725 |
+
$ascii .= '\f';
|
3726 |
+
break;
|
3727 |
+
case $ord_var_c == 0x0D:
|
3728 |
+
$ascii .= '\r';
|
3729 |
+
break;
|
3730 |
+
|
3731 |
+
case $ord_var_c == 0x22:
|
3732 |
+
case $ord_var_c == 0x2F:
|
3733 |
+
case $ord_var_c == 0x5C:
|
3734 |
+
// double quote, slash, slosh
|
3735 |
+
$ascii .= '\\'.$var{$c};
|
3736 |
+
break;
|
3737 |
+
|
3738 |
+
case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
|
3739 |
+
// characters U-00000000 - U-0000007F (same as ASCII)
|
3740 |
+
$ascii .= $var{$c};
|
3741 |
+
break;
|
3742 |
+
|
3743 |
+
case (($ord_var_c & 0xE0) == 0xC0):
|
3744 |
+
// characters U-00000080 - U-000007FF, mask 1 1 0 X X X X X
|
3745 |
+
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
3746 |
+
$char = pack('C*', $ord_var_c, ord($var{$c + 1}));
|
3747 |
+
$c += 1;
|
3748 |
+
$utf16 = $this->utf82utf16($char);
|
3749 |
+
$ascii .= sprintf('\u%04s', bin2hex($utf16));
|
3750 |
+
break;
|
3751 |
+
|
3752 |
+
case (($ord_var_c & 0xF0) == 0xE0):
|
3753 |
+
// characters U-00000800 - U-0000FFFF, mask 1 1 1 0 X X X X
|
3754 |
+
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
3755 |
+
$char = pack('C*', $ord_var_c,
|
3756 |
+
ord($var{$c + 1}),
|
3757 |
+
ord($var{$c + 2}));
|
3758 |
+
$c += 2;
|
3759 |
+
$utf16 = $this->utf82utf16($char);
|
3760 |
+
$ascii .= sprintf('\u%04s', bin2hex($utf16));
|
3761 |
+
break;
|
3762 |
+
|
3763 |
+
case (($ord_var_c & 0xF8) == 0xF0):
|
3764 |
+
// characters U-00010000 - U-001FFFFF, mask 1 1 1 1 0 X X X
|
3765 |
+
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
3766 |
+
$char = pack('C*', $ord_var_c,
|
3767 |
+
ord($var{$c + 1}),
|
3768 |
+
ord($var{$c + 2}),
|
3769 |
+
ord($var{$c + 3}));
|
3770 |
+
$c += 3;
|
3771 |
+
$utf16 = $this->utf82utf16($char);
|
3772 |
+
$ascii .= sprintf('\u%04s', bin2hex($utf16));
|
3773 |
+
break;
|
3774 |
+
|
3775 |
+
case (($ord_var_c & 0xFC) == 0xF8):
|
3776 |
+
// characters U-00200000 - U-03FFFFFF, mask 111110XX
|
3777 |
+
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
3778 |
+
$char = pack('C*', $ord_var_c,
|
3779 |
+
ord($var{$c + 1}),
|
3780 |
+
ord($var{$c + 2}),
|
3781 |
+
ord($var{$c + 3}),
|
3782 |
+
ord($var{$c + 4}));
|
3783 |
+
$c += 4;
|
3784 |
+
$utf16 = $this->utf82utf16($char);
|
3785 |
+
$ascii .= sprintf('\u%04s', bin2hex($utf16));
|
3786 |
+
break;
|
3787 |
+
|
3788 |
+
case (($ord_var_c & 0xFE) == 0xFC):
|
3789 |
+
// characters U-04000000 - U-7FFFFFFF, mask 1111110X
|
3790 |
+
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
3791 |
+
$char = pack('C*', $ord_var_c,
|
3792 |
+
ord($var{$c + 1}),
|
3793 |
+
ord($var{$c + 2}),
|
3794 |
+
ord($var{$c + 3}),
|
3795 |
+
ord($var{$c + 4}),
|
3796 |
+
ord($var{$c + 5}));
|
3797 |
+
$c += 5;
|
3798 |
+
$utf16 = $this->utf82utf16($char);
|
3799 |
+
$ascii .= sprintf('\u%04s', bin2hex($utf16));
|
3800 |
+
break;
|
3801 |
+
}
|
3802 |
+
}
|
3803 |
+
|
3804 |
+
return '"'.$ascii.'"';
|
3805 |
+
|
3806 |
+
case 'array':
|
3807 |
+
/*
|
3808 |
+
* As per JSON spec if any array key is not an integer
|
3809 |
+
* we must treat the the whole array as an object. We
|
3810 |
+
* also try to catch a sparsely populated associative
|
3811 |
+
* array with numeric keys here because some JS engines
|
3812 |
+
* will create an array with empty indexes up to
|
3813 |
+
* max_index which can cause memory issues and because
|
3814 |
+
* the keys, which may be relevant, will be remapped
|
3815 |
+
* otherwise.
|
3816 |
+
*
|
3817 |
+
* As per the ECMA and JSON specification an object may
|
3818 |
+
* have any string as a property. Unfortunately due to
|
3819 |
+
* a hole in the ECMA specification if the key is a
|
3820 |
+
* ECMA reserved word or starts with a digit the
|
3821 |
+
* parameter is only accessible using ECMAScript's
|
3822 |
+
* bracket notation.
|
3823 |
+
*/
|
3824 |
+
|
3825 |
+
// treat as a JSON object
|
3826 |
+
if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) {
|
3827 |
+
$properties = array_map(array($this, 'name_value'), array_keys($var), array_values($var));
|
3828 |
+
|
3829 |
+
foreach($properties as $property) {
|
3830 |
+
if(La_Rpc_Json::isError($property)) {
|
3831 |
+
return $property;
|
3832 |
+
}
|
3833 |
+
}
|
3834 |
+
|
3835 |
+
return '{' . join(',', $properties) . '}';
|
3836 |
+
}
|
3837 |
+
|
3838 |
+
// treat it like a regular array
|
3839 |
+
$elements = array_map(array($this, 'encode'), $var);
|
3840 |
+
|
3841 |
+
foreach($elements as $element) {
|
3842 |
+
if(La_Rpc_Json::isError($element)) {
|
3843 |
+
return $element;
|
3844 |
+
}
|
3845 |
+
}
|
3846 |
+
|
3847 |
+
return '[' . join(',', $elements) . ']';
|
3848 |
+
|
3849 |
+
case 'object':
|
3850 |
+
$vars = get_object_vars($var);
|
3851 |
+
|
3852 |
+
$properties = array_map(array($this, 'name_value'),
|
3853 |
+
array_keys($vars),
|
3854 |
+
array_values($vars));
|
3855 |
+
|
3856 |
+
foreach($properties as $property) {
|
3857 |
+
if(La_Rpc_Json::isError($property)) {
|
3858 |
+
return $property;
|
3859 |
+
}
|
3860 |
+
}
|
3861 |
+
|
3862 |
+
return '{' . join(',', $properties) . '}';
|
3863 |
+
|
3864 |
+
default:
|
3865 |
+
if ($this->use & self::SERVICES_JSON_SUPPRESS_ERRORS) {
|
3866 |
+
return 'null';
|
3867 |
+
}
|
3868 |
+
return new La_Rpc_Json_Error(gettype($var)." can not be encoded as JSON string");
|
3869 |
+
}
|
3870 |
+
}
|
3871 |
+
|
3872 |
+
/**
|
3873 |
+
* array-walking function for use in generating JSON-formatted name-value pairs
|
3874 |
+
*
|
3875 |
+
* @param string $name name of key to use
|
3876 |
+
* @param mixed $value reference to an array element to be encoded
|
3877 |
+
*
|
3878 |
+
* @return string JSON-formatted name-value pair, like '"name":value'
|
3879 |
+
* @access private
|
3880 |
+
*/
|
3881 |
+
function name_value($name, $value)
|
3882 |
+
{
|
3883 |
+
$encoded_value = $this->encode($value);
|
3884 |
+
|
3885 |
+
if(La_Rpc_Json::isError($encoded_value)) {
|
3886 |
+
return $encoded_value;
|
3887 |
+
}
|
3888 |
+
|
3889 |
+
return $this->encode(strval($name)) . ':' . $encoded_value;
|
3890 |
+
}
|
3891 |
+
|
3892 |
+
/**
|
3893 |
+
* reduce a string by removing leading and trailing comments and whitespace
|
3894 |
+
*
|
3895 |
+
* @param $str string string value to strip of comments and whitespace
|
3896 |
+
*
|
3897 |
+
* @return string string value stripped of comments and whitespace
|
3898 |
+
* @access private
|
3899 |
+
*/
|
3900 |
+
function reduce_string($str)
|
3901 |
+
{
|
3902 |
+
$str = preg_replace(array(
|
3903 |
+
|
3904 |
+
// eliminate single line comments in '// ...' form
|
3905 |
+
'#^\s*//(.+)$#m',
|
3906 |
+
|
3907 |
+
// eliminate multi-line comments in '/* ... */' form, at start of string
|
3908 |
+
'#^\s*/\*(.+)\*/#Us',
|
3909 |
+
|
3910 |
+
// eliminate multi-line comments in '/* ... */' form, at end of string
|
3911 |
+
'#/\*(.+)\*/\s*$#Us'
|
3912 |
+
|
3913 |
+
), '', $str);
|
3914 |
+
|
3915 |
+
// eliminate extraneous space
|
3916 |
+
return trim($str);
|
3917 |
+
}
|
3918 |
+
|
3919 |
+
/**
|
3920 |
+
* decodes a JSON string into appropriate variable
|
3921 |
+
*
|
3922 |
+
* @param string $str JSON-formatted string
|
3923 |
+
*
|
3924 |
+
* @return mixed number, boolean, string, array, or object
|
3925 |
+
* corresponding to given JSON input string.
|
3926 |
+
* See argument 1 to Services_JSON() above for object-output behavior.
|
3927 |
+
* Note that decode() always returns strings
|
3928 |
+
* in ASCII or UTF-8 format!
|
3929 |
+
* @access public
|
3930 |
+
*/
|
3931 |
+
function decode($str)
|
3932 |
+
{
|
3933 |
+
if ($this->isJsonDecodeEnabled()) {
|
3934 |
+
return json_decode($str);
|
3935 |
+
}
|
3936 |
+
|
3937 |
+
$str = $this->reduce_string($str);
|
3938 |
+
|
3939 |
+
switch (strtolower($str)) {
|
3940 |
+
case 'true':
|
3941 |
+
return true;
|
3942 |
+
|
3943 |
+
case 'false':
|
3944 |
+
return false;
|
3945 |
+
|
3946 |
+
case 'null':
|
3947 |
+
return null;
|
3948 |
+
|
3949 |
+
default:
|
3950 |
+
$m = array();
|
3951 |
+
|
3952 |
+
if (is_numeric($str)) {
|
3953 |
+
// Lookie-loo, it's a number
|
3954 |
+
|
3955 |
+
// This would work on its own, but I'm trying to be
|
3956 |
+
// good about returning integers where appropriate:
|
3957 |
+
// return (float)$str;
|
3958 |
+
|
3959 |
+
// Return float or int, as appropriate
|
3960 |
+
return ((float)$str == (integer)$str)
|
3961 |
+
? (integer)$str
|
3962 |
+
: (float)$str;
|
3963 |
+
|
3964 |
+
} elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) {
|
3965 |
+
// STRINGS RETURNED IN UTF-8 FORMAT
|
3966 |
+
$delim = substr($str, 0, 1);
|
3967 |
+
$chrs = substr($str, 1, -1);
|
3968 |
+
$utf8 = '';
|
3969 |
+
$strlen_chrs = strlen($chrs);
|
3970 |
+
|
3971 |
+
for ($c = 0; $c < $strlen_chrs; ++$c) {
|
3972 |
+
|
3973 |
+
$substr_chrs_c_2 = substr($chrs, $c, 2);
|
3974 |
+
$ord_chrs_c = ord($chrs{$c});
|
3975 |
+
|
3976 |
+
switch (true) {
|
3977 |
+
case $substr_chrs_c_2 == '\b':
|
3978 |
+
$utf8 .= chr(0x08);
|
3979 |
+
++$c;
|
3980 |
+
break;
|
3981 |
+
case $substr_chrs_c_2 == '\t':
|
3982 |
+
$utf8 .= chr(0x09);
|
3983 |
+
++$c;
|
3984 |
+
break;
|
3985 |
+
case $substr_chrs_c_2 == '\n':
|
3986 |
+
$utf8 .= chr(0x0A);
|
3987 |
+
++$c;
|
3988 |
+
break;
|
3989 |
+
case $substr_chrs_c_2 == '\f':
|
3990 |
+
$utf8 .= chr(0x0C);
|
3991 |
+
++$c;
|
3992 |
+
break;
|
3993 |
+
case $substr_chrs_c_2 == '\r':
|
3994 |
+
$utf8 .= chr(0x0D);
|
3995 |
+
++$c;
|
3996 |
+
break;
|
3997 |
+
|
3998 |
+
case $substr_chrs_c_2 == '\\"':
|
3999 |
+
case $substr_chrs_c_2 == '\\\'':
|
4000 |
+
case $substr_chrs_c_2 == '\\\\':
|
4001 |
+
case $substr_chrs_c_2 == '\\/':
|
4002 |
+
if (($delim == '"' && $substr_chrs_c_2 != '\\\'') ||
|
4003 |
+
($delim == "'" && $substr_chrs_c_2 != '\\"')) {
|
4004 |
+
$utf8 .= $chrs{++$c};
|
4005 |
+
}
|
4006 |
+
break;
|
4007 |
+
|
4008 |
+
case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)):
|
4009 |
+
// single, escaped unicode character
|
4010 |
+
$utf16 = chr(hexdec(substr($chrs, ($c + 2), 2)))
|
4011 |
+
. chr(hexdec(substr($chrs, ($c + 4), 2)));
|
4012 |
+
$utf8 .= $this->utf162utf8($utf16);
|
4013 |
+
$c += 5;
|
4014 |
+
break;
|
4015 |
+
|
4016 |
+
case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F):
|
4017 |
+
$utf8 .= $chrs{$c};
|
4018 |
+
break;
|
4019 |
+
|
4020 |
+
case ($ord_chrs_c & 0xE0) == 0xC0:
|
4021 |
+
// characters U-00000080 - U-000007FF, mask 1 1 0 X X X X X
|
4022 |
+
//see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
4023 |
+
$utf8 .= substr($chrs, $c, 2);
|
4024 |
+
++$c;
|
4025 |
+
break;
|
4026 |
+
|
4027 |
+
case ($ord_chrs_c & 0xF0) == 0xE0:
|
4028 |
+
// characters U-00000800 - U-0000FFFF, mask 1 1 1 0 X X X X
|
4029 |
+
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
4030 |
+
$utf8 .= substr($chrs, $c, 3);
|
4031 |
+
$c += 2;
|
4032 |
+
break;
|
4033 |
+
|
4034 |
+
case ($ord_chrs_c & 0xF8) == 0xF0:
|
4035 |
+
// characters U-00010000 - U-001FFFFF, mask 1 1 1 1 0 X X X
|
4036 |
+
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
4037 |
+
$utf8 .= substr($chrs, $c, 4);
|
4038 |
+
$c += 3;
|
4039 |
+
break;
|
4040 |
+
|
4041 |
+
case ($ord_chrs_c & 0xFC) == 0xF8:
|
4042 |
+
// characters U-00200000 - U-03FFFFFF, mask 111110XX
|
4043 |
+
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
4044 |
+
$utf8 .= substr($chrs, $c, 5);
|
4045 |
+
$c += 4;
|
4046 |
+
break;
|
4047 |
+
|
4048 |
+
case ($ord_chrs_c & 0xFE) == 0xFC:
|
4049 |
+
// characters U-04000000 - U-7FFFFFFF, mask 1111110X
|
4050 |
+
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
4051 |
+
$utf8 .= substr($chrs, $c, 6);
|
4052 |
+
$c += 5;
|
4053 |
+
break;
|
4054 |
+
|
4055 |
+
}
|
4056 |
+
|
4057 |
+
}
|
4058 |
+
|
4059 |
+
return $utf8;
|
4060 |
+
|
4061 |
+
} elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) {
|
4062 |
+
// array, or object notation
|
4063 |
+
|
4064 |
+
if ($str{0} == '[') {
|
4065 |
+
$stk = array(self::SERVICES_JSON_IN_ARR);
|
4066 |
+
$arr = array();
|
4067 |
+
} else {
|
4068 |
+
if ($this->use & self::SERVICES_JSON_LOOSE_TYPE) {
|
4069 |
+
$stk = array(self::SERVICES_JSON_IN_OBJ);
|
4070 |
+
$obj = array();
|
4071 |
+
} else {
|
4072 |
+
$stk = array(self::SERVICES_JSON_IN_OBJ);
|
4073 |
+
$obj = new stdClass();
|
4074 |
+
}
|
4075 |
+
}
|
4076 |
+
|
4077 |
+
array_push($stk, array('what' => self::SERVICES_JSON_SLICE,
|
4078 |
+
'where' => 0,
|
4079 |
+
'delim' => false));
|
4080 |
+
|
4081 |
+
$chrs = substr($str, 1, -1);
|
4082 |
+
$chrs = $this->reduce_string($chrs);
|
4083 |
+
|
4084 |
+
if ($chrs == '') {
|
4085 |
+
if (reset($stk) == self::SERVICES_JSON_IN_ARR) {
|
4086 |
+
return $arr;
|
4087 |
+
|
4088 |
+
} else {
|
4089 |
+
return $obj;
|
4090 |
+
|
4091 |
+
}
|
4092 |
+
}
|
4093 |
+
|
4094 |
+
//print("\nparsing {$chrs}\n");
|
4095 |
+
|
4096 |
+
$strlen_chrs = strlen($chrs);
|
4097 |
+
|
4098 |
+
for ($c = 0; $c <= $strlen_chrs; ++$c) {
|
4099 |
+
|
4100 |
+
$top = end($stk);
|
4101 |
+
$substr_chrs_c_2 = substr($chrs, $c, 2);
|
4102 |
+
|
4103 |
+
if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == self::SERVICES_JSON_SLICE))) {
|
4104 |
+
// found a comma that is not inside a string, array, etc.,
|
4105 |
+
// OR we've reached the end of the character list
|
4106 |
+
$slice = substr($chrs, $top['where'], ($c - $top['where']));
|
4107 |
+
array_push($stk, array('what' => self::SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false));
|
4108 |
+
//print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
|
4109 |
+
|
4110 |
+
if (reset($stk) == self::SERVICES_JSON_IN_ARR) {
|
4111 |
+
// we are in an array, so just push an element onto the stack
|
4112 |
+
array_push($arr, $this->decode($slice));
|
4113 |
+
|
4114 |
+
} elseif (reset($stk) == self::SERVICES_JSON_IN_OBJ) {
|
4115 |
+
// we are in an object, so figure
|
4116 |
+
// out the property name and set an
|
4117 |
+
// element in an associative array,
|
4118 |
+
// for now
|
4119 |
+
$parts = array();
|
4120 |
+
|
4121 |
+
if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
|
4122 |
+
// "name":value pair
|
4123 |
+
$key = $this->decode($parts[1]);
|
4124 |
+
$val = $this->decode($parts[2]);
|
4125 |
+
|
4126 |
+
if ($this->use & self::SERVICES_JSON_LOOSE_TYPE) {
|
4127 |
+
$obj[$key] = $val;
|
4128 |
+
} else {
|
4129 |
+
$obj->$key = $val;
|
4130 |
+
}
|
4131 |
+
} elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
|
4132 |
+
// name:value pair, where name is unquoted
|
4133 |
+
$key = $parts[1];
|
4134 |
+
$val = $this->decode($parts[2]);
|
4135 |
+
|
4136 |
+
if ($this->use & self::SERVICES_JSON_LOOSE_TYPE) {
|
4137 |
+
$obj[$key] = $val;
|
4138 |
+
} else {
|
4139 |
+
$obj->$key = $val;
|
4140 |
+
}
|
4141 |
+
}
|
4142 |
+
|
4143 |
+
}
|
4144 |
+
|
4145 |
+
} elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != self::SERVICES_JSON_IN_STR)) {
|
4146 |
+
// found a quote, and we are not inside a string
|
4147 |
+
array_push($stk, array('what' => self::SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c}));
|
4148 |
+
//print("Found start of string at {$c}\n");
|
4149 |
+
|
4150 |
+
} elseif (($chrs{$c} == $top['delim']) &&
|
4151 |
+
($top['what'] == self::SERVICES_JSON_IN_STR) &&
|
4152 |
+
(($chrs{$c - 1} != '\\') ||
|
4153 |
+
($chrs{$c - 1} == '\\' && $chrs{$c - 2} == '\\'))) {
|
4154 |
+
// found a quote, we're in a string, and it's not escaped
|
4155 |
+
array_pop($stk);
|
4156 |
+
//print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n");
|
4157 |
+
|
4158 |
+
} elseif (($chrs{$c} == '[') &&
|
4159 |
+
in_array($top['what'], array(self::SERVICES_JSON_SLICE, self::SERVICES_JSON_IN_ARR, self::SERVICES_JSON_IN_OBJ))) {
|
4160 |
+
// found a left-bracket, and we are in an array, object, or slice
|
4161 |
+
array_push($stk, array('what' => self::SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false));
|
4162 |
+
//print("Found start of array at {$c}\n");
|
4163 |
+
|
4164 |
+
} elseif (($chrs{$c} == ']') && ($top['what'] == self::SERVICES_JSON_IN_ARR)) {
|
4165 |
+
// found a right-bracket, and we're in an array
|
4166 |
+
array_pop($stk);
|
4167 |
+
//print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
|
4168 |
+
|
4169 |
+
} elseif (($chrs{$c} == '{') &&
|
4170 |
+
in_array($top['what'], array(self::SERVICES_JSON_SLICE, self::SERVICES_JSON_IN_ARR, self::SERVICES_JSON_IN_OBJ))) {
|
4171 |
+
// found a left-brace, and we are in an array, object, or slice
|
4172 |
+
array_push($stk, array('what' => self::SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false));
|
4173 |
+
//print("Found start of object at {$c}\n");
|
4174 |
+
|
4175 |
+
} elseif (($chrs{$c} == '}') && ($top['what'] == self::SERVICES_JSON_IN_OBJ)) {
|
4176 |
+
// found a right-brace, and we're in an object
|
4177 |
+
array_pop($stk);
|
4178 |
+
//print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
|
4179 |
+
|
4180 |
+
} elseif (($substr_chrs_c_2 == '/*') &&
|
4181 |
+
in_array($top['what'], array(self::SERVICES_JSON_SLICE, self::SERVICES_JSON_IN_ARR, self::SERVICES_JSON_IN_OBJ))) {
|
4182 |
+
// found a comment start, and we are in an array, object, or slice
|
4183 |
+
array_push($stk, array('what' => self::SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false));
|
4184 |
+
$c++;
|
4185 |
+
//print("Found start of comment at {$c}\n");
|
4186 |
+
|
4187 |
+
} elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == self::SERVICES_JSON_IN_CMT)) {
|
4188 |
+
// found a comment end, and we're in one now
|
4189 |
+
array_pop($stk);
|
4190 |
+
$c++;
|
4191 |
+
|
4192 |
+
for ($i = $top['where']; $i <= $c; ++$i)
|
4193 |
+
$chrs = substr_replace($chrs, ' ', $i, 1);
|
4194 |
+
|
4195 |
+
//print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
|
4196 |
+
|
4197 |
+
}
|
4198 |
+
|
4199 |
+
}
|
4200 |
+
|
4201 |
+
if (reset($stk) == self::SERVICES_JSON_IN_ARR) {
|
4202 |
+
return $arr;
|
4203 |
+
|
4204 |
+
} elseif (reset($stk) == self::SERVICES_JSON_IN_OBJ) {
|
4205 |
+
return $obj;
|
4206 |
+
|
4207 |
+
}
|
4208 |
+
|
4209 |
+
}
|
4210 |
+
}
|
4211 |
+
}
|
4212 |
+
|
4213 |
+
protected function isJsonEncodeEnabled() {
|
4214 |
+
return La_Php::isFunctionEnabled('json_encode');
|
4215 |
+
}
|
4216 |
+
|
4217 |
+
protected function isJsonDecodeEnabled() {
|
4218 |
+
return La_Php::isFunctionEnabled('json_decode');
|
4219 |
+
}
|
4220 |
+
|
4221 |
+
|
4222 |
+
/**
|
4223 |
+
* @todo Ultimately, this should just call PEAR::isError()
|
4224 |
+
*/
|
4225 |
+
function isError($data, $code = null)
|
4226 |
+
{
|
4227 |
+
if (is_object($data) &&
|
4228 |
+
(get_class($data) == 'La_Rpc_Json_Error' || is_subclass_of($data, 'La_Rpc_Json_Error'))) {
|
4229 |
+
return true;
|
4230 |
+
}
|
4231 |
+
return false;
|
4232 |
+
}
|
4233 |
+
}
|
4234 |
+
|
4235 |
+
class La_Rpc_Json_Error {
|
4236 |
+
private $message;
|
4237 |
+
|
4238 |
+
public function __construct($message) {
|
4239 |
+
$this->message = $message;
|
4240 |
+
}
|
4241 |
+
}
|
4242 |
+
|
4243 |
+
|
4244 |
+
} //end La_Rpc_Json
|
4245 |
+
|
4246 |
+
if (!class_exists('La_Rpc_JsonObject', false)) {
|
4247 |
+
class La_Rpc_JsonObject extends La_Object {
|
4248 |
+
|
4249 |
+
public function __construct($object = null) {
|
4250 |
+
if ($object != null) {
|
4251 |
+
$this->initFrom($object);
|
4252 |
+
}
|
4253 |
+
}
|
4254 |
+
|
4255 |
+
public function decode($string) {
|
4256 |
+
if ($string == null || $string == "") {
|
4257 |
+
throw new La_Exception("Invalid format (".get_class($this).")");
|
4258 |
+
}
|
4259 |
+
$string = stripslashes($string);
|
4260 |
+
$json = new La_Rpc_Json();
|
4261 |
+
$object = $json->decode($string);
|
4262 |
+
if (!is_object($object)) {
|
4263 |
+
throw new La_Exception("Invalid format (".get_class($this).")");
|
4264 |
+
}
|
4265 |
+
$this->initFrom($object);
|
4266 |
+
}
|
4267 |
+
|
4268 |
+
private function initFrom($object) {
|
4269 |
+
$object_vars = get_object_vars($object);
|
4270 |
+
foreach ($object_vars as $name => $value) {
|
4271 |
+
if (property_exists($this, $name)) {
|
4272 |
+
$this->$name = $value;
|
4273 |
+
}
|
4274 |
+
}
|
4275 |
+
}
|
4276 |
+
|
4277 |
+
public function encode() {
|
4278 |
+
$json = new La_Rpc_Json();
|
4279 |
+
return $json->encode($this);
|
4280 |
+
}
|
4281 |
+
|
4282 |
+
public function __toString() {
|
4283 |
+
return $this->encode();
|
4284 |
+
}
|
4285 |
+
}
|
4286 |
+
|
4287 |
+
} //end La_Rpc_JsonObject
|
4288 |
+
|
4289 |
+
if (!class_exists('La_Net_Http_Client', false)) {
|
4290 |
+
class La_Net_Http_Client extends La_Net_Http_ClientBase {
|
4291 |
+
|
4292 |
+
protected function isNetworkingEnabled() {
|
4293 |
+
return Gpf::YES;
|
4294 |
+
}
|
4295 |
+
|
4296 |
+
}
|
4297 |
+
|
4298 |
+
} //end La_Net_Http_Client
|
4299 |
+
|
4300 |
+
if (!class_exists('Gpf', false)) {
|
4301 |
+
class Gpf {
|
4302 |
+
const YES = 'Y';
|
4303 |
+
const NO = 'N';
|
4304 |
+
}
|
4305 |
+
}
|
4306 |
+
/*
|
4307 |
+
VERSION
|
4308 |
+
8420bb3c08118181a7f384fda817c252
|
4309 |
+
*/
|
4310 |
+
?>
|
app/code/local/Qualityunit/Liveagent/Helper/Settings.php
ADDED
@@ -0,0 +1,187 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* @copyright Copyright (c) 2007 Quality Unit s.r.o.
|
4 |
+
* @author Juraj Simon
|
5 |
+
* @package WpLiveAgentPlugin
|
6 |
+
* @version 1.0.0
|
7 |
+
*
|
8 |
+
* Licensed under GPL2
|
9 |
+
*/
|
10 |
+
|
11 |
+
class Qualityunit_Liveagent_Helper_Settings {
|
12 |
+
const CACHE_VALIDITY = 600;
|
13 |
+
|
14 |
+
//internal settings
|
15 |
+
const INTERNAL_SETTINGS = 'la-settings_internal-settings';
|
16 |
+
const OWNER_SESSIONID = 'la-settings_owner-sessionid';
|
17 |
+
const OWNER_AUTHTOKEN = 'la-settings_owner-authtoken';
|
18 |
+
const BUTTONS_DATA = 'la-settings_buttonsdata';
|
19 |
+
const ACCOUNT_STATUS = 'la-settings_accountstatus';
|
20 |
+
const ACCOUNT_NOT_REACHABLE_TIMES = 'la-settings_accountnotreachabletimes';
|
21 |
+
const LAST_BUTTONS_RELOAD_TIME = 'la-settings_lastbuttonsreloadtime';
|
22 |
+
|
23 |
+
|
24 |
+
//general page
|
25 |
+
const GENERAL_SETTINGS_PAGE_NAME = 'la-config-general-page';
|
26 |
+
const SIGNUP_SETTINGS_PAGE_NAME = 'la-config-signup-page';
|
27 |
+
const SIGNUP_WAIT_SETTINGS_PAGE_NAME = 'la-config-signup-wait-page';
|
28 |
+
|
29 |
+
const LA_URL_SETTING_NAME = 'la-url';
|
30 |
+
const LA_OWNER_EMAIL_SETTING_NAME = 'la-owner-email';
|
31 |
+
const LA_OWNER_PASSWORD_SETTING_NAME = 'la-owner-password';
|
32 |
+
const GENERAL_SETTINGS_PAGE_STATE_SETTING_NAME = 'general-settings-state';
|
33 |
+
|
34 |
+
//buttons options
|
35 |
+
const BUTTONS_SETTINGS_PAGE_NAME = 'la-config-buttons-page';
|
36 |
+
const BUTTONS_CONFIGURATION_SETTING_NAME = 'la-buttons-configuration';
|
37 |
+
|
38 |
+
const NO_AUTH_TOKEN = 'no_auth_token';
|
39 |
+
|
40 |
+
const ACCOUNT_STATUS_NOTSET = 'N';
|
41 |
+
const ACCOUNT_STATUS_SET = 'S';
|
42 |
+
|
43 |
+
public function sanitizeUrl($url) {
|
44 |
+
if (stripos($url, 'http://')!==false || stripos($url, 'https://')!==false) {
|
45 |
+
return $url;
|
46 |
+
}
|
47 |
+
return 'http://' . $url;
|
48 |
+
}
|
49 |
+
|
50 |
+
public function clearCache() {
|
51 |
+
/*update_option(self::OWNER_SESSIONID, '');
|
52 |
+
update_option(self::OWNER_AUTHTOKEN, '');
|
53 |
+
update_option(self::BUTTONS_DATA, '');*/
|
54 |
+
}
|
55 |
+
|
56 |
+
private function setCachedSetting($code, $value) {
|
57 |
+
/*$settings = get_option($code);
|
58 |
+
$settingValue = $value . "||" . time();
|
59 |
+
if ($settings != '') {
|
60 |
+
update_option($code, $settingValue);
|
61 |
+
} else {
|
62 |
+
add_option($code, $settingValue);
|
63 |
+
}*/
|
64 |
+
}
|
65 |
+
|
66 |
+
private function getCachedSetting($code) {
|
67 |
+
/*$settings = get_option($code);
|
68 |
+
if ($settings == null || trim($settings) == '') {
|
69 |
+
throw new liveagent_Exception_SettingNotValid(__(sprintf('Setting %s not defined yet.', $code)));
|
70 |
+
}
|
71 |
+
$settings = explode("||", $settings, 2);
|
72 |
+
$validTo = $settings[1] + self::CACHE_VALIDITY + 0;
|
73 |
+
if ($validTo > time()) {
|
74 |
+
return $settings[0];
|
75 |
+
} else {
|
76 |
+
if (array_key_exists('time', $settings)) {
|
77 |
+
$message = __(sprintf('Setting\'s %s validity exceeded: %s', $code, $settings['time']));
|
78 |
+
} else {
|
79 |
+
$message = __(sprintf('Setting\'s %s validity exceeded: unknown', $code));
|
80 |
+
}
|
81 |
+
throw new liveagent_Exception_SettingNotValid($message);
|
82 |
+
}*/
|
83 |
+
}
|
84 |
+
|
85 |
+
public function getOwnerSessionId() {
|
86 |
+
return $this->getOption(Qualityunit_Liveagent_Helper_Settings::OWNER_SESSIONID);
|
87 |
+
}
|
88 |
+
|
89 |
+
public function getOwnerAuthToken() {
|
90 |
+
$token = $this->getOption(Qualityunit_Liveagent_Helper_Settings::OWNER_AUTHTOKEN);
|
91 |
+
if ($token == '') {
|
92 |
+
$this->login();
|
93 |
+
$token = $this->getOption(Qualityunit_Liveagent_Helper_Settings::OWNER_AUTHTOKEN);
|
94 |
+
}
|
95 |
+
return $token;
|
96 |
+
}
|
97 |
+
|
98 |
+
public function login() {
|
99 |
+
$auth = new Qualityunit_Liveagent_Helper_Auth();
|
100 |
+
$loginData = $auth->LoginAndGetLoginData();
|
101 |
+
try {
|
102 |
+
$sessionId = $loginData->getValue('session');
|
103 |
+
$this->setOption(Qualityunit_Liveagent_Helper_Settings::OWNER_SESSIONID, $sessionId);
|
104 |
+
} catch (La_Data_RecordSetNoRowException $e) {
|
105 |
+
throw new Qualityunit_Liveagent_Exception_ConnectProblem();
|
106 |
+
}
|
107 |
+
try {
|
108 |
+
$token = $sessionId = $loginData->getValue('authtoken');
|
109 |
+
$this->setOption(Qualityunit_Liveagent_Helper_Settings::OWNER_AUTHTOKEN, $token);
|
110 |
+
} catch (La_Data_RecordSetNoRowException $e) {
|
111 |
+
// we are communicating with older LA that does not send auth token
|
112 |
+
$this->setOption(Qualityunit_Liveagent_Helper_Settings::OWNER_AUTHTOKEN, '');
|
113 |
+
}
|
114 |
+
return $sessionId;
|
115 |
+
}
|
116 |
+
|
117 |
+
public function settingsDefinedForConnection() {
|
118 |
+
//return strlen(trim($this->getLiveAgentUrl())) && strlen(trim($this->getOwnerEmail()));
|
119 |
+
}
|
120 |
+
|
121 |
+
public function getButtonsGridRecordset() {
|
122 |
+
/*try {
|
123 |
+
$data = unserialize($this->getCachedSetting(self::BUTTONS_DATA));
|
124 |
+
} catch (liveagent_Exception_SettingNotValid $e) {
|
125 |
+
$buttonsHelper = new liveagent_helper_Buttons();
|
126 |
+
$data = $buttonsHelper->getData();
|
127 |
+
if ($data->getSize() == 0) {
|
128 |
+
return $data;
|
129 |
+
}
|
130 |
+
$this->setCachedSetting(self::BUTTONS_DATA, serialize($data));
|
131 |
+
}
|
132 |
+
return $data;*/
|
133 |
+
}
|
134 |
+
|
135 |
+
public function getLiveAgentUrl() {
|
136 |
+
return $this->getOption(Qualityunit_Liveagent_Helper_Settings::LA_URL_SETTING_NAME);
|
137 |
+
}
|
138 |
+
|
139 |
+
public function getOwnerEmail() {
|
140 |
+
return $this->getOption(Qualityunit_Liveagent_Helper_Settings::LA_OWNER_EMAIL_SETTING_NAME);
|
141 |
+
//return get_option(self::LA_OWNER_EMAIL_SETTING_NAME);
|
142 |
+
}
|
143 |
+
|
144 |
+
public function getOwnerPassword() {
|
145 |
+
return $this->getOption(Qualityunit_Liveagent_Helper_Settings::LA_OWNER_PASSWORD_SETTING_NAME);
|
146 |
+
}
|
147 |
+
|
148 |
+
public function buttonIsEnabled($buttonId) {
|
149 |
+
/*$value = get_option(liveagent_Settings::BUTTONS_CONFIGURATION_SETTING_NAME);
|
150 |
+
if ($value == '' || $value === null) {
|
151 |
+
return false;
|
152 |
+
}
|
153 |
+
if (array_key_exists($buttonId, $value) && $value[$buttonId] == 'true') {
|
154 |
+
return true;
|
155 |
+
}
|
156 |
+
return false;*/
|
157 |
+
}
|
158 |
+
|
159 |
+
public function getButtonsLastReloadTime() {
|
160 |
+
return $this->getOption(self::LAST_BUTTONS_RELOAD_TIME);
|
161 |
+
}
|
162 |
+
|
163 |
+
public function updateLastButtonsReloadTime() {
|
164 |
+
$this->setOption(self::LAST_BUTTONS_RELOAD_TIME, time());
|
165 |
+
}
|
166 |
+
|
167 |
+
public function setOption($name, $value) {
|
168 |
+
$setting = Mage::getModel('liveagent/settings')->load($name, 'name');
|
169 |
+
$setting->setValue($value);
|
170 |
+
$setting->setName($name);
|
171 |
+
$setting->save();
|
172 |
+
}
|
173 |
+
|
174 |
+
public function getOption($name) {
|
175 |
+
$setting = Mage::getModel('liveagent/settings')->load($name, 'name');
|
176 |
+
return $setting->getData('value');
|
177 |
+
}
|
178 |
+
|
179 |
+
public function getAccountStatus() {
|
180 |
+
return $this->getOption(Qualityunit_Liveagent_Helper_Settings::ACCOUNT_STATUS);
|
181 |
+
}
|
182 |
+
|
183 |
+
public function connectionSettingsAreEmpty() {
|
184 |
+
return $this->getOption(Qualityunit_Liveagent_Helper_Settings::LA_URL_SETTING_NAME) == '' && $this->getOption(Qualityunit_Liveagent_Helper_Settings::LA_OWNER_EMAIL_SETTING_NAME) == '';
|
185 |
+
}
|
186 |
+
}
|
187 |
+
?>
|
app/code/local/Qualityunit/Liveagent/Helper/Signup.php
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* @copyright Copyright (c) 2007 Quality Unit s.r.o.
|
4 |
+
* @author Juraj Simon
|
5 |
+
* @package WpLiveAgentPlugin
|
6 |
+
* @version 1.0.0
|
7 |
+
*
|
8 |
+
* Licensed under GPL2
|
9 |
+
*/
|
10 |
+
|
11 |
+
class Qualityunit_Liveagent_Helper_Signup extends Qualityunit_Liveagent_Helper_Base {
|
12 |
+
|
13 |
+
public function signup($name, $email, $domain, $password, $papVisitorId = '') {
|
14 |
+
$request = new La_Rpc_ActionRequest('Dp_QualityUnit_La_Signup', 'createAccountRequest');
|
15 |
+
$request->setUrl('http://members.qualityunit.com/scripts/server.php');
|
16 |
+
$request->addParam('domain', $domain);
|
17 |
+
$request->addParam('name', $name);
|
18 |
+
$request->addParam('email', $email);
|
19 |
+
$request->addParam('password', $password);
|
20 |
+
$request->addParam('variationid', '00198b52');
|
21 |
+
$request->addParam('PAPvisitorId', $papVisitorId);
|
22 |
+
$request->addParam('source', 'magento');
|
23 |
+
$request->sendNow();
|
24 |
+
return $request->getStdResponse();
|
25 |
+
}
|
26 |
+
}
|
app/code/local/Qualityunit/Liveagent/Model/Buttons.php
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Qualityunit_Liveagent_Model_Buttons extends Mage_Core_Model_Abstract
|
4 |
+
{
|
5 |
+
public function _construct()
|
6 |
+
{
|
7 |
+
parent::_construct();
|
8 |
+
$this->_init('liveagent/buttons');
|
9 |
+
}
|
10 |
+
}
|
app/code/local/Qualityunit/Liveagent/Model/Liveagent.php
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Qualityunit_Liveagent_Model_Liveagent extends Mage_Core_Model_Abstract
|
4 |
+
{
|
5 |
+
public function _construct()
|
6 |
+
{
|
7 |
+
parent::_construct();
|
8 |
+
$this->_init('liveagent/liveagent');
|
9 |
+
}
|
10 |
+
}
|
app/code/local/Qualityunit/Liveagent/Model/Mysql4/Buttons.php
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Qualityunit_Liveagent_Model_Mysql4_Buttons extends Mage_Core_Model_Mysql4_Abstract
|
4 |
+
{
|
5 |
+
public function _construct()
|
6 |
+
{
|
7 |
+
$this->_init('liveagent/liveagentbuttons', 'liveagentbutton_id');
|
8 |
+
}
|
9 |
+
}
|
app/code/local/Qualityunit/Liveagent/Model/Mysql4/Buttons/Collection.php
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Qualityunit_Liveagent_Model_Mysql4_Buttons_Collection extends Mage_Core_Model_Mysql4_Collection_Abstract
|
4 |
+
{
|
5 |
+
public function _construct()
|
6 |
+
{
|
7 |
+
parent::_construct();
|
8 |
+
$this->_init('liveagent/buttons');
|
9 |
+
}
|
10 |
+
}
|
app/code/local/Qualityunit/Liveagent/Model/Mysql4/Liveagent.php
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Qualityunit_Liveagent_Model_Mysql4_Liveagent extends Mage_Core_Model_Mysql4_Abstract
|
4 |
+
{
|
5 |
+
public function _construct()
|
6 |
+
{
|
7 |
+
// Note that the liveagent_id refers to the key field in your database table.
|
8 |
+
$this->_init('liveagent/liveagent', 'liveagent_id');
|
9 |
+
}
|
10 |
+
}
|
app/code/local/Qualityunit/Liveagent/Model/Mysql4/Liveagent/Collection.php
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Qualityunit_Liveagent_Model_Mysql4_Liveagent_Collection extends Mage_Core_Model_Mysql4_Collection_Abstract
|
4 |
+
{
|
5 |
+
public function _construct()
|
6 |
+
{
|
7 |
+
parent::_construct();
|
8 |
+
$this->_init('liveagent/liveagent');
|
9 |
+
}
|
10 |
+
}
|
app/code/local/Qualityunit/Liveagent/Model/Mysql4/Settings.php
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Qualityunit_Liveagent_Model_Mysql4_Settings extends Mage_Core_Model_Mysql4_Abstract
|
4 |
+
{
|
5 |
+
public function _construct()
|
6 |
+
{
|
7 |
+
// Note that the liveagent_id refers to the key field in your database table.
|
8 |
+
$this->_init('liveagent/liveagentsettings', 'id');
|
9 |
+
}
|
10 |
+
}
|
app/code/local/Qualityunit/Liveagent/Model/Mysql4/Settings/Collection.php
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Qualityunit_Liveagent_Model_Mysql4_Settings_Collection extends Mage_Core_Model_Mysql4_Collection_Abstract
|
4 |
+
{
|
5 |
+
public function _construct()
|
6 |
+
{
|
7 |
+
parent::_construct();
|
8 |
+
$this->_init('liveagent/liveagentsettings');
|
9 |
+
}
|
10 |
+
}
|
app/code/local/Qualityunit/Liveagent/Model/Settings.php
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Qualityunit_Liveagent_Model_Settings extends Mage_Core_Model_Abstract
|
4 |
+
{
|
5 |
+
public function _construct()
|
6 |
+
{
|
7 |
+
parent::_construct();
|
8 |
+
$this->_init('liveagent/settings');
|
9 |
+
}
|
10 |
+
}
|
app/code/local/Qualityunit/Liveagent/Model/Status.php
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Qualityunit_Liveagent_Model_Status extends Varien_Object
|
4 |
+
{
|
5 |
+
const STATUS_ENABLED = 'Y';
|
6 |
+
const STATUS_DISABLED = 'N';
|
7 |
+
|
8 |
+
static public function getOptionArray()
|
9 |
+
{
|
10 |
+
return array(
|
11 |
+
self::STATUS_ENABLED => Mage::helper('liveagent')->__('Enabled'),
|
12 |
+
self::STATUS_DISABLED => Mage::helper('liveagent')->__('Disabled')
|
13 |
+
);
|
14 |
+
}
|
15 |
+
}
|
app/code/local/Qualityunit/Liveagent/controllers/Adminhtml/ButtonsController.php
ADDED
@@ -0,0 +1,84 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Qualityunit_Liveagent_Adminhtml_ButtonsController extends Mage_Adminhtml_Controller_action {
|
4 |
+
|
5 |
+
/**
|
6 |
+
* @var Qualityunit_Liveagent_Helper_Settings
|
7 |
+
**/
|
8 |
+
private $settings = null;
|
9 |
+
|
10 |
+
protected function _construct() {
|
11 |
+
parent::_construct();
|
12 |
+
$path = dirname(__FILE__);
|
13 |
+
require_once $path . '/../../Helper/PhpApi.php';
|
14 |
+
$this->settings = new Qualityunit_Liveagent_Helper_Settings();
|
15 |
+
}
|
16 |
+
|
17 |
+
private function initLayout() {
|
18 |
+
$this->loadLayout()
|
19 |
+
->_setActiveMenu('liveagent/buttons')
|
20 |
+
->_addBreadcrumb(Mage::helper('adminhtml')->__('Buttons'), Mage::helper('adminhtml')->__('Settings'));
|
21 |
+
}
|
22 |
+
|
23 |
+
private function doAfterPost() {
|
24 |
+
$this->_redirect('*/*');
|
25 |
+
}
|
26 |
+
|
27 |
+
private function doPostAction() {
|
28 |
+
$post = $this->getRequest()->getPost();
|
29 |
+
$this->doAfterPost();
|
30 |
+
}
|
31 |
+
|
32 |
+
public function postAction() {
|
33 |
+
$this->initLayout();
|
34 |
+
try {
|
35 |
+
$this->doPostAction();
|
36 |
+
} catch (Exception $e) {
|
37 |
+
Mage::log($e->getMessage(), Zend_log::ERR);
|
38 |
+
Mage::getSingleton('adminhtml/session')->addError($e->getMessage());
|
39 |
+
$this->_redirect('*/*');
|
40 |
+
$this->renderLayout();
|
41 |
+
}
|
42 |
+
}
|
43 |
+
|
44 |
+
public function indexAction() {
|
45 |
+
$this->initLayout();
|
46 |
+
try {
|
47 |
+
$this->doIndexAction();
|
48 |
+
} catch (Exception $e) {
|
49 |
+
Mage::log($e->getMessage(), Zend_log::ERR);
|
50 |
+
Mage::getSingleton('adminhtml/session')->addError($e->getMessage());
|
51 |
+
$this->renderLayout();
|
52 |
+
}
|
53 |
+
}
|
54 |
+
|
55 |
+
public function doIndexAction() {
|
56 |
+
$block = new Qualityunit_Liveagent_Block_ButtonsGrid();
|
57 |
+
$this->_addContent($this->getLayout()->createBlock($block));
|
58 |
+
$this->renderLayout();
|
59 |
+
}
|
60 |
+
|
61 |
+
public function massStatusAction()
|
62 |
+
{
|
63 |
+
$liveagentIds = $this->getRequest()->getParam('buttonids');
|
64 |
+
if(!is_array($liveagentIds)) {
|
65 |
+
Mage::getSingleton('adminhtml/session')->addError($this->__('Please select item(s)'));
|
66 |
+
} else {
|
67 |
+
try {
|
68 |
+
foreach ($liveagentIds as $liveagentId) {
|
69 |
+
$liveagent = Mage::getSingleton('liveagent/buttons')
|
70 |
+
->load($liveagentId)
|
71 |
+
->setOnlinestatus($this->getRequest()->getParam('status'))
|
72 |
+
->setIsMassupdate(true)
|
73 |
+
->save();
|
74 |
+
}
|
75 |
+
$this->_getSession()->addSuccess(
|
76 |
+
$this->__('Total of %d button(s) were successfully updated', count($liveagentIds))
|
77 |
+
);
|
78 |
+
} catch (Exception $e) {
|
79 |
+
$this->_getSession()->addError($e->getMessage());
|
80 |
+
}
|
81 |
+
}
|
82 |
+
$this->_redirect('*/*/index');
|
83 |
+
}
|
84 |
+
}
|
app/code/local/Qualityunit/Liveagent/controllers/Adminhtml/LiveagentController.php
ADDED
@@ -0,0 +1,242 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Qualityunit_Liveagent_Adminhtml_LiveagentController extends Mage_Adminhtml_Controller_Action {
|
4 |
+
|
5 |
+
const LIVEAGENT_PLUGIN_NAME = 'liveagent';
|
6 |
+
const ACTION_CREATE = 'c';
|
7 |
+
|
8 |
+
/**
|
9 |
+
* @var Qualityunit_Liveagent_Helper_Settings
|
10 |
+
**/
|
11 |
+
private $settings = null;
|
12 |
+
|
13 |
+
protected function _construct() {
|
14 |
+
parent::_construct();
|
15 |
+
$path = dirname(__FILE__);
|
16 |
+
require_once $path . '/../../Helper/PhpApi.php';
|
17 |
+
$this->settings = new Qualityunit_Liveagent_Helper_Settings();
|
18 |
+
}
|
19 |
+
|
20 |
+
private function initLayout() {
|
21 |
+
$this->loadLayout()
|
22 |
+
->_setActiveMenu('liveagent/account')
|
23 |
+
->_addBreadcrumb(Mage::helper('adminhtml')->__('Account'), Mage::helper('adminhtml')->__('Settings'));
|
24 |
+
}
|
25 |
+
|
26 |
+
private function doAfterPost() {
|
27 |
+
$this->_redirect('*/*');
|
28 |
+
}
|
29 |
+
|
30 |
+
private function doPostAction() {
|
31 |
+
$post = $this->getRequest()->getPost();
|
32 |
+
if (!array_key_exists('action', $post)) {
|
33 |
+
$this->doAfterPost();
|
34 |
+
return;
|
35 |
+
}
|
36 |
+
if ($post['action']=="r") {
|
37 |
+
try {
|
38 |
+
$this->validateSignupMail($post[Qualityunit_Liveagent_Helper_Settings::LA_OWNER_EMAIL_SETTING_NAME]);
|
39 |
+
$this->registerAccountAction(
|
40 |
+
$post[Qualityunit_Liveagent_Block_Signup::FULL_NAME_FIELD],
|
41 |
+
$post[Qualityunit_Liveagent_Helper_Settings::LA_OWNER_EMAIL_SETTING_NAME],
|
42 |
+
$post[Qualityunit_Liveagent_Helper_Settings::LA_URL_SETTING_NAME],
|
43 |
+
substr(md5(microtime()),0,8),
|
44 |
+
''
|
45 |
+
);
|
46 |
+
} catch (Qualityunit_Liveagent_Exception_SignupFailed $e) {
|
47 |
+
$this->signupFailed($e);
|
48 |
+
return;
|
49 |
+
}
|
50 |
+
$this->doAfterPost();
|
51 |
+
return;
|
52 |
+
}
|
53 |
+
if ($post['action']==Qualityunit_Liveagent_Block_Account::SAVE_ACCOUNT_SETTINGS_ACTION_FLAG) {
|
54 |
+
$this->saveAccountSettings($post);
|
55 |
+
Mage::getSingleton('adminhtml/session')->addSuccess(Mage::helper('adminhtml')->__('Account settings were saved successfully'));
|
56 |
+
}
|
57 |
+
$this->doAfterPost();
|
58 |
+
}
|
59 |
+
|
60 |
+
private function validateSignupMail($mail) {
|
61 |
+
if (!Zend_Validate::is($mail, 'EmailAddress')) {
|
62 |
+
throw new Qualityunit_Liveagent_Exception_SignupFailed(Mage::helper('adminhtml')->__('Please enter valid email address'));
|
63 |
+
}
|
64 |
+
}
|
65 |
+
|
66 |
+
private function signupFailed($e) {
|
67 |
+
Mage::getSingleton('adminhtml/session')->addError($e->getMessage());
|
68 |
+
$this->doAfterPost();
|
69 |
+
}
|
70 |
+
|
71 |
+
public function postAction() {
|
72 |
+
$this->initLayout();
|
73 |
+
try {
|
74 |
+
$this->doPostAction();
|
75 |
+
} catch (Exception $e) {
|
76 |
+
Mage::log($e->getMessage(), Zend_log::ERR);
|
77 |
+
Mage::getSingleton('adminhtml/session')->addError($e->getMessage());
|
78 |
+
$this->_redirect('*/*');
|
79 |
+
$this->renderLayout();
|
80 |
+
}
|
81 |
+
}
|
82 |
+
|
83 |
+
private function saveAccountsettings($post) {
|
84 |
+
$this->settings->setOption(Qualityunit_Liveagent_Helper_Settings::LA_OWNER_EMAIL_SETTING_NAME, $post[Qualityunit_Liveagent_Helper_Settings::LA_OWNER_EMAIL_SETTING_NAME]);
|
85 |
+
$this->settings->setOption(Qualityunit_Liveagent_Helper_Settings::LA_OWNER_PASSWORD_SETTING_NAME, $post[Qualityunit_Liveagent_Helper_Settings::LA_OWNER_PASSWORD_SETTING_NAME]);
|
86 |
+
$this->settings->setOption(Qualityunit_Liveagent_Helper_Settings::LA_URL_SETTING_NAME, $post[Qualityunit_Liveagent_Helper_Settings::LA_URL_SETTING_NAME]);
|
87 |
+
}
|
88 |
+
|
89 |
+
public function indexAction() {
|
90 |
+
$this->initLayout();
|
91 |
+
try {
|
92 |
+
$this->doIndexAction();
|
93 |
+
} catch (Exception $e) {
|
94 |
+
Mage::log($e->getMessage(), Zend_log::ERR);
|
95 |
+
Mage::getSingleton('adminhtml/session')->addError($e->getMessage());
|
96 |
+
$this->renderLayout();
|
97 |
+
}
|
98 |
+
}
|
99 |
+
|
100 |
+
private function getAccountNotReachableTimes() {
|
101 |
+
$times = $this->settings->getOption(Qualityunit_Liveagent_Helper_Settings::ACCOUNT_NOT_REACHABLE_TIMES);
|
102 |
+
if ($times == '') {
|
103 |
+
return 0;
|
104 |
+
}
|
105 |
+
return $times;
|
106 |
+
}
|
107 |
+
|
108 |
+
/**
|
109 |
+
* @return Qualityunit_Liveagent_Block_Waiting
|
110 |
+
*/
|
111 |
+
private function getWaitingDialog() {
|
112 |
+
$this->settings->setOption(Qualityunit_Liveagent_Helper_Settings::ACCOUNT_NOT_REACHABLE_TIMES, $this->settings->getOption(Qualityunit_Liveagent_Helper_Settings::ACCOUNT_NOT_REACHABLE_TIMES) + 1);
|
113 |
+
return new Qualityunit_Liveagent_Block_Waiting();
|
114 |
+
}
|
115 |
+
|
116 |
+
public function doIndexAction() {
|
117 |
+
if ($this->getRequest()->getParam('action')=="") {
|
118 |
+
if ($this->isNew()) {
|
119 |
+
$block = new Qualityunit_Liveagent_Block_Signup();
|
120 |
+
} else if ($this->isWaiting()) {
|
121 |
+
if ($this->getAccountNotReachableTimes() <= 1) {
|
122 |
+
$block = $this->getWaitingDialog();
|
123 |
+
} else if ($this->getAccountNotReachableTimes() > 1) {
|
124 |
+
if ($this->accountIsOnline() || $this->getAccountNotReachableTimes() > 3) {
|
125 |
+
$this->skipWaitAction();
|
126 |
+
$this->renderAccountDialog();
|
127 |
+
$this->renderLayout();
|
128 |
+
return;
|
129 |
+
}
|
130 |
+
$block = $this->getWaitingDialog();
|
131 |
+
}
|
132 |
+
} else {
|
133 |
+
$this->renderAccountDialog();
|
134 |
+
$this->renderLayout();
|
135 |
+
return;
|
136 |
+
}
|
137 |
+
$this->_addContent($this->getLayout()->createBlock($block));
|
138 |
+
$this->renderLayout();
|
139 |
+
return;
|
140 |
+
}
|
141 |
+
if ($this->getRequest()->getParam('action')=="c") {
|
142 |
+
$this->resetAccountAction();
|
143 |
+
$block = new Qualityunit_Liveagent_Block_Signup();
|
144 |
+
}
|
145 |
+
if ($this->getRequest()->getParam('action')=="s") {
|
146 |
+
$this->skipWaitAction();
|
147 |
+
$this->renderAccountDialog();
|
148 |
+
$this->renderLayout();
|
149 |
+
return;
|
150 |
+
}
|
151 |
+
$this->_addContent($this->getLayout()->createBlock($block));
|
152 |
+
$this->renderLayout();
|
153 |
+
}
|
154 |
+
|
155 |
+
private function renderConnectionInfo() {
|
156 |
+
$block = new Qualityunit_Liveagent_Block_Connectioninfo();
|
157 |
+
$block->setConnectionValid($this->accountIsOnline());
|
158 |
+
$this->_addContent($this->getLayout()->createBlock($block));
|
159 |
+
}
|
160 |
+
|
161 |
+
private function renderAccountButton() {
|
162 |
+
$block = new Qualityunit_Liveagent_Block_Accountbutton();
|
163 |
+
$block->setSettings($this->settings);
|
164 |
+
$this->_addContent($this->getLayout()->createBlock($block));
|
165 |
+
}
|
166 |
+
|
167 |
+
private function renderCreateFreeAccountWidget() {
|
168 |
+
$block = new Qualityunit_Liveagent_Block_CreateFreeAccountWidget();
|
169 |
+
$this->_addContent($this->getLayout()->createBlock($block));
|
170 |
+
}
|
171 |
+
|
172 |
+
private function renderAccountDialog() {
|
173 |
+
$this->renderConnectionInfo();
|
174 |
+
if ($this->accountIsOnline()) {
|
175 |
+
$buttons = new Qualityunit_Liveagent_Helper_Buttons();
|
176 |
+
$buttons->refresh();
|
177 |
+
$buttons->enableDefaultButtonIfNoImpressions();
|
178 |
+
$this->renderAccountButton();
|
179 |
+
} else {
|
180 |
+
if ($this->settings->connectionSettingsAreEmpty()) {
|
181 |
+
$this->renderCreateFreeAccountWidget();
|
182 |
+
}
|
183 |
+
}
|
184 |
+
$block = new Qualityunit_Liveagent_Block_Account();
|
185 |
+
$this->_addContent($this->getLayout()->createBlock($block));
|
186 |
+
}
|
187 |
+
|
188 |
+
private function accountIsOnline() {
|
189 |
+
$auth = new Qualityunit_Liveagent_Helper_Auth();
|
190 |
+
try {
|
191 |
+
$auth->ping();
|
192 |
+
Mage::log('Account is online!', Zend_Log::INFO);
|
193 |
+
return true;
|
194 |
+
} catch (Qualityunit_Liveagent_Exception_ConnectProblem $e) {
|
195 |
+
Mage::log('Account not online', Zend_Log::INFO);
|
196 |
+
return false;
|
197 |
+
}
|
198 |
+
}
|
199 |
+
|
200 |
+
private function isNew() {
|
201 |
+
return $this->settings->getAccountStatus() == Qualityunit_Liveagent_Helper_Base::ACCOUNT_STATUS_NOTSET;
|
202 |
+
}
|
203 |
+
|
204 |
+
private function isWaiting() {
|
205 |
+
return $this->settings->getAccountStatus() == Qualityunit_Liveagent_Helper_Base::ACCOUNT_STATUS_WAIT;
|
206 |
+
}
|
207 |
+
|
208 |
+
private function resetAccountAction() {
|
209 |
+
$this->settings->setOption(Qualityunit_Liveagent_Helper_Settings::ACCOUNT_STATUS, Qualityunit_Liveagent_Helper_Base::ACCOUNT_STATUS_NOTSET);
|
210 |
+
}
|
211 |
+
|
212 |
+
private function sendSignupRequest($name, $email, $domain, $password, $papvisitorId) {
|
213 |
+
$signupHelper = new Qualityunit_Liveagent_Helper_Signup();
|
214 |
+
try {
|
215 |
+
$response = $signupHelper->signup($name, $email, $domain, $password, $papvisitorId);
|
216 |
+
} catch (La_Exception $e) {
|
217 |
+
throw new Qualityunit_Liveagent_Exception_SignupFailed($e->getMessage());
|
218 |
+
}
|
219 |
+
Mage::log("Signup response recieved:" . print_r($response, true), Zend_log::DEBUG);
|
220 |
+
if ($response->success != "Y") {
|
221 |
+
Mage::log("Response contain error:" . $response->errorMessage, Zend_log::DEBUG);
|
222 |
+
throw new Qualityunit_Liveagent_Exception_SignupFailed($response->errorMessage);
|
223 |
+
}
|
224 |
+
Mage::log("Response OK", Zend_log::DEBUG);
|
225 |
+
}
|
226 |
+
|
227 |
+
private function registerAccountAction($name, $email, $domain, $password, $papvisitorId) {
|
228 |
+
$this->sendSignupRequest($name, $email, $domain, $password, $papvisitorId);
|
229 |
+
$this->settings->setOption(Qualityunit_Liveagent_Helper_Settings::LA_URL_SETTING_NAME, 'http://' . $domain . '.ladesk.com');
|
230 |
+
$this->settings->setOption(Qualityunit_Liveagent_Helper_Settings::LA_OWNER_EMAIL_SETTING_NAME, $email);
|
231 |
+
$this->settings->setOption(Qualityunit_Liveagent_Helper_Settings::LA_OWNER_PASSWORD_SETTING_NAME, $password);
|
232 |
+
$this->settings->setOption(Qualityunit_Liveagent_Helper_Settings::ACCOUNT_STATUS, Qualityunit_Liveagent_Helper_Base::ACCOUNT_STATUS_WAIT);
|
233 |
+
}
|
234 |
+
|
235 |
+
private function skipWaitAction() {
|
236 |
+
$this->settings->setOption(Qualityunit_Liveagent_Helper_Settings::ACCOUNT_STATUS, Qualityunit_Liveagent_Helper_Base::ACCOUNT_STATUS_SET);
|
237 |
+
$this->settings->setOption(Qualityunit_Liveagent_Helper_Settings::ACCOUNT_NOT_REACHABLE_TIMES, 0);
|
238 |
+
$buttons = new Qualityunit_Liveagent_Helper_Buttons();
|
239 |
+
$buttons->enableDefaultButton();
|
240 |
+
$buttons->enableDefaultButton('button1');
|
241 |
+
}
|
242 |
+
}
|
app/code/local/Qualityunit/Liveagent/controllers/IndexController.php
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
class Qualityunit_Liveagent_IndexController extends Mage_Core_Controller_Front_Action
|
3 |
+
{
|
4 |
+
public function indexAction()
|
5 |
+
{
|
6 |
+
$this->loadLayout();
|
7 |
+
$this->renderLayout();
|
8 |
+
}
|
9 |
+
}
|
app/code/local/Qualityunit/Liveagent/etc/config.xml
ADDED
@@ -0,0 +1,153 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<config>
|
3 |
+
<modules>
|
4 |
+
<Qualityunit_Liveagent>
|
5 |
+
<version>0.1.0</version>
|
6 |
+
</Qualityunit_Liveagent>
|
7 |
+
</modules>
|
8 |
+
<frontend>
|
9 |
+
<routers>
|
10 |
+
<liveagent>
|
11 |
+
<use>standard</use>
|
12 |
+
<args>
|
13 |
+
<module>Qualityunit_Liveagent</module>
|
14 |
+
<frontName>liveagent</frontName>
|
15 |
+
</args>
|
16 |
+
</liveagent>
|
17 |
+
</routers>
|
18 |
+
<layout>
|
19 |
+
<updates>
|
20 |
+
<liveagent>
|
21 |
+
<file>liveagent.xml</file>
|
22 |
+
</liveagent>
|
23 |
+
</updates>
|
24 |
+
</layout>
|
25 |
+
</frontend>
|
26 |
+
<admin>
|
27 |
+
<routers>
|
28 |
+
<liveagent>
|
29 |
+
<use>admin</use>
|
30 |
+
<args>
|
31 |
+
<module>Qualityunit_Liveagent</module>
|
32 |
+
<frontName>liveagent</frontName>
|
33 |
+
</args>
|
34 |
+
</liveagent>
|
35 |
+
</routers>
|
36 |
+
</admin>
|
37 |
+
<adminhtml>
|
38 |
+
<menu>
|
39 |
+
<liveagent module="liveagent">
|
40 |
+
<title>Liveagent</title>
|
41 |
+
<sort_order>71</sort_order>
|
42 |
+
<children>
|
43 |
+
<account module="liveagent">
|
44 |
+
<title>Account settings</title>
|
45 |
+
<sort_order>0</sort_order>
|
46 |
+
<action>liveagent/adminhtml_liveagent</action>
|
47 |
+
</account>
|
48 |
+
<buttons module="liveagent">
|
49 |
+
<title>Buttons</title>
|
50 |
+
<sort_order>1</sort_order>
|
51 |
+
<action>liveagent/adminhtml_buttons</action>
|
52 |
+
</buttons>
|
53 |
+
</children>
|
54 |
+
</liveagent>
|
55 |
+
</menu>
|
56 |
+
<acl>
|
57 |
+
<resources>
|
58 |
+
<all>
|
59 |
+
<title>Allow Everything</title>
|
60 |
+
</all>
|
61 |
+
<admin>
|
62 |
+
<children>
|
63 |
+
<Qualityunit_Liveagent>
|
64 |
+
<title>Liveagent Module</title>
|
65 |
+
<sort_order>10</sort_order>
|
66 |
+
</Qualityunit_Liveagent>
|
67 |
+
</children>
|
68 |
+
</admin>
|
69 |
+
</resources>
|
70 |
+
</acl>
|
71 |
+
<layout>
|
72 |
+
<updates>
|
73 |
+
<liveagent>
|
74 |
+
<file>liveagent.xml</file>
|
75 |
+
</liveagent>
|
76 |
+
</updates>
|
77 |
+
</layout>
|
78 |
+
</adminhtml>
|
79 |
+
<global>
|
80 |
+
<models>
|
81 |
+
<liveagent>
|
82 |
+
<class>Qualityunit_Liveagent_Model</class>
|
83 |
+
<resourceModel>liveagent_mysql4</resourceModel>
|
84 |
+
</liveagent>
|
85 |
+
<liveagent_mysql4>
|
86 |
+
<class>Qualityunit_Liveagent_Model_Mysql4</class>
|
87 |
+
<entities>
|
88 |
+
<liveagent>
|
89 |
+
<table>liveagent</table>
|
90 |
+
</liveagent>
|
91 |
+
<liveagentsettings>
|
92 |
+
<table>liveagentsettings</table>
|
93 |
+
</liveagentsettings>
|
94 |
+
<liveagentbuttons>
|
95 |
+
<table>liveagentbuttons</table>
|
96 |
+
</liveagentbuttons>
|
97 |
+
</entities>
|
98 |
+
</liveagent_mysql4>
|
99 |
+
</models>
|
100 |
+
<resources>
|
101 |
+
<liveagent_setup>
|
102 |
+
<setup>
|
103 |
+
<module>Qualityunit_Liveagent</module>
|
104 |
+
</setup>
|
105 |
+
<connection>
|
106 |
+
<use>core_setup</use>
|
107 |
+
</connection>
|
108 |
+
</liveagent_setup>
|
109 |
+
<liveagent_write>
|
110 |
+
<connection>
|
111 |
+
<use>core_write</use>
|
112 |
+
</connection>
|
113 |
+
</liveagent_write>
|
114 |
+
<liveagent_read>
|
115 |
+
<connection>
|
116 |
+
<use>core_read</use>
|
117 |
+
</connection>
|
118 |
+
</liveagent_read>
|
119 |
+
</resources>
|
120 |
+
<blocks>
|
121 |
+
<liveagent>
|
122 |
+
<class>Qualityunit_Liveagent_Block</class>
|
123 |
+
</liveagent>
|
124 |
+
<dialog>
|
125 |
+
<class>Qualityunit_Liveagent_Block</class>
|
126 |
+
</dialog>
|
127 |
+
<connectioninfo>
|
128 |
+
<class>Qualityunit_Liveagent_Block</class>
|
129 |
+
</connectioninfo>
|
130 |
+
<accountbutton>
|
131 |
+
<class>Qualityunit_Liveagent_Block</class>
|
132 |
+
</accountbutton>
|
133 |
+
<page>
|
134 |
+
<rewrite>
|
135 |
+
<html_head>Qualityunit_Liveagent_Block_CustomHeader</html_head>
|
136 |
+
</rewrite>
|
137 |
+
</page>
|
138 |
+
<adminhtml>
|
139 |
+
<rewrite>
|
140 |
+
<page_head>Qualityunit_Liveagent_Block_CustomHeader2</page_head>
|
141 |
+
</rewrite>
|
142 |
+
</adminhtml>
|
143 |
+
</blocks>
|
144 |
+
<helpers>
|
145 |
+
<liveagent>
|
146 |
+
<class>Qualityunit_Liveagent_Helper</class>
|
147 |
+
</liveagent>
|
148 |
+
<buttons>
|
149 |
+
<class>Qualityunit_Liveagent_Helper</class>
|
150 |
+
</buttons>
|
151 |
+
</helpers>
|
152 |
+
</global>
|
153 |
+
</config>
|
app/code/local/Qualityunit/Liveagent/sql/liveagent_setup/mysql4-install-0.1.0.php
ADDED
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
$installer = $this;
|
4 |
+
|
5 |
+
$installer->startSetup();
|
6 |
+
|
7 |
+
/*$installer->run("
|
8 |
+
|
9 |
+
-- DROP TABLE IF EXISTS {$this->getTable('liveagent')};
|
10 |
+
CREATE TABLE {$this->getTable('liveagent')} (
|
11 |
+
`liveagent_id` int(11) unsigned NOT NULL auto_increment,
|
12 |
+
`title` varchar(255) NOT NULL default '',
|
13 |
+
`filename` varchar(255) NOT NULL default '',
|
14 |
+
`content` text NOT NULL default '',
|
15 |
+
`status` smallint(6) NOT NULL default '0',
|
16 |
+
`created_time` datetime NULL,
|
17 |
+
`update_time` datetime NULL,
|
18 |
+
PRIMARY KEY (`liveagent_id`)
|
19 |
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
20 |
+
|
21 |
+
");*/
|
22 |
+
|
23 |
+
$installer->run("
|
24 |
+
DROP TABLE IF EXISTS {$this->getTable('liveagentbuttons')};
|
25 |
+
CREATE TABLE {$this->getTable('liveagentbuttons')} (
|
26 |
+
`liveagentbutton_id` int(11) unsigned NOT NULL auto_increment,
|
27 |
+
`buttonid` char(8) NOT NULL,
|
28 |
+
`userid` char(8) DEFAULT NULL,
|
29 |
+
`name` text,
|
30 |
+
`contenttype` char(1) DEFAULT NULL,
|
31 |
+
`onlinestatus` char(1) DEFAULT NULL,
|
32 |
+
`onlinecode` longtext,
|
33 |
+
`offlinecode` longtext,
|
34 |
+
`window_width` varchar(10) DEFAULT NULL,
|
35 |
+
`window_height` varchar(10) DEFAULT NULL,
|
36 |
+
`window_position` varchar(20) DEFAULT NULL,
|
37 |
+
`impressions` int(11) DEFAULT '0',
|
38 |
+
`chats` int(11) DEFAULT '0',
|
39 |
+
`data1` varchar(255) DEFAULT NULL,
|
40 |
+
`data2` varchar(255) DEFAULT NULL,
|
41 |
+
`data3` varchar(255) DEFAULT NULL,
|
42 |
+
`data4` varchar(255) DEFAULT NULL,
|
43 |
+
`data5` varchar(255) DEFAULT NULL,
|
44 |
+
PRIMARY KEY (`liveagentbutton_id`)
|
45 |
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
46 |
+
|
47 |
+
DROP TABLE IF EXISTS {$this->getTable('liveagentsettings')};
|
48 |
+
CREATE TABLE {$this->getTable('liveagentsettings')} (
|
49 |
+
`id` int(11) unsigned NOT NULL auto_increment,
|
50 |
+
`name` varchar(255) NOT NULL,
|
51 |
+
`value` varchar(255) DEFAULT NULL,
|
52 |
+
PRIMARY KEY (`id`)
|
53 |
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
54 |
+
|
55 |
+
INSERT INTO liveagentsettings (`name` ,`value`) VALUES ('la-settings_accountstatus', 'N');
|
56 |
+
INSERT INTO liveagentsettings (`name` ,`value`) VALUES ('la-settings_accountnotreachabletimes', '0');
|
57 |
+
");
|
58 |
+
|
59 |
+
$installer->endSetup();
|
app/design/adminhtml/default/default/layout/liveagent.xml
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<layout version="0.1.0">
|
3 |
+
<liveagent_adminhtml_liveagent_index>
|
4 |
+
<reference name="content">
|
5 |
+
<block type="liveagent/dialog" name="dialog" template="liveagent/dialog.phtml"/>
|
6 |
+
</reference>
|
7 |
+
</liveagent_adminhtml_liveagent_index>
|
8 |
+
</layout>
|
app/design/adminhtml/default/default/template/liveagent/dialog.phtml
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
<!-- dialog content template-->
|
app/design/frontend/base/default/layout/liveagent.xml
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<layout version="0.1.0">
|
3 |
+
<default>
|
4 |
+
<reference name="head">
|
5 |
+
<block type="core/template" name="liveagent_header" template="liveagent/header.phtml" />
|
6 |
+
</reference>
|
7 |
+
<reference name="after_body_start">
|
8 |
+
<block type="core/template" name="liveagent_button" template="liveagent/button.phtml" />
|
9 |
+
</reference>
|
10 |
+
</default>
|
11 |
+
</layout>
|
app/design/frontend/base/default/template/liveagent/button.phtml
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
$collection = Mage::getModel('liveagent/buttons')->getCollection()->addFilter('contenttype', 'F')->addFilter('onlinestatus', 'Y');
|
3 |
+
$setting = Mage::getModel('liveagent/settings')->load('la-url', 'name');
|
4 |
+
$url = $setting->getValue();
|
5 |
+
echo '<div id="la_x2s6df8d"/>';
|
6 |
+
foreach ($collection as $button) {
|
7 |
+
echo '<img src="'.$url . '/scripts/pix.gif" onLoad="LiveAgentTracker.createButton(\''.$button->getButtonid().'\', this);"/>' . "\n";
|
8 |
+
}
|
9 |
+
|
10 |
+
?>
|
app/design/frontend/base/default/template/liveagent/header.phtml
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
$setting = Mage::getModel('liveagent/settings')->load('la-url', 'name');
|
3 |
+
$url = $setting->getValue();
|
4 |
+
echo '<script type="text/javascript" id="la_x2s6df8d" src="'.$url.'/scripts/trackjs.php"></script>';
|
5 |
+
?>
|
app/etc/modules/Qualityunit_Liveagent.xml
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<config>
|
3 |
+
<modules>
|
4 |
+
<Qualityunit_Liveagent>
|
5 |
+
<active>true</active>
|
6 |
+
<codePool>local</codePool>
|
7 |
+
</Qualityunit_Liveagent>
|
8 |
+
</modules>
|
9 |
+
</config>
|
package.xml
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<package>
|
3 |
+
<name>Liveagent</name>
|
4 |
+
<version>1.0.15</version>
|
5 |
+
<stability>stable</stability>
|
6 |
+
<license uri="http://www.gnu.org/licenses/gpl-3.0.txt">GPLv3</license>
|
7 |
+
<channel>community</channel>
|
8 |
+
<extends/>
|
9 |
+
<summary>LiveAgent plugin integrates well known help desk and live chat software into any Magento installation. No HTML knowledge is required.</summary>
|
10 |
+
<description>Magento-LiveAgent plugin integrates full featured help desk and live chat software Live Agent into any Magento installation.
|
11 |
+
Simply add "start chat" button by few simple clicks and be live within 5 minutes.</description>
|
12 |
+
<notes>changes:
|
13 |
+
- removes magento compilator errors</notes>
|
14 |
+
<authors><author><name>Juraj Simon</name><user>jurajsim</user><email>jsimon@qualityunit.com</email></author></authors>
|
15 |
+
<date>2012-01-25</date>
|
16 |
+
<time>10:48:29</time>
|
17 |
+
<contents><target name="magelocal"><dir name="Qualityunit"><dir name="Liveagent"><dir name="Block"><file name="Account.php" hash="3c5780c7e43a1b427c8a9942be5ae5f4"/><file name="Accountbutton.php" hash="ed893391cef66ed9a20270dcd825e8a7"/><dir name="Adminhtml"><dir name="Config"><file name="Account.php" hash="bd7cfa5110511019f7a163a3e1237f8d"/></dir><dir name="Liveagent"><file name="Grid.php" hash="bd7cfa5110511019f7a163a3e1237f8d"/></dir><file name="Liveagent.php" hash="39a36de680b8bd0f892cac2eceda9aa3"/></dir><file name="Base.php" hash="be036bcec33c8cc8b6248f04e66ab2ae"/><file name="ButtonsGrid.php" hash="403f095a11c3cbdd4c8d2bdd5c39ea92"/><file name="Connectioninfo.php" hash="0ba2988926c3a458b402030f90a9c6c8"/><file name="CreateFreeAccountWidget.php" hash="69673bbf0662db1ed97d5055184707d8"/><file name="CustomHeader.php" hash="d2f34ee2a9338729d6e72c328469eb2f"/><file name="CustomHeader2.php" hash="bcab9079100055561d93f38e35eefcad"/><file name="Dialog.php" hash="b599ad757d352cd8205f5eb297b33aaf"/><file name="ErrorMessageWidget.php" hash="c2464b0cc51dcc66c2a1da4f5d7196ce"/><file name="FloatButtonWidget.php" hash="e7541c92e18c59dce02435de291ab117"/><file name="Liveagent.php" hash="b2a3acbd39f442b2c1f41844a93c1fed"/><file name="Signup.php" hash="519d3b0126b7add1dd6f9f17fb956457"/><file name="Waiting.php" hash="5d305d888e7268885f1df43976b6d67a"/></dir><dir name="Exception"><file name="ConnectProblem.php" hash="f2c9840d533e6389ba84989337de32c9"/><file name="SignupFailed.php" hash="e370773d3b306bb8c24e5263d1491860"/></dir><dir name="Helper"><file name="Auth.php" hash="8263ab6dbff508b343bb2dda38227f3d"/><file name="Base.php" hash="8003134735200ef67da5e32810373dca"/><file name="Buttons.php" hash="050bef921fc945e18b21fc03120610b1"/><file name="Data.php" hash="e390bbfd2177732fb4701692dcdf9e21"/><file name="PhpApi.php" hash="be07541b661295f7d587355719f90641"/><file name="Settings.php" hash="1ad5a2e8e0380e25761ef560e4df0f86"/><file name="Signup.php" hash="54ee655169693c1434ba57d19b4ba236"/></dir><dir name="Model"><file name="Buttons.php" hash="ab4d53d1fdf7266f086f56fe5b789d9a"/><file name="Liveagent.php" hash="8bbff1b87bc9359b20fd57e903cc36a7"/><dir name="Mysql4"><dir name="Buttons"><file name="Collection.php" hash="1aa2f16ba17d7b35622aac90e49ab0d8"/></dir><file name="Buttons.php" hash="0b8cdf68a1a733ac9c0b2306bb7d707d"/><dir name="Liveagent"><file name="Collection.php" hash="4d97914f2b313bf94c153825926a24c6"/></dir><file name="Liveagent.php" hash="ce9e8956b01d6adbd8f6e47d90a940db"/><dir name="Settings"><file name="Collection.php" hash="90b3bf0169c4954eca8ad1fafc727cdf"/></dir><file name="Settings.php" hash="742ed68fe5865687b4d3663274720c80"/></dir><file name="Settings.php" hash="295eda087e5e7e3a7125d57823a0059c"/><file name="Status.php" hash="7c974f2495a419f687ce0f13421b4e59"/></dir><dir name="controllers"><dir name="Adminhtml"><file name="ButtonsController.php" hash="a6beefa9175c7eb5fcb5463eabecb035"/><file name="LiveagentController.php" hash="9a15220aa00775d759f147c4a922edbc"/></dir><file name="IndexController.php" hash="6ed77d2da66be08bd439f68820dbf1c0"/></dir><dir name="etc"><file name="config.xml" hash="048a093bb26aee02c3a441f7cf9ef131"/></dir><dir name="sql"><dir name="liveagent_setup"><file name="mysql4-install-0.1.0.php" hash="c3b21fc18c4f4e51b118670ecb50952f"/></dir></dir></dir><file name=".buildpath" hash="0d2475e3be03419439e2a22ebc4e0813"/><file name=".project" hash="41fa1353a5ab19352d5636d52e17351d"/><dir name=".settings"><file name="org.eclipse.php.core.prefs" hash="abf8f34f8087365ab830524698638d7c"/><file name="org.eclipse.wst.jsdt.ui.superType.container" hash="b27d1cf62dde4473bab7c433317bb0ce"/><file name="org.eclipse.wst.jsdt.ui.superType.name" hash="c89686a387d2b12b3c729ce35a0bcb5b"/><file name=".jsdtscope" hash="60becf9566a086946234ab57c156ae64"/></dir></dir></target><target name="magedesign"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="layout"><file name="liveagent.xml" hash="0dcae8c167ac1993cd79ab11c3617726"/></dir><dir name="template"><dir name="liveagent"><file name="dialog.phtml" hash="db91a6f20a5fc16e7f5d492ee8cdc49f"/></dir></dir></dir></dir></dir><dir name="frontend"><dir name="base"><dir name="default"><dir name="layout"><file name="liveagent.xml" hash="8315b710ce2d644aa98666e25e53f24e"/></dir><dir name="template"><dir name="liveagent"><file name="button.phtml" hash="f923d78234b7d814b0f7ac79c89f0900"/><file name="header.phtml" hash="e56cdc01a062e445e0105a6aa13c5999"/></dir></dir></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="Qualityunit_Liveagent.xml" hash="db13786c45588e15d5a390201a1709e4"/></dir></target></contents>
|
18 |
+
<compatible/>
|
19 |
+
<dependencies><required><php><min>5.2.0</min><max>5.6.0</max></php><extension><name>curl</name><min></min><max></max></extension></required></dependencies>
|
20 |
+
</package>
|