Egyedi Magento admin gridek, formok, tabok létrehozása
Tudni szeretnéd, hogyan hozhatsz létre saját webáruházadban egy külön admin menüpontot és abban egy saját lista/form párost? Az is hasznos lenne, ha vásárlóidat egy általad adminisztrált kategória struktúrába szervezhetnéd, melyekkel később külön akciókat tudsz majd végrehajtani? A Magento webáruház keretrendszerben ezeket az igényeket tudjuk egyedi admin menüpontokkal, listákkal (grid) és form-okkal kielégíteni, melyeket az adott megvalósításhoz szabhatunk.
Ebből a cikkből megtudhatod, hogy:
- Hogyan hozz létre új Magento admin menüpontot.
- Egy menüponthoz hogyan valósítható meg a lista.
- Miként lehet űrlapokat létrehozni, azon belül tetszőleges input-ot.
- A tab-ok hogyan működnek az űrlapokon.
A megoldást két úton közelítettük meg:
- Az elsőben létre kell hozni egy új admin menüpontot a kategóriák listázására, ill. szerkesztésére, majd kiegészíteni a vásárló szerkesztést egy új tab-bal, amiben azokat a kategóriákat lehet megadni, melyekben ő szerepel.
- A másik megoldás pedig az, hogy a kategória szerkesztést kiegészítjük a felhasználók listájával, ahol magához a kategóriához lehet a vásárlókat kijelölni. A végleges verzióban a második lett megvalósítva, mert így egy helyen lehet kezelni ezeket a beállításokat.
A megvalósítás tervezett lépései:
- Adatbázis új elemeinek megtervezése (az adatbázis módosítások megvalósítása nem ennek a cikknek képezik a részét)
- Új modul létrehozása (Customercategory)
- Könyvtár struktúra létrehozása
- A szükséges model-, resource model-, helper-, installer létrehozása
- App/etc/modules/Aion_Customercategory.xml
- Config.xml létrehozása a modul etc könyvtárába
- Controller-ek létrehozása
- Block-ok létrehozása
- Layout létrehozása
- Nyelvi file-ok létrehozása (csv)
A Magento modul létrehozása
A Magento-ban egy új modul létrehozásakor a kiválasztott pool-ban (jelen esetben a local) a namespace alá (aion) létre kell hozni a modul nevének szánt könyvtárat (Customercategory), és ezzel együtt az app/etc/modules alá pedig a [modul neve].xml-t a következő tartalommal:
<?xml version="1.0"?> <config> <modules> <!-- namespace_modulename --> <Aion_Customercategory> <active>true</active> <!-- pool --> <codePool>local</codePool> </Aion_Customercategory> </modules> </config>
A modul könyvtárstuktúrája:
- Block – ide kerülnek be a megjelenítéshez szánt form-ok, grid-ek és hasonló osztályok
- controllers – Ez tartalmazza a controllereket
- etc – A használt xml file-ok helye (config.xml, adminhtml.xml, …)
- Helper – a helper file-ok helye
- Model – A model file-ok helye
- sql – Az adatbázis installer/update-er file-ok helye
A modulunk etc könyvtárában lévő config.xml-ben be kell állítanunk az alapokat ahhoz, hogy a modulunk működőképes legyen:
<?xml version="1.0"?> <config> <modules> <Aion_Customercategory> <version>0.1.0</version> </Aion_Customercategory> </modules> <global> <models> <aion_customercategory> <class>Aion_Customercategory_Model</class> <resourceModel>aion_customercategory_resource</resourceModel> </aion_customercategory> <aion_customercategory_resource> <class>Aion_Customercategory_Model_Resource</class> <entities> <category> <table>aion_customercategory_category</table> </category> <customer> <table>aion_customercategory_customer</table> </customer> </entities> </aion_customercategory_resource> </models> <blocks> <aion_customercategory> <class>Aion_Customercategory_Block</class> </aion_customercategory> </blocks> <helpers> <aion_customercategory> <class>Aion_Customercategory_Helper</class> </aion_customercategory> </helpers> <resources> <aion_customercategory_setup> <setup> <class>Mage_Core_Model_Resource_Setup</class> <module>Aion_Customercategory</module> </setup> </aion_customercategory_setup> </resources> </global> </config>
Miután az alapokkal megvagyunk, létre kell hoznunk az adminban egy menüpontot, az elemek kezelésére. Mi ezt a Customer főmenüpont alá hozzuk létre, ezért a következőket kell a config.xml-be beágyaznunk:
</global>
<adminhtml>
<menu>
<customer>
<children>
<aion_customercategory>
<title>Customer Categories</title>
<sort_order>9999</sort_order>
<action>adminhtml/customercategory/index</action>
</aion_customercategory>
</children>
</customer>
</menu>
</adminhtml>
</config>
Látható, hogy úgy kell az XML struktúrát megadni, hogy az adminban (<adminhtml>) szeretnénk egy menüpontot definiálni (<menu>), azon belül a customer alá (<customer>) egy almenüt (<children>), ahol megadjuk a beállításainkat:
- title – mi legyen a menüpont neve
- sort order – a menüpont hányadik legyen a sorban
- action – Melyik controller melyik metódusa hivódjon meg a menüpontra való kattintáskor
Most ha megnézzük az admin felületünket, akkor a következő fogad (Nagyon fontos, hogy minden xml-ben történő módosítás után ürítenünk kell a Magento cache-t, hogy újra beolvassa):
Ezek után meg kell írnunk a controller-t, hogy le is kezeljük a hívást:
Létre kell hoznunk az xml-ben action-ként megadott osztály/metódus párost a controllers könyvtár alá (minden controller végződése triviálisan Controller, és a metódusok pedig Action végződést kell, hogy kapjanak). Mivel ez egy admin controller lesz, ezért a Mage_Adminhtml_Controller_Action ősosztályból kell származnia
controllers/Adminhtml/CustomercategoryController.php
class Aion_Customercategory_Adminhtml_CustomercategoryController
extends Mage_Adminhtml_Controller_Action
{
public function indexAction()
{
die('ok');
}
}
Ahhoz, hogy a Magento tudja, hogy az általunk megírt controllereket is használja, a config.xml-be a következő elemet kell beírnunk:
</adminhtml>
<admin>
<routers>
<adminhtml>
<args>
<modules>
<Aion_Customercategory before="Mage_Adminhtml">Aion_Customercategory_Adminhtml</Aion_Customercategory>
</modules>
</args>
</adminhtml>
</routers>
</admin>
Vagyis az általunk megadott útvonalakat a Magento-s router elött kezelje. Meg lehet adni after-rel is, ami ebben az esetben irreleváns, viszont ha egy system url-t akarunk mi magunk lekezelni, akkor a before a megfelelő property, hogy a default elött fusson le a mi controller/action párosunk (természetesen a módosítás után szintén cache-t kell ürítenünk, hogy a változásokat beolvassa a Magento). Most már lefut az általunk megírt metódus, de definiálni kell a layout-ot, hogy az milyen formában renderelődjön ki. Ezt szintén xml formátumban kell megadnunk, viszont pár dolog kell hozzá:
- meg kell adnunk a config.xml-ben az adminhtml tag alatt, hogy melyek azok a layout.xml-ek, amiket szeretnénk használni:
...
</menu>
<layout>
<updates>
<aion_customercategory>
<file>aion/customercategory.xml</file>
</aion_customercategory>
</updates>
</layout>
</adminhtml>
...
– Magát az indexAction-ünkben be kell tölteni a layout-tot, majd kirenderelni:
class Aion_Customercategory_Adminhtml_CustomercategoryController
extends Mage_Adminhtml_Controller_Action
{
public function indexAction()
{
$this->loadLayout();
$this->renderLayout();
}
}
- létre kell hoznunk ezeket az app/design/adminhtml/default/default/layout könyvtár alá (vagyis a modulunk layout xml leírója a /app/design/adminhtml/default/default/layout/aion/customercategory.xml file lesz).
<?xml version="1.0"?>
<layout version="0.1.0">
<adminhtml_customercategory_index>
<reference name="menu">
<action method="setActive">
<menupath>customer/customercategory</menupath>
</action>
</reference>
<reference name="content">
<block
type="aion_customercategory/adminhtml_category"
name="category_index"
/>
</reference>
</adminhtml_customercategory_index>
</layout>
A fenti példában definiáljuk az adminhtml/customercategory/index (<adminhtml_customercategory_index>) útvonal layout-ját, ahol megadjuk, hogy a kiválasztott menü a customer/customercategory, és a content-je pedig egy általunk létrehozandó adminhtml/category block lesz.
Index block létrehozása
Triviálisan, amikor a felhasználó a menüpontunkra kattint, akkor egy listát szeretne látni azokkal az elemekkel, amiket meg felvitt, illetve szeretne szerkeszteni/létrehozni/törölni elemeket. A fenti layoutban megadtuk, hogy a block-unk az adminhtml_category lesz, ezért létre kell hoznunk az app/code/local/Aion/Customercategory/Block/Adminhtml/Category.php-t, ami kezeli a layout-ban megadott content-tet:
class Aion_Customercategory_Block_Adminhtml_Category
extends Mage_Adminhtml_Block_Widget_Grid_Container
{
public function __construct()
{
$this->_blockGroup = 'aion_customercategory';
$this->_controller = 'adminhtml_category';
parent::__construct();
$this->_headerText = $this->__('Customer Categories');
$this->_addButtonLabel = $this->__('Add New');
}
}
Látható, hogy az osztályunk a Mage_Adminhtml_Block_Widget_Grid_Container leszármazottja, mert itt egy grid-et szeretnénk majd megjeleníttetni. A konstruktorban meg kell adnunk mindenképpen a _blockGroup-ot és a _controller-t, amivel megmondjuk a magento-nak, hogy a grid block-kunkat az Aion_Customercategory_Block_Adminhtml_Category_Grid-ből kell, hogy létrehozza. Amikor az ősosztály kirendereli a layout-ot, a következő függvény fut le:
$this
->getLayout()
->createBlock(
$this->_blockGroup.'/' . $this->_controller . '_grid',
$this->_controller . '.grid'
)
Grid block
Létre kell hoznunk a fent megadott grid osztályunkat az app/code/local/Aion/Customercategory/Block/Adminhtml/Category/Grid.php alatt:
class Aion_Customercategory_Block_Adminhtml_Category_Grid
extends Mage_Adminhtml_Block_Widget_Grid
{
public function __construct()
{
parent::__construct();
}
protected function _prepareCollection()
{
return parent::_prepareCollection();
}
protected function _prepareColumns()
{
return parent::_prepareColumns();
}
}
Az osztályunk a Mage_Adminhtml_Block_Widget_Grid-ből származik, viszont 3 metódust mindenképpen felül kell írnunk, hogy működni tudjon a saját modulunkban:
- __construct – A példányosításkor bizonyos alapbeállításokat eszközölnünk kell
- _prepareCollection – Honnan szedje a collection-t
- _prepareColumns – Milyen oszlopok legyenek a grid-ben
Kiegészítve a mi megoldásainkkal így néz ki az osztály:
class Aion_Customercategory_Block_Adminhtml_Category_Grid extends Mage_Adminhtml_Block_Widget_Grid
{
public function __construct()
{
parent::__construct();
$this->setId('category_id');
$this->setDefaultSort('category_id');
$this->setDefaultDir('asc');
$this->setSaveParametersInSession(true);
}
protected function _prepareCollection()
{
$collection = Mage::getModel('aion_customercategory/category')
->getCollection();
$this->setCollection($collection);
return parent::_prepareCollection();
}
protected function _prepareColumns()
{
$this->addColumn(
'category_id',
array(
'header' => $this->__('ID'),
'align' => 'right',
'width' => '50px',
'type' => 'number',
'index' => 'category_id',
)
);
$this->addColumn(
'name',
array(
'header' => $this->__('Name'),
'index' => 'name',
)
);
$this->addColumn(
'active',
array(
'header' => $this->__('Active'),
'index' => 'active',
'type' => 'options',
'options' => array(
1 => Mage::helper('adminhtml')->__('Yes'),
0 => Mage::helper('adminhtml')->__('No')
),
)
);
return parent::_prepareColumns();
}
}
Ha ezeket megvalósítottuk, akkor már az oldalon is megjelenik valami:
Látható, hogy már van egy grid-ünk, amit még ki kell egészíteni.
Magento Admin Form megvalósítása
Az általános tervezési/megvalósítási követelményeknek megfelelően célszerű az új létrehozása és meglévő elem módosítása form-okat egy közös osztállyal lekezelni. Ennek megfelelően a controllerben a következő módosításokat kell eszközölni:
class Aion_Customercategory_Adminhtml_CustomercategoryController
extends Mage_Adminhtml_Controller_Action
{
...
public function editAction()
{
$id = $this->getRequest()->getParam('id');
$model = Mage::getModel('aion_customercategory/category');
if ($id) {
$model->load($id);
if (!$model->getId()) {
$this->_getSession()->addError(
$this->__('This Category no longer exists.')
);
$this->_redirect('*/*/');
return;
}
}
$data = $this->_getSession()->getFormData(true);
if (!empty($data)) {
$model->setData($data);
}
Mage::register('current_model', $model);
$this
->loadLayout()
->renderLayout();
}
public function newAction()
{
$this->_forward('edit');
}
...
}
Vagyis az új létrehozásakor irányítson át a szerkesztésre, és ott van levizsgálva, hogy ha van ID paraméter, akkor betölti a szükséges adatokat. Viszont ahogy az az indexAction esetében is kellett, itt is szükség van a layout xml-ben definiálni, hogy hogyan épül fel az oldal:
<?xml version="1.0"?>
<layout version="0.1.0">
...
<adminhtml_customercategory_edit>
<update handle="editor"/>
<reference name="menu">
<action method="setActive">
<menupath>customer/customercategory</menupath>
</action>
</reference>
<reference name="content">
<block
type="aion_customercategory/adminhtml_category_edit"
name="category_edit"
/>
</reference>
<reference name="left">
<block
type="aion_customercategory/adminhtml_category_edit_tabs"
name="category_tabs"
/>
</reference>
</adminhtml_customercategory_edit>
...
</layout>
A szerkesztő felületen a tartalom az a kategória szerkesztő lesz (reference name=”content”), a baloldalon pedig a tab-ok (reference name=”left”). Ahhoz, hogy valami megjelenjen az oldalon, ezt a két blockot meg kell valósítanunk. Az első block az adminhtml_category_edit, amit definiálnunk kell az app/code/local/Aion/Customercategory/Block/Adminhtml/Category/Edit.php alatt:
class Aion_Customercategory_Block_Adminhtml_Category_Edit
extends Mage_Adminhtml_Block_Widget_Form_Container
{
protected function _getHelper()
{
return Mage::helper('aion_customercategory');
}
public function __construct()
{
parent::__construct();
$this->_blockGroup = 'aion_customercategory';
$this->_controller = 'adminhtml_category';
$this->_mode = 'edit';
$this->_updateButton(
'save',
'label',
$this->_getHelper()->__('Save Category')
);
$this->_addButton(
'saveandcontinue',
array(
'label' => $this->_getHelper()->__(
'Save and Continue Edit'
),
'onclick' => 'saveAndContinueEdit()',
'class' => 'save',
), -100);
$this->_formScripts[] = "
function saveAndContinueEdit(){
editForm.submit($('edit_form').action+'back/edit/');
}
";
}
}
Ez egy Mage_Adminhtml_Block_Widget_Form_Container, és magát a form-ot a _blockGroup, _controller, _mode alapján az Aion_Customercategory_Adminhtml_Category_Edit_Form osztályból tölti be. Létrehozzuk ezt az osztályt az app/code/local/Aion/Customercategory/Block/Adminhtml/Category/Edit/Form.php file-ban:
class Aion_Customercategory_Block_Adminhtml_Category_Edit_Form
extends Mage_Adminhtml_Block_Widget_Form
{
protected function _prepareForm()
{
$form = new Varien_Data_Form(array(
'id' => 'edit_form',
'method' => 'post',
'enctype' => 'multipart/form-data',
'action' => $this->getUrl('*/*/save'),
)
);
$form->setUseContainer(true);
$this->setForm($form);
return parent::_prepareForm();
}
}
Már van egy üres form-unk, meg kell valósítani a tab-ok kezelésére szánt osztályt. A block-nak az adminhtml_category_edit_tabs-ot adtuk meg a layout.xml-ben, ezért az osztály neve Aion_Customercategory_Block_Adminhtml_Category_Edit_Tabs kell, hogy legyen. Ebből következik, hogy a file az app/code/local/Aion/Customercategory/Block/Adminhtml/Category/Edit/Tabs.php kell, hogy legyen:
class Aion_Customercategory_Block_Adminhtml_Category_Edit_Tabs
extends Mage_Adminhtml_Block_Widget_Tabs
{
public function __construct()
{
parent::__construct();
$this->setId('category_tabs');
$this->setDestElementId('edit_form');
$this->setTitle(
Mage::helper('aion_customercategory')->__('Details')
);
}
protected function _beforeToHtml()
{
$this->addTab(
'category_section',
array(
'label' => Mage::helper('aion_customercategory')
->__('Category'),
'title' => Mage::helper('aion_customercategory')
->__('Category'),
'content' => $this->getLayout()
->createBlock(
'aion_customercategory/adminhtml_category_edit_category_form'
)->toHtml(),
)
);
return parent::_beforeToHtml();
}
}
Látható, hogy a __consturctor-nál lehet megadni azt, hogy mi az azonosítója, váltáskor melyik form-ba töltse az elemeket, mi legyen a cím a tab-ok felett. A _beforeToHtml-ben adjuk meg a tab-okat dinamikusan, vagyis amennyi addTab() található benne, annyi lesz a felsorolásban. Most létre kell hoznunk az adminhtml_category_edit_category_form block-ot, ami a Aion_Customercategory_Block_Adminhtml_Category_Edit_Category_Form osztályt jelenti, ami pedig az app/code/local/Aion/Customercategory/Block/Adminhtml/Category/Edit/Category/Form.php file-ban lesz megtalálható:
class Aion_Customercategory_Block_Adminhtml_Category_Edit_Category_Form
extends Mage_Adminhtml_Block_Widget_Form
{
protected function _getModel()
{
return Mage::registry('current_model');
}
protected function _getHelper()
{
return Mage::helper('aion_customercategory');
}
protected function _prepareForm()
{
$model = $this->_getModel();
$form = new Varien_Data_Form(array(
'id' => 'edit_form',
'action' => $this->getUrl('*/*/save'),
'method' => 'post'
));
$fieldset = $form->addFieldset('base_fieldset', array(
'legend' => $this->_getHelper()->__('Category Information'),
'class' => 'fieldset-wide',
));
if ($model && $model->getId()) {
$modelPk = $model->getResource()->getIdFieldName();
$fieldset->addField($modelPk, 'hidden', array(
'name' => $modelPk,
));
}
$fieldset->addField('name', 'text', array(
'name' => 'name', 'required' => true,
'label' => $this->_getHelper()->__('Name'),
'title' => $this->_getHelper()->__('Name'),
)
);
$fieldset->addField('active', 'select', array(
'name' => 'active', 'required' => true,
'label' => $this->_getHelper()->__('Active'),
'title' => $this->_getHelper()->__('Active'),
'options' => array(
'1' => Mage::helper('adminhtml')->__('Yes'),
'0' => Mage::helper('adminhtml')->__('No'),
),
)
);
if ($model) {
$form->setValues($model->getData());
}
$this->setForm($form);
return parent::_prepareForm();
}
}
A segéd metódusok mellett a _prepareForm() függvényben adjuk a felülethez a field-eket, amelyekre szükségünk van. Most már egy látható felületünk is van, ha megtekintjük az oldalt:
Ezzel megoldottuk az új létrehozása, elem módosítása felületet, viszont tudnunk kell elmenteni is a form-on felvitt adatokat. Nincs másra szükségünk, mint a controller-ben (CustomercategoryController) egy saveAction() metódust definiálni, ami ezt meg is teszi:
...
public function saveAction()
{
$redirectBack = $this->getRequest()->getParam('back', false);
if ($data = $this->getRequest()->getPost()) {
$id = $this->getRequest()->getParam('id');
$model = Mage::getModel('aion_customercategory/category');
if ($id) {
$model->load($id);
if (!$model->getId()) {
$this->_getSession()->addError(
$this->__('This Category no longer exists.')
);
$this->_redirect('*/*/index');
return;
}
}
try {
$model->addData($data);
$this->_getSession()->setFormData($data);
$model->save();
$this->_getSession()->setFormData(false);
$this->_getSession()->addSuccess(
$this->__('The Category has been saved.')
);
} catch (Mage_Core_Exception $e) {
$this->_getSession()->addError($e->getMessage());
$redirectBack = true;
} catch (Exception $e) {
$this->_getSession()->addError(
$this->__('Unable to save the Category.')
);
$redirectBack = true;
Mage::logException($e);
}
if ($redirectBack) {
$this->_redirect('*/*/edit', array('id' => $model->getId()));
return;
}
}
$this->_redirect('*/*/index');
}
...
A mentés után már a listában is megtalálhatóak azok az elemek, amiket felvittünk:
Az általános grid funkciók a magento-ból származtatott osztály miatt már így is működnek:
- szűrés
- sorrendezés
- lapozás
Meg kell adnunk, hogy ha egy-egy sorra kattintunk, akkor milyen url-re dobjon az oldal. Ezt az Aion_Customercategory_Block_Adminhtml_Category_Grid osztályban kell megtennünk a következő metódus segítségével:
public function getRowUrl($row)
{
return $this->getUrl('*/*/edit', array('id' => $row->getId()));
}
Ahhoz, hogy a teljes funkcionalitást megvalósítsuk, a törlésre is szükség van, amit a szerkesztő form-ról érhetünk el, és automatikusan egy megerősítő popup után átirányít a deleteAction() függvényre, vagyis a controllerben ezt is meg kell valósítanunk:
public function deleteAction() { if ($id = $this->getRequest()->getParam('id')) { try { $model = Mage::getModel('aion_customercategory/category'); $model->load($id); if (!$model->getId()) { Mage::throwException($this->__('Unable to find a Category to delete.')); } $model->delete(); $this->_getSession()->addSuccess( $this->__('The Category has been deleted.') ); $this->_redirect('*/*/index'); return; } catch (Mage_Core_Exception $e) { $this->_getSession()->addError($e->getMessage()); } catch (Exception $e) { $this->_getSession()->addError( $this->__('An error occurred while deleting Category data. Please review log and try again.') ); Mage::logException($e); } $this->_redirect('*/*/edit', array('id' => $id)); return; } $this->_getSession()->addError( $this->__('Unable to find a Category to delete.') ); $this->_redirect('*/*/index'); }
Ezzel már szerkeszteni tudjuk a kategóriákat, ha módosítani kell a szerkezetet, akkor elég csak a form-ban elvenni vagy hozzáadni field-eket egyszerűen kitörölve, vagy az addField() metódust használni. Ahhoz, hogy vásárlókat tudjunk a kategóriához adni a tervezési fázisban az ajax-os tab megoldás mellett döntöttünk. Egy új tab-ot kell felvenni a Aion_Customercategory_Block_Adminhtml_Category_Edit_Tabs osztályban, ami ajaxosan tölti be a customer grid-et:
protected function _beforeToHtml()
{
...
$this->addTab('customers', array(
'label' => $this->__('Customers'),
'title' => $this->__('Customers'),
'url' => $this->getUrl(
'*/*/customerstab',
array('_current' => true)
),
'class' => 'ajax'
));
return parent::_beforeToHtml();
}
Az url kulcs alatt látható, hogy a már megvalósított controller-ünk customerstabAction metódusát hívja meg, amiben elvégezzük a szükséges műveleteket:
public function customerstabAction()
{
$saved_customer_ids = array();
//Your load logic
$this
->loadLayout()
->getLayout()
->getBlock('category.customer.tab')
->setSelectedCustomers($saved_customer_ids);
$this->renderLayout();
}
Viszont fontos, hogy mint minden admin elemnek, ennek is kell a layout.xml-ben egy leíró blokk, hogy miket tartalmazzon:
...
<adminhtml_customercategory_customerstab>
<block type="core/text_list" name="root" output="toHtml">
<block type="aion_customercategory/adminhtml_category_edit_customer_grid" name="category.customer.tab"/>
</block>
</adminhtml_customercategory_customerstab>
...
Viszont fontos, hogy mint minden admin elemnek, ennek is kell a layout.xml-ben egy leíró blokk, hogy miket tartalmazzon:
...
<adminhtml_customercategory_customerstab>
<block type="core/text_list" name="root" output="toHtml">
<block type="aion_customercategory/adminhtml_category_edit_customer_grid" name="category.customer.tab"/>
</block>
</adminhtml_customercategory_customerstab>
...
Létre kell hoznunk a szükséges block-ot, ami ebben a példában az adminhtml_category_edit_customer_grid -> Aion_Customercategory_Block_Adminhtml_Category_Edit_Customer_Grid -> app/code/local/Aion/Customercategory/Block/Adminhtml/Category/Edit/Customer/Grid.php Ahogy azt már az előző grid-ünknél is megtettük, a __construct(), _prepareCollection(), _prepareColumns() metódusokat meg kell adni:
class Aion_Customercategory_Block_Adminhtml_Category_Edit_Customer_Grid extends Mage_Adminhtml_Block_Widget_Grid { public function __construct() { parent::__construct(); $this->setId('customerGrid'); $this->setUseAjax(true); $this->setSaveParametersInSession(true); }
protected function _prepareCollection() { $collection = Mage::getResourceModel('customer/customer_collection') ->addNameToSelect();$this->setCollection($collection); return parent::_prepareCollection(); }protected function _prepareColumns() { $this->addColumn('selected_customers', array( 'header' => $this->__('Select'), 'type' => 'checkbox', 'index' => 'entity_id', 'align' => 'center', 'field_name'=> 'selected_customers[]', 'values' => $this->getSelectedCustomers(), ));$this->addColumn('customer_name', array( 'header' => $this->__('Name'), 'index' => 'name', 'align' => 'left', ));$this->addColumn('email', array( 'header' => $this->__('E-mail'), 'index' => 'email', 'align' => 'left', ));return parent::_prepareColumns(); } }
A constructorban ha setUseAjax(true), akkor értelemszerűen ajax-osan próbálja majd lekérni a grid-et, viszont ehhez meg kell adni még ebben az osztályban a gridUrl-t is:
public function getGridUrl() { return $this->getUrl('*/*/customersgrid', array('_current' => true)); }
Azonban triviálisan ez egy controller/action hívás, ezért azt is meg kell valósítani a controllerben:
Ahhoz, hogy ez az ajax-os oldal is kirenderelődjön, és ne kapjunk hibát, természetesen a layout.xml-ben meg kell adni a szükséges adatokat:public function customersgridAction() { $this ->loadLayout() ->getLayout() ->getBlock('category.customer.tab') ->setSelectedCustomers($this->getRequest()->getPost('customers', null));$this->renderLayout(); }
...
<adminhtml_customercategory_customersgrid>
<block type="core/text_list" name="root" output="toHtml">
<block type="aion_customercategory/adminhtml_category_edit_customer_grid" name="category.customer.tab"/>
</block>
</adminhtml_customercategory_customersgrid>
...
Ha ezeket megvalósítottuk, akkor már láthatjuk az ajax-osan betöltött customer grid-ünket:
A következő lépés, hogy a kiválasztott customer entitásokat el tudjuk tárolni a kategóriához, vagyis egy hidden inputba be kell az ID-kat rakni, hogy a mentéskor ezeket eltárolhassuk. Ez azért kell, mert ha csak a grid-ben kijelölt checkbox-okat vizsgálnánk, akkor a lapozáskor vagy szűréskor a már kiválasztott checkbox lehet, hogy nem jelenik meg, így nem tudnánk elküldeni a mentési folyamat részeként. Szerencsére a Magento rendelkezik megoldással erre a problémára, a tab-unkat ki kell egészíteni egy új block-kal (widget_grid_serializer), ami ezt lekezeli, és csak a legfontosabb beállításokat/módosításokat kell a kódunkban elvégezni:
...
<adminhtml_customercategory_customerstab>
<block type="core/text_list" name="root" output="toHtml">
<block type="aion_customercategory/adminhtml_category_edit_customer_grid" name="category.customer.tab"/>
<block type="adminhtml/widget_grid_serializer" name="category.customer.serializer">
<action method="initSerializerBlock">
<grid_block_name>category.customer.tab</grid_block_name>
<data_callback>getSelectedCustomerIds</data_callback>
<hidden_input_name>customer_ids</hidden_input_name>
<reload_param_name>customers</reload_param_name>
</action>
</block>
</block>
</adminhtml_customercategory_customerstab>
...
Látszik, hogy meghívja az initSerializerBlock() metódust, aminek a paraméterei:
- grid_block_name – melyik grid-re vonatkozik a szerializálás
- data_callback – milyen általunk írt metódus adja vissza a már kiválasztott azonosítókat
- hidden_input_name – mi legyen a neve az inputnak (később a post során ezzel hivatkozhatunk rá)
- reload_param_name – melyik az a paraméter, ami a már tárolt elemeket tartalmazza
Most meg kell valósítanunk az Aion_Customercategory_Block_Adminhtml_Category_Edit_Customer_Grid osztályban a getSelectedCustomerIds() függvényt, ami visszaadja a kategóriához már megadott azonosítókat:
public function getSelectedCustomerIds()
{
$returnArray = array();
//Your getter logic
return $returnArray;
}
Ezzel megvalósítottuk a betöltést, most a mentési procedúrát kell kiegészíteni a kiválasztott azonosítók letárolásával. Fontos, hogy az inputban szerializálva vannak az adatok, vagyis vissza kell fejteni, hogy azt el is tudjuk tárolni. Természetesen ezt a CustomercategoryController saveAction()-ben kell megvalósítani:
public function saveAction()
{
$redirectBack = $this->getRequest()->getParam('back', false);
if ($data = $this->getRequest()->getPost()) {
...
if ($customersIds = $this->getRequest()->getParam('customer_ids', null)) {
$customersIds = Mage::helper('adminhtml/js')
->decodeGridSerializedInput($customersIds);
//Your save logic
}
if ($redirectBack) {
$this->_redirect('*/*/edit', array('id' => $model->getId()));
return;
}
}
...
}
Végezetül egy dolog maradt még hátra, hogy teljes értékű felületet kapjunk, az, hogy az admin felhasználó tudjon szűrni a listában azokra a felhasználókra, akik ki vannak már jelölve, illetve akik nincsenek.
Ezt úgy lehet megoldani,hogy kiegészítjük az Aion_Customercategory_Block_Adminhtml_Category_Edit_Customer_Grid-et egy általunk létrehozott metódussal amit megadhatunk az oszlop hozzáadásánál, hogy mi legyen a szűrés függvénye:
$this->addColumn('selected_customers', array(
...
'filter_condition_callback' => array($this, '_selectedCustomerFilter'),
));
Vagyis a selected_customers oszlopban a szűrést a _selectedCustomerFilter() valósítsa meg:
protected function _selectedCustomerFilter($collection, $column)
{
$filter = $this->getRequest()->getParam('filter', null);
$filter_data = Mage::helper('adminhtml')->prepareFilterString($filter);
if (!$filter_data || !isset($filter_data['selected_customers'])) {
return $this;
}
$selectedCustomers = $this->getSelectedCustomers();
if (!$selectedCustomers || !is_array($selectedCustomers)) {
return $this;
}
if ($filter_data['selected_customers'] == '1') {
$operator = 'IN';
} else {
$operator = 'NOT IN';
}
$collection->getSelect()->where('e.entity_id ' . $operator . ' (' . implode(',', $selectedCustomers) . ')');
return $this;
}
Ezzel a példával könnyedén meg tudunk valósítani olyan ügyféligényeket, amikor új menüpontot, új formot, új gridet vagy dinamukus tab-okat kell létrehoznunk. Dolgozhatunk meglévő collection-ökkel vagy custom adatbázis modellekkel is. A Magento nagyon sok segítséget nyújt a megvalósítás során, rengeteg core-szinten megvalósított osztálya van, amiket csak használnunk kell, illetve kiegészíteni. Ha úgy gondolod, ez a cikk hasznos lehet másoknak is, kérjük, oszd meg. Bármilyen kérdéssel, kéréssel fordulj hozzánk bizalommal kommentben.
cialis http://www.cialislet.com/
hydroxychloroquine online https://azhydroxychloroquine.com/
naltrexone 25 mg https://naltrexoneonline.confrancisyalgomas.com/
hydroxychloroquine for sale online https://chloroquine1st.com/
prednisone price https://bvsinfotech.com/
careprost rx https://www.jueriy.com/
I think this is one of the most important information for me.
And i’m glad reading your article. But wanna remark on few general things,
The site style is wonderful, the articles is really nice : D.
Good job, cheers
I’m curious to find out what blog platform you happen to be utilizing?
I’m experiencing some minor security problems with my latest website and I’d like to find something more safeguarded.
Do you have any suggestions?
generic of januvia http://lm360.us/
cialis 20mg http://cialisoni.com/
hydroxychloroquin https://webbfenix.com/
cialis generic online pharmacy https://wisig.org/
generic viagra without subscription amazon https://viatribuy.com/
cephalexin 500 mg cap https://keflex.webbfenix.com/
Your mode of telling all in this post is truly good, every one be able to
effortlessly understand it, Thanks a lot. cheap flights 34pIoq5
Hi! I know this is sort of off-topic but I needed to ask. Does
building a well-established blog such as yours take a large amount of work?
I’m completely new to running a blog however I
do write in my journal daily. I’d like to start a
blog so I can share my personal experience and thoughts online.
Please let me know if you have any kind of suggestions or tips for new aspiring blog owners.
Appreciate it! cheap flights 31muvXS
Hey would you mind letting me know which web host you’re utilizing?
I’ve loaded your blog in 3 completely different internet browsers and I must say this blog
loads a lot faster then most. Can you recommend a good
web hosting provider at a reasonable price?
Many thanks, I appreciate it! cheap flights 2CSYEon
Woah! I’m really digging the template/theme of this
blog. It’s simple, yet effective. A lot of times it’s very
hard to get that “perfect balance” between usability and appearance.
I must say you have done a excellent job with this.
In addition, the blog loads super quick for me on Safari.
Outstanding Blog! cheap flights 31muvXS
Hello to every body, it’s my first pay a quick visit of
this blog; this webpage carries awesome and truly good data designed for readers.
I visit each day a few web sites and sites to read articles or
reviews, except this blog provides feature based articles.
https://www.adidasyeezy.co/Adidas yeezy
[url=http://www.yeezy350.uk.com/][b]Yeezy 350[/b][/url]
azithromycin dosage https://azithromycinx250.com/
[url=http://www.airmax97.us.com/][b]Air Max 97[/b][/url]
viagra without a doctor prescription not scam https://mymvrc.org/
[url=http://www.airmax97.us.com/][b]Air Max 97[/b][/url]
[url=https://www.yeezy350.de/][b]Yeezy 350[/b][/url]
win money 2019
deviant art
medical doctor database
online pharmacy
buy domains
northwest pharmacy in canada https://canadiantrypharmacy.com – internet pharmacy no prior prescription
visibly delay only the ventilator to undergo simply chief it. buy tadalafil online canada were the chief noticed resplendent in spite of upbringing activity.
Amazing loads of very good info.
http://canadian1pharmacy.com buy generic cialis online
pharmacy online http://viaciabox.com – online pharmacy online canadian pharmacy no prescription
Whoa all kinds of awesome facts., kamagra fda https://kamagrahome.com kamagra 100
Xerosis as teratogenic on an secretive-compulsiveРІdrinking musicianship goodrx cialis the Recovery Span of Cases of Active navy surgeon restrictions.
mobile county health department mobile al kamagra for cheap https://www.goldkamagra.com – kamagra 100mg oral jelly suppliers
free money
http://www.loansonline1.com payday loans online same day
Hurray! I just got $1 BitCoin, Free! Earn $10 BitCoin Coupons & Huge Referral Bonus, All Free! Join me NOW: btckick.com
See you in a bit., kamagra 100 http://www.kamagrapolo.com kamagra 100 mg oral jelly
https://www.withoutvisit.com non prescription viagra
http://www.loansonline1.com online payday loans
https://viagrabun.com – online pharmacy
best place to buy generic viagra online buy cheap viagra viagra from india
http://cialiswlmrt.com – cialis generic
http://withoutdct.com – viagra without a doctor prescription
https://cialis20walmart.com cialis lower blood pressure
http://canadian5pharmacy.com canadian pharcharmy online no precipitation
viagra without a doctor prescription usa viagra online generic viagra cost
cialis samples request cheap cialis cialis before and after
buy generic viagra online viagra viagra prescription
amoxycillin1st.com https://amoxycillin1st.com/
ed supplements how to get prescription drugs without doctor ed products
health risks associated with smoking ciggarettes
http://canadianpharmacy-md.com – canadian pharmacy
online pharmacy viagra viagra cheapest generic viagra
top rated ed pills
where to buy viagra online cheap viagra viagra
vacuum therapy for ed
viagra for sale viagra generic viagra online
viagra without a doctor prescription
primary care doctor state of colorado department of health care policy
viagra without a doctor prescription https://www.withoutdroch.com
professional medical education education medical
https://www.kamagramama.com – kamagra
erectile dysfunction pills ED Pills Without Doctor Prescription ed aids
can you catch hiv from root canal symptoms united states department of health and human resources non profit organizations
viagra without doctor prescription. http://www.doctorxep.com Opqpwmo femuck
very good put up, i definitely love this website, carry on it
erectile dysfunction natural remedies Cheap Erection Pills prescription meds without the prescriptions
latisse prescription https://carepro1st.com/
is generic cialis safe buy tadalafil high blood pressure and cialis
what is cialis used for
Cheers. Lots of knowledge.! https://www.kamagramama.com kamagra 100mg
Wow many of beneficial advice.
http://canadianpharmacy-md.com international drug mart canadian pharmacy online store
cialis vs viagra effectiveness buy tadalafil 30 day cialis trial offer
real cialis online with paypal
male dysfunction pills https://canadaedwp.com/ non prescription erection pills
Cheers. A good amount of data.. viagra no prescription
You definitely made the point.!
cialis generic
male enhancement pills https://canadaedwp.com/ errection problem cure
viagra
Thanks a bunch for sharing this with all of us you actually know what you are talking about! Bookmarked. Please also visit my site =). We could have a link exchange arrangement between us!
viagra online
does viagra add size viagra thбєЈo dЖ°б»Јc cб»§a phЖ°ЖЎng Д‘Гґng how to get viagra
foods with natural viagra https://purevigra.com can you get viagra from a walk in clinic
foods to avoid with viagra viagra commercial guy tibet viagrasД± bitkisel cialis
ivermectin 3mg tablets for scabies https://ivermectin.webbfenix.com/
clomid success story https://salemeds24.wixsite.com/clomid
Helpful info. Fortunate me I discovered your website accidentally, and I’m surprised why this twist of fate did not took place in advance! I bookmarked it.
payday loans online payday loans no credit check
indian brand viagra suppliers viagra samples free free samples to uk viagra
It’s actually a cool and useful piece of info. I am satisfied that you simply shared this helpful info with us. Please stay us informed like this. Thank you for sharing.
online pharmacy canadian pharmacy
denver viagra viagra no prescription generic viagra vs viagra
next day delivery viagra paradiseviagira.com viagra buy online paypal
vente viagra au canada https://buybuyviamen.com/ el viagra y la prostatitis
I’m impressed, I must say. Actually rarely do I encounter a weblog that’s both educative and entertaining, and let me inform you, you have hit the nail on the head. Your idea is excellent; the problem is something that not sufficient individuals are speaking intelligently about. I am very pleased that I stumbled across this in my seek for one thing regarding this.
health care insurance plans internal medicine physicians near me
viagra without a doctor prescription
viagra prescription nz
buy generic drugs drugs from india
tadalafil generic vs vidalista https://vidalista.buszcentrum.com/
canadian pharmacy online pharmacy
best replacement for silagra https://silagra.buszcentrum.com/
buy generic hydroxychloroquine https://hydroxychloroquine.mlsmalta.com/
without doctor visit vidalista generic https://vidalista.mlsmalta.com/
hydroxychloroquine coronavirus dosage https://hydroxychloroquine.webbfenix.com/
real viagra without a prescription viagra for sale from canada generic sildenafil for sale in canada
ivermectin for head lice dosage https://ivermectin.mlsmalta.com/
where can i get viagra online viagra for women in india viagra tablet purchase online
red cialis viagra kullanД±mД± almonds viagra do you need to take viagra with food
Whoa a good deal of useful info.,
cialis online
Hello There. I found your blog using msn. This is a very well written article. I will be sure to bookmark it and come back to read more of your useful information. Thanks for the post. I will certainly return.
viagra generic otc viagra soft tabs 100mg sildenafil 20 mg cost in india
Would you be all in favour of exchanging links?
instant online payday loans personal loans
canadian pharmacy
can i buy sildenafil over the counter in uk buy sildenafil 100mg uk viagra online without prescription usa
can i mix tramadol with viagra qual o valor do viagra magkano ang viagra sa pilipinas
sildenafil https://sildgeneric100.com/ sildenafil without doctor prescription
pfizer viagra 100mg paypal viagra in canada buy viagra from germany
Can I just say what a reduction to seek out somebody who actually knows what theyre speaking about on the internet. You undoubtedly know methods to carry a problem to gentle and make it important. Extra people need to read this and understand this aspect of the story. I cant imagine youre no more fashionable because you undoubtedly have the gift.
urgent essay writing service essay writing for english tests short persuasive essay
blood pressure too low how to raise,
cialis coupon
sildenafil dosage http://droga5.net/
essay writing learning objectives geography homework help with science homework
Hello! I just wanted to ask if you ever have any trouble with hackers? My last blog (wordpress) was hacked and I ended up losing many months of hard work due to no backup. Do you have any solutions to protect against hackers?
online medication canadian pharmacy
Appreciating the dedication you put into your blog and in depth information you offer. It’s great to come across a blog every once in a while that isn’t the same unwanted rehashed material. Great read! I’ve bookmarked your site and I’m adding your RSS feeds to my Google account.
best online drugstore https://sildenafilxxl.com/ how much is viagra
essays you can buy doctoral dissertation proposal essays gre
viagra price comparison generic viagra gold viagra pills 90
buy essays papers writing a persuasive speech phd thesis help
buy vidalista https://vidalista40mg.mlsmalta.com/
hypothesis of research paper essay writing toronto writing a good conclusion to a research paper
essay unity buy custom research paper sections in a research paper
professional essay writing services buy essay service assignments done for you
Do you mind if I quote a couple of your articles as long as I provide credit and sources back to your blog? My blog is in the very same area of interest as yours and my users would truly benefit from some of the information you present here. Please let me know if this okay with you. Many thanks!
canadian pharmacies
Thanks a lot. I value it.,
kamagra
writing a research paper thesis essay collection writing essay for college application
how to cure ed naturally buy Cipro ed vacuum pump
discount viagra viagra for sale viagra otc
natural herbs for ed canadian pharmacy online homepage
cialis and interaction with ibutinib cheap cialis generic cialis at walmart
viagra walgreens viagra discount viagra canada
drugs causing ed trusted india online pharmacies natural ed treatment
cialis lowest price cialis fda warning list cialis
2016 health care reform,
kamagra oral jelly
viagra without prescription
natural ed: muse ed drug medication for ed
compare ed drugs: legal to buy prescription drugs from canada erectile dysfunction medication
buy ed pills: tadalafil without a doctor’s prescription drugs prices
albuterol solution for nebulizers https://amstyles.com/
FLO does cialis cause headache cialis no prescription cialis boston
real cialis without a doctor’s prescription: best drug for ed legal to buy prescription drugs without prescription
tom ellis mens health photo shoot,
levitra for sale
Oxxx cialis vs cialis generic buy cialis australia cheap cialis online india
online ed drugs: otc ed pills treatment for erectile dysfunction
cheap medication online: buy prescription drugs without doctor medicine for erectile
pump for ed: otc ed pills ed clinic
America cost cialis walmart pharmacy cialis professional canada cialis london delivery
otc ed drugs online pharmacies in canada online drugs
how to calibrate blood pressure monitor free healthcare. viagra without doctor prescription Aorq75w qucmde
cialis no prescription arizona price of cialis at walgreens fed ex overnight delivery cialis
FLO online pharmacy cialis generic cialis 100mg cialis generic effectiveness
generic zithromax india zithromax 500 mg lowest price pharmacy online buy zithromax online cheap
viagra online sell cipla viagra review viagra on;ine
cheap generic viagra walmart viagra best place to buy generic viagra online
online medical journals,
viagra without a doctor prescription
best liquid cialis how much does cialis cost at walmart which is better – cialis or viagra
tiujana cialis normal dose cialis buy cialis online canadian
cialis prices 20mg generic cialis bitcoin cialis online
Generic
cialis users experience cialis 20mg buy cialis overseas
purchase cialis in montreal professional viagra cialis blak cialis
buying viagra or cialis min canada purchase cheap cialis soft tabs 5mg cialis
better levitra or cialis buy cialis usa generic cialis results
viagra alternative australia 365pills generic viagra generic viagra in australia
how do i get viagra online viagra super force reviews viagra online canada
the affordable care act aarp health insurance under 65. generic cialis Erppt31 gdnuem
viagra rezeptfrei comprare viagra con paypal viagra pt.
generic cialis reviews buy cialis with paypal cialis 800mg black
where to buy viagra https://genericvgr100.com can you buy viagra over the counter
how to get hiv,
viagra
purchase discount cialis online generic cialis discount cialis effecten
how to get viagra without a doctor https://genericvgr100.online how to buy viagra
plaquenil hydroxychloroquine stock market https://hydroxychloroquine.wisig.org/
what is the best viagra levitra or cialis generic levitra online pharmacy levitra atsauksmes
lonoke ocuty health department lonoke arkansas azalea health. buy cialis Ylibolx qjneri
testosterone lab test mens health,
buy cialis online
medications online buy antiviral drugs buy Valtrex
buy ed drugs online pharmacies without an rx canadian pharmacy viagra
levitra melt fiyat levitra buy online canada kako se koristi levitra
ed meds online without prescription or membership canadian prescription drugs by mail online pharmacies without an rx
buy prescription drugs from canada cheap canadian pharmacy cialis canadian pharmacy cialis
ed supplements men’s ed pills best erectile dysfunction medication
Regards. Lots of knowledge., viagra without a doctor prescription Ebkloqh.
can veterans get viagra buying viagra in n ireland viagra price
viagra young people buy viagra brand viagra northwest england
canadian drugs online canada prescription pharmacy canadian pharmacy viagra
how much is viagra viagra coupons viagra without prescription
stock for hydroxychloroquine https://hydroxychloroquinee.com/
viagra u viagra results photos buy viagra in ncanada
anti fungal pills without prescription ed treatments ed natural treatment
Generic buy cialis us pharmacy lightcaliscom cialis online without rx
when did hiv reach the united states which immune cell type does hiv usually infect?. does viagra require a prescription in usa Ofafr83 pfawnu viagra causing heart problems
cheap medications fda approved canadian online pharmacies canadian online pharmacies
Generic does va provide cialis cialis miami what dose of cialis
Seriously many of superb tips., kamagra 100mg oral jelly suppliers Ebzym54.
cialis canada tadalafil 5mg cialis
canadian drugs online online pharmacy canada canada online pharmacy
Generic cialis de cumparat generic cialis tadalafil bph
ed devices canadian pharmacies shipping to usa canadian online pharmacies
sildenafil with dapoxetine https://dapoxetine.confrancisyalgomas.com/
Generic cialis us pharmacy cialis 20mg cialis best results
vacuum pump for ed canadian online pharmacies canada online pharmacy
You actually explained this very well!, finasteride Eybpkie.
Generic generic cialis malaysia generic cialis buy cialis ontario
sjvyogkd how to buy viagra how to get viagra without a doctor
Taxi moto line
128 Rue la Boétie
75008 Paris
+33 6 51 612 712
Taxi moto paris
You should be a part of a contest for one of the finest websites online.
I am going to recommend this blog!
viagra prescription https://cheapvgr100.com/ rgtgelhy
Generic difference between doses cialis au cialis cheapest cialis internet
We stumbled over here coming from a different page
and thought I might as well check things out. I like what I see so now i’m following you.
Look forward to looking into your web page yet again.
I do not even know how I ended up here, but I thought this post was great.
I do not know who you are but certainly you are going
to a famous blogger if you aren’t already ;) Cheers!
I don’t even know how I ended up here, but I thought this post was good.
I don’t know who you are but certainly you’re going to a famous blogger if you are not already ;) Cheers!
zdrfuhwj generic viagra where to buy viagra
Generic cialis with overnight delivery cialis over night delivery cialis en pharmacie
cialis brand no prescription
pfizer viagra sales
buy cialis with dapoxetine online Atoli edido
Yqjvveqb canadian pharmaceuticals online health ca
otc acyclovir tablets acyclovir tablet zovirax pill
Its such as you read my thoughts! You appear to know a lot about this, like you wrote the e book in it or something. I feel that you could do with a few p.c. to pressure the message home a little bit, however instead of that, this is excellent blog. An excellent read. I’ll definitely be back.|
Unquestionably believe that that you stated. Your favourite reason seemed to be at the net the simplest thing
to keep in mind of. I say to you, I certainly get irked
whilst other folks think about concerns that they plainly don’t recognise about.
You controlled to hit the nail upon the highest as well as defined out the entire thing with no need
side-effects , folks can take a signal. Will likely be back to get more.
Thanks
Do you mind if I quote a couple of your posts
as long as I provide credit and sources back to your website?
My blog site is in the exact same niche as yours and my
users would really benefit from a lot of the information you provide here.
Please let me know if this alright with you. Appreciate
it!
cost of allegra 180 mg allegra gel caps coupon zyrtec 5mg
cipla india viagraAvor52y pruvux viagra without doctor prescription. celebrities that have rheumatoid arthritis dry blood hiv oxygen.
levitra andorra sin receta levitra buy generic which is best viagra or cialis or levitra
amoxicillin buy canada can you buy amoxicillin over the counter cheap bactrim
I visited multiple web pages but the audio feature for audio songs existing at this website is truly superb.|
que precio tiene levitra generic levitra buy online australia levitra administracion
zithromax for sale us where can i buy amoxicillin online generic amoxicillin
generic benadryl canada 1000 mg benadryl where to get benadryl uk
levitra generique bayer levitra buy online australia cheapest mode emploi levitra
yasmin pill canada pilex price shatavari fertility
10.00 allegra coupon periactin over the counter canada benadryl
dose massima di levitra levitra 40 mg sale can you take levitra after expiration date
yasmin 28 generic levlen canada buy yasmin
скачать сайт гидра на телефон представляет собой шоп, что придуман для магазинов незаконных вещей и услуг. Такого рода услугу сложно купить в традиционном магазине, потому что это противоправно.
vad kostar cialis pР“Тђ apoteketOaaqw87 ywi51u cialis online. bacon health risks asthma action plan pdf.
Alqsm57 canadian pharmaceuticals flu like symptoms std
alesse 28 mg how much is yasmin pill 2010 yasmin
levitra und sport levitra for sale on ebay viagra sau levitra
periactin prescription buy allegra australia best zyrtec prices
levitra and heart disease levitra wholesale no prescription levitra 10 mg orodispersible tablets
viagra compared to levitra cheap levitra buy levitra per paypal bezahlen
levitra 20 mg venezuela levitra buying levitra 30 day trial
prices of cialis http://cialisirt.online/ cialis tadalafil 20 mg mrlzhwnx
п»їcialis http://cialisirt.online/ can you have multiple orgasms with cialis gdewywoo
Udtj12c canadian pharmacy mens health products
fda warning list cialis http://cialisirt.com/ cialis tadalafil 20 mg ssuvlukf
USA
cialis indian brands cialis over night delivery pricing for cialis
over the counter viagra http://viagrastm.com/ generic for viagra ggnovfrz
Brand
buy cialis walmart cialis miami generic cialis legal us
coupon for cialis by manufacturer http://cialisirt.online/ generic cialis no doctor’s prescription lnevbett
http://canadianvolk.com
Generic
cialis india price buy cialis in australia buying cheap cialis online
Thanks – Enjoyed this article, can you make it so I get an email sent to me when you write a fresh post?
Brand
buy cialis florida cialis miami cialis helps premature
Brand
i need cialis tadalafil cialis cheap cialis eu
generic zantac for sale generic for zantac
ventolin hfa inhaler ventolin prescription online
prazosin online
viagra for sale no prescription
sildenafil actavis 50mg Atoli edido
buy zantac zantac carcinogen
amoxicillin pills 500 mg amoxicillin 500 mg cost
what causes ed legal to buy prescription drugs without prescription
cipro online business registration
2 day delivery viagra online
levitra pill review Atoli edido
http://bambulapharmacy.com
zantac generic zantac coupon
https://levitraye.com
can you buy prescription overseas https://buymeds.mlsmalta.com/
zantac coupon buy zantac
my canadian pharmacy erectile dysfunction causes drugstore
amoxicillin 500 mg purchase without prescription amoxicillin 50 mg tablets
medical pharmacy best ed medication drugstore beetle
india pharmacy best ed medication online canadian pharmacy
drugstore near me ed medication pharmacy cheap
treatments for ed https://canadarx24.com/ natural ed cures
5mg cialis https://ciaaliss.com/
http://bambulapharmacy.com
drugs prices https://canadarx24.com/ comparison of ed drugs
https://levitraye.com
us pharmacy drugs from canada canada drug pharmacy
I really appreciate this post. I’ve been looking all over for this! Thank God I found it on Bing. You’ve made my day! Thx again…
over the counter viagra los angeles
cost of viagra in chennai
viagra generic next day Atoli edido
canadian pharmacy generic viagra erectile dysfunction 24 hour pharmacy
generic viagra with overnight shipping
flos medicinae viagra
who will make generic viagra Atoli edido
http://sansordonnancefr.com – parapharmacie en ligne
You have made your stand very well.. sildenafil citrate 100mg
ed pills for sale blpvwdgz buy levitra ed natural remedies
best male enhancement apgwssiy levitra canada over the counter ed treatment
viagra canada sgqpqltl buy viagra generic viagra without a doctor prescription canada
cialis price cialis ysemyvxs cialis coupons
ed treatment review hpguedea buy levitra mens ed
cheap health insurance plans generic viagra
what is the best ed drug rvoeoqmr levitra for sale injections for ed
discount viagra leifrfqe buy viagra online cheapest generic viagra
http://withoutscript.com – medicare part d that covers viagra
hrlz viagra online http://dietkannur.org mwrg ksru
cialis v-tada 20 mg
paypal cialis
viagra viagra generics Atoli edido
when will generic levitra ba available
cialis online australia
buy viagra dr fox Atoli edido
cialis before and after 5 mg cialis coupon printable kkgmrhmx 30 day cialis trial offer
average price cialis
$200 cialis coupon cialis 20 mg best price himyaqvo 5mg cialis
viagra or cialis
what should be included in model progams for hiv/aids viagra without doctor prescription
I was suggested this website by my cousin. I am not sure whether this post is written by him as no one else know such detailed about my problem. You’re incredible! Thanks!
cialis shipping brand generic
bayviagra
farmacia on line italia cialis Atoli edido
[url=http://upsildenafil.com/]sildenafil 25 mg coupon[/url] [url=http://cialisdrug.com/]cost of cialis prescription[/url] [url=http://ordviagra.com/]can you buy viagra over the counter canada[/url] [url=http://xtadalafil.com/]buy cialis price[/url] [url=http://fildenasildenafil.com/]sildenafil 100mg price canada[/url] [url=http://levothyroxinesynthroid.com/]synthroid 150 mcg price[/url] [url=http://tetracyclineonline.com/]where can i buy terramycin eye ointment for my cat[/url] [url=http://lasixfurosemidepill.com/]furosemide 40 mg tablet cost[/url]
http://bambulapharmacy.com
generic viagra for sale viagra
viagra prescription viagra without a doctor
https://viaprescription.com/
buy prescription viagra online without buy viagra very cheap
generic viagra without a doctor prescription meds online without doctor prescription
what is tinder , how to use tinder https://tinderdatingsiteus.com/
generic viagra without a doctor prescription generic viagra for ed
buy viagra online http://viaaagra.com/
viagra Without a Doctor Prescription buy generic viagra
https://viaprescription.com/