HelperList status action with ajax - php

I'm in charge of creating a small payment module. The configuration has to be managed with a simple CRUD, and I use the HelperList class to display a table with the records stored in the database.
One of the tables database structure is similar to this
'CREATE TABLE IF NOT EXISTS '._DB_PREFIX_.'MODULE_ITEM
(
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(100) NOT NULL,
`active` VARCHAR(3) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE='._MYSQL_ENGINE_.' DEFAULT CHARSET=utf8;'
So, the list_fields value is like this
array(
'id' => array(
title' => $this->l('Id'),
//'width' => 140,
'type' => 'text',
'align' => 'center'
),
'name' => array(
'title' => $this->l('Name'),
//'width' => 140,
'type' => 'text',
'align' => 'center'
),
'active' => array(
'title' => $this->l('Status'),
//'width' => 140,
'active' => 'statusItem',
'type' => 'boolean',
'align' => 'center',
'ajax'=> true
)
);
As I intend to enable or disable the item via a button I use the 'active' and 'ajax' options for this specific field, and when rendered in the module configuration page the link generated for the column in question is something like: index.php?controller=AdminModules&configure=Example&item_id=4&statusItem&action=statusItem&ajax=1&(...). Please notice that statusItem is the name of the action.
On the other hand, I wrote this function in the module main file, which should change the item status.
public function ajaxProcessStatusItem()
{
$id=(int)Tools::getValue('item_id');
$value=(int) Db::getInstance()->executeS($this->createSelectQuery('module_item','item_id',$id))[active];
Db::getInstance()->update('module_item', array('active' => !$value), 'item_id='.$id);
die();
}
I've been using this article of the official documentation to create the list, but no matter what name I use ('ajaxProcess', 'ajaxProcessSatusItem', 'statusItem', and every caps variation I could think of) all I get is a blank page in response, and no change in the status. I had a look at the source code and there is no comment in the HelperList class regarding how the function should be called.
Any help will be appreciated.

If you use ObjectModel class for your data object, you can autmatically generate toggle button just by adding one line:
AdminProductTabController.php or when defining fields somwehre else
and calling HelperList->generate()
'active' => array(
'title' => 'Active',
'active' => 'status',
'filter_key' => '!active',
'type' => 'bool',
'width' => 'auto',
'orderby' => false,
'search' => false,
)
Line 'active' => 'status', doesn't refer to any field names. Add this line to your list definition (if you're defining list field properties in Admin{YourObjectModel}Controller or calling HelperList from somewhere else).
An excerpt from my ObjectModel:
ProductTab.php
class ProductTab extends ObjectModel {
.......
public static $definition = array(
..........
'active' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool',),
I looked up my code and I noticed that I actually called a special processing function:
AdminProductTabController.php
public function initProcess()
{
$id_product_tab = (int)Tools::getValue('id_product_tab');
$product_tab = new ProductTab($id_product_tab);
$isStatusAction = Tools::getIsset('status'.$this->table);
if ($isStatusAction)
{
$product_tab->toggleStatus();
Tools::redirectAdmin($this->href_back);
}
}
Hope this will help you out.

Related

Add New Back Office Field In Prestashop

How can i add a new field in prestashop's back office?
Specific, i want to insert a text field in the BO: Orders->Statuses->Add New Order Status under the status name. Which files i have to modify in order to do that? Can anyone describes the full procedure?
Thanks
I am using Prestashop version 1.6.1.2 and added one text field using following steps. You need to make changes in core files. You have to add field in one table in database and do some changes in class and controller file.
Here are the steps to do the same. I have adde field 'my_custom_field'.
Add one field in order_state table
ALTER TABLE {YOUR_DB_PREFIX}order_state ADD my_custom_field VARCHAR(50) NOT NULL;
Change class file of order state. You need to define your field in file "classes/order/OrderState.php"
After code
public $deleted = 0;
add this code snipet
public $my_custom_field;
After code
'deleted' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
add this code snipet
'my_custom_field' => array('type' => self::TYPE_STRING),
open "controllers/admin/AdminStatusesController.php" file and do following changes
in function initOrderStatutsList()
after this code
'name' => array(
'title' => $this->l('Name'),
'width' => 'auto',
'color' => 'color'
),
add this code
'my_custom_field' => array(
'title' => $this->l('My Custom Field'),
'width' => 'auto',
),
in function renderForm()
after this code
array(
'type' => 'text',
'label' => $this->l('Status name'),
'name' => 'name',
'lang' => true,
'required' => true,
'hint' => array(
$this->l('Order status (e.g. \'Pending\').'),
$this->l('Invalid characters: numbers and').' !<>,;?=+()##"{}_$%:'
)
),
add this code
array(
'type' => 'text',
'label' => $this->l('My Custom field'),
'name' => 'my_custom_field',
),
Do changes suggested here. Hope this helps you :)

Yii display multiple Child elements as links in a CGridView Field

I have the following table:
CREATE TABLE "place" (
"id" int8 NOT NULL DEFAULT nextval('place_id_seq'::regclass),
"name" varchar(128) NOT NULL,
"parent" int8,
"description" varchar(100)
)
WITH (OIDS=FALSE);
(It's PostgreSQL but this shouldn't be relevant here)
I created the CRUD through giix and changed a bit the relations to match my needs. So I ended up with:
public function relations() {
return array(
'parent0' => array(self::BELONGS_TO, 'Places', 'parent'),
'places' => array(self::HAS_MANY, 'Places', 'parent'),
);
}
The goal here is that a place can belong to another place and have multiple children places.
My problem is that I need to change the admin action to match the following grid:
Print manipulated by the inspector to reflect the desired behaviour
So my problem is to get the list of all the children objects and display it as a list of links. I tried change the respective admin.php view file for:
$this->widget('zii.widgets.grid.CGridView', array(
'id' => 'places-grid',
'dataProvider' => new CActiveDataProvider('Places', array('id'=>$model->places)),
'filter' => $model,
'columns' => array(
array(
'name'=>'parent',
'value'=>'GxHtml::valueEx($data->parent0)',
'filter'=>GxHtml::listDataEx(Places::model()->findAllAttributes(null, true)),
),
'name',
'places',
array(
'class' => 'CButtonColumn',
),
),
));
But this, as expected, throughs an error:
htmlspecialchars() expects parameter 1 to be string, array given
Also I don't know this would even work with the built in avanced search.
Could anyone kindly point me into the correct direction here?
After much search I found a way to solve my problem. Not sure if it's the best way but it works nicely:
$this->widget('zii.widgets.grid.CGridView', array(
'id' => 'places-grid',
'dataProvider' => new CActiveDataProvider('Places', array('id'=>$model->places)),
'filter' => $model,
'columns' => array(
array(
'name'=>'parent',
'value'=>'GxHtml::valueEx($data->parent0)',
'filter'=>GxHtml::listDataEx(Places::model()->findAllAttributes(null, true)),
),
'name',
array(
'header'=>'Children',
'type'=>'html',
'value'=> function($data) {
$placesLinks = array();
foreach ($data->places as $place) {
$placesLinks[] = GxHtml::link(GxHtml::encode(GxHtml::valueEx($place, 'name')), array('places/view', 'id' => GxActiveRecord::extractPkValue($place, true)));
}
return implode(', ', $placesLinks);
}
),
array(
'class' => 'CButtonColumn',
),
),
));
This uses Giix. If you don't use that then you'll have to change the link generation accordingly.
Cheers

Associating an item to multiple other items (of a different class) using Prestashop's backoffice

Having just arrived at Prestashop 1.5, I am making a very simple module: a video of the week, associated with multiple products that need to appear right next to it.
I decided to start from the Backoffice. Right now, I can view, add, edit and remove all the Video entries but I'm a bit lost on how to map the N-N association between a video and its related products... The lack of documentation isn't helping either.
Any ideas how to pull this off?
Here's a bit of my code, the Video class is defined by:
class Video extends ObjectModel {
public $id_video;
public $title;
public $url;
public $active;
public static $definition = array(
'table' => 'video',
'primary' => 'id_video',
'multilang' => false,
'fields' => array(
'id_video' => array(
'type' => ObjectModel :: TYPE_INT
),
'title' => array(
'type' => ObjectModel :: TYPE_STRING,
'required' => true
),
'url' => array(
'type' => ObjectModel :: TYPE_STRING,
'required' => true
),
'active' => array(
'type' => ObjectModel :: TYPE_BOOL,
'required' => true
)
),
);
(...)
and the AdminVideo class is here:
class AdminVideoController extends ModuleAdminController {
public function __construct()
{
$this->table = 'video';
$this->className = 'Video';
$this->lang = false;
$this->fields_list['id_video'] = array(
'title' => $this->l('ID'),
'align' => 'center',
);
$this->fields_list['title'] = array(
'title' => $this->l('Title'),
'width' => 'auto'
);
$this->fields_list['url'] = array(
'title' => $this->l('URL'),
'width' => 'auto'
);
$this->fields_list['active'] = array(
'title' => $this->l('Active'),
'width' => '70',
'align' => 'center',
'active' => 'status',
'type' => 'bool',
'orderby' => false
);
parent::__construct();
}
public function postProcess()
{
parent::postProcess();
}
public function renderList()
{
$this->addRowAction('edit');
$this->addRowAction('delete');
$this->addRowAction('details');
return parent::renderList();
}
public function renderForm()
{
if (!($obj = $this->loadObject(true)))
return;
$this->fields_form = array(
'legend' => array(
'title' => $this->l('This weeks video'),
'image' => '../img/admin/world.gif'
),
'input' => array(
array(
'type' => 'text',
'label' => $this->l('Nome'),
'name' => 'title',
'size' => 33,
'required' => true,
'desc' => $this->l('Title')
),
array(
'type' => 'text',
'label' => $this->l('URL'),
'name' => 'url',
'size' => 33,
'required' => true,
'desc' => $this->l('Video URL')
),
array(
'type' => 'radio',
'label' => $this->l('Active:'),
'name' => 'active',
'required' => false,
'class' => 't',
'is_bool' => true,
'values' => array(
array(
'id' => 'active_on',
'value' => 1,
'label' => $this->l('Enabled')
),
array(
'id' => 'active_off',
'value' => 0,
'label' => $this->l('Disabled')
)
),
'desc' => $this->l('Only one video can be active at any given time')
),
)
);
if (Shop::isFeatureActive())
{
$this->fields_form['input'][] = array(
'type' => 'shop',
'label' => $this->l('Shop association:'),
'name' => 'checkBoxShopAsso',
);
}
$this->fields_form['submit'] = array(
'title' => $this->l(' Save '),
'class' => 'button'
);
if (!($obj = $this->loadObject(true)))
return;
return parent::renderForm();
}
}
One other thing: would it be possible to add a preview of the video inside the backoffice? I tried to echo YouTube's embed code, but it gets inserted even before the header. Is there a clean way of doing this or do I have to use some jQuery trickery? I was basically doing an echo of YT's embed code just before the end of postProcess().
Thanks in advance!
The simplest way to associate the videos to the products is by adding a "products" text field in your "video" table to store a comma separated list of the ids of the associated products (eg.: 1,10,27). Even if it's a bit rudimentary, it should work.
Alternatively, you could use a table like this:
create table video_product (
id_association int not null auto_increment,
id_video int,
id_product int,
primary key (id_association)
);
The problem with this solution is that the PrestaShop ObjectModel core does not provide any method to automatically update or delete the related tables (at least as far as I know), so you have to insert the code to manage the "video_product" table in your "Video" class.
If you want an example of how to do this, you should look at the classes/Product.php script, which manages the product table and all its related tables (categories, tags, features, attachments, etc.).
To have an idea of how the Prestashop database is structured, have a look at the docs/dbmodel.mwb file, which contains the schema of the database; this file can be viewed by using the MySQL Workbench application.

File property in an drupal entity class?

How can I store a file in a drupal entity? I have a plublic key to associate to an user so I have created an APIuser entity but I don't know what kind of field give to the public key property
function api_user_schema() {
$schema['api_user'] = array(
'description' => 'The base table for api_user.',
'fields' => array(
'id' => array(
'description' => 'The primary identifier for an artwork.',
'type' => 'serial',
'unsigned' => TRUE,
'not null' => TRUE,
),
'public_key' => array(
'description' => 'The primary identifier for the public key.',
'type' => ???,
'unsigned' => TRUE,
'not null' => TRUE,
)
'created' => array(
'description' =>
'The Unix timestamp when the api_user was created.',
'type' => 'int',
'not null' => TRUE,
'default' => 0,
),
'changed' => array(
'description' =>
'The Unix timestamp when the api_user was most recently saved.',
'type' => 'int',
'not null' => TRUE,
'default' => 0,
),
),
'unique keys' => array(
'id' => array('id')
),
'primary key' => array('id'),
);
return $schema;
}
What you've got there is the definition of a single database table; Drupal offers no layer on top of that for files, so if you want to store a file you'll have to do so manually.
The best example you can take is that of the core user entity. It defines the picture property, which is an ID referencing an entry in the file_managed table (incidentally this is how all permanent file storage is handled by Drupal core by default).
This is the schema definition for that db column (from user_schema()):
'picture' => array(
'type' => 'int',
'not null' => TRUE,
'default' => 0,
'description' => "Foreign key: {file_managed}.fid of user's picture.",
)
Which is very similar to what your definition will need to look like.
From there, have a look at the user_account_form() function (which defines the form element for the picture property), and the user_validate_picture() function, which will show you how to perform the file upload, save the file in the file_managed table, and change the submitted value for the picture field to the relevant file ID (so that it automatically gets saved against the entity).
You'll mostly be replicating the code from those two functions so it won't be that tricky.

Add source model to attribute in magento

I created an install script to add two fields to customer using the script below.
But I get this error.
Source model "" not found for attribute "dob_month"
Am I not defining the model in the first line? What does that actually do? What is the best way to fix this?
$setup = new Mage_Eav_Model_Entity_Setup('core_setup');
$setup->addAttribute('customer', 'dob_month', array(
'label' => 'Month',
'type' => 'varchar',
'input' => 'dropdown',
'visible' => true,
'required' => true,
'position' => 1,
'option' => array (
'value' => array (
'optionone' => array('January'),
'optiontwo' => array('February'),
'optionthree' => array('March'),
'optionfour' => array('April'),
'optionfive' => array('May'),
'optionsix' => array('June'),
'optionseven' => array('July'),
'optioneight' => array('August'),
'optionnine' => array('September'),
'optionten' => array('October'),
'optioneleven' => array('November'),
'optiontwelve' => array('December')
)
)
));
$setup->addAttribute('customer', 'dob_year', array (
'label' => 'Year',
'type' => 'varchar',
'input' => 'text',
'visible' => true,
'required' => true,
'position' => 1
));
If you've already added the attribute, you'll want to use updateAttribute to set the source model value in the eav_attribute table.
<?php
$installer = Mage::getResourceModel('customer/setup','default_setup');
/***
* When working with EAV entities it's important to use their module's setup class.
* See Mage_Customer_Model_Resource_Setup::_prepareValues() to understand why.
*/
$installer->startSetup();
$installer->updateAttribute(
'customer',
'dob_month',
'source_model', //a.o.t. 'source'
'whatever/source_model',
)
$installer->endSetup();
If not, then you can use addAttribute(), which - due to the Mage_Eav setup class' _prepareValues() method - requires an alias for the source_model column as indicated in Alexei's answer ('source' as opposed to 'source_model').
Source model is used when Magento needs to know possible values of your attribute. For example, when rendering dropdown for your attribute. So no, you're not defining it. If my memory doesn't fail me, you can do that by adding 'source' to attribute definition array. Something like:
...
'source' => 'eav/entity_attribute_source_table'
...
That will mean that all your possible options are stored in tables eav_attribute_option and eav_attribute_option. So if your options from install script are successfully added to these tables, that should work. Or you can write your own source model, which I prefer more.

Categories