Use setQueriedColumns on GridField - php

I have a dataobject which I want to use on a GridField on a page but I want to limit the columns displayed. I used setQueriedColumns() to list the fields I wanted but it is still displaying the default $summary_fields from the dataobject.
MyActivity dataobject:
class MyActivity extends DataObject{
private static $db = array(
'Title' => 'Varchar(255)',
'URLSegment' => 'Varchar(512)',
'IsPublished' => 'Boolean',
'IsPublic' => 'Boolean',
'IsBooked' => 'Boolean',
'MaxDuration' => 'Int',
'PricePoint' => 'Int',
'Summary' => 'HTMLText',
'Body' => 'HTMLText',
'Sort' => 'Int'
);
private static $has_one = array(
'FileAttachment' => 'File'
);
private static $summary_fields = array(
'Title' => 'Name',
'URLSegment' => 'URLSegment',
'IsPublished' => 'Published',
'IsBooked' => 'Booked',
'Events.Count' => 'List of Events',
'Categories.Count' => ' of Categories'
);
static $has_many = array(
'Events' => 'MyEvent'
);
static $belongs_many_many = array(
'Categories' => 'MyCategory'
);
...
}
MyActivityPage:
class MyActivityPage extends Page{
public function getCMSFields(){
$fields = parent::getCMSFields();
$GridFieldConfig = GridFieldConfig_RecordEditor::create();
$fields->addFieldToTab('Root.Courses',
GridField::create(
'FileAttachment',
'Activity List',
MyActivity::get()->filter(['IsPublished' => 1])
->setQueriedColumns([
'Title',
'URLSegment',
'IsPublished'
]),
$GridFieldConfig
)
);
return $fields;
}
...
}

After thorough searching, I got what I'm looking for. Apparently, we can set the columns using GridFieldConfig then limit the fields by overriding the $summary_fields using the setDisplayFields() method in the GridFieldDataColumns object.
This could be handy to people who are looking for similar solution.
$gridField = GridField::create(
'FileAttachment',
'Activity List',
MyActivity::get()->filter(['IsPublished' => 1]),
$GridFieldConfig
)
$gridField->getConfig()
->getComponentByType('GridFieldDataColumns')
->setDisplayFields([
'Title' => 'Title',
'URLSegment' => 'URLSegment',
'IsPublished' => 'IsPublished'
]);
$fields->addFieldToTab('Root.Courses',$gridField);`

Related

Silverstripe 3.4 gridfieldextensions GridFieldEditableColumns

I am using gridfieldextensions and GridFieldEditableColumns on a GridFieldConfig_RelationEditor.
How can the GridField - Actions be moved to the right?
[![enter image description here][1]][1]
class StaffCatObject extends DataObject
private static $many_many = array(
'Staffs' => 'Staff'
);
private static $many_many_extraFields = array(
'Staffs' => array(
'SortOrder' => 'Int',
'Display' => 'Boolean(1)'
),
);
public function getCMSFields() {
$fields = parent::getCMSFields();
.......
$GridFieldConfig = GridFieldConfig_RelationEditor::create();
$GridFieldConfig->removeComponentsByType('GridFieldPaginator');
$GridFieldConfig->addComponent(new GridFieldPaginator(20));
$GridFieldConfig->addComponent(new GridFieldEditableColumns());
$GridFieldConfig->addComponent( new GridFieldDeleteAction());
$items = $this->Staffs();
if (class_exists('GridFieldOrderableRows') && !$items instanceof UnsavedRelationList) {
$GridFieldConfig->addComponent(new GridFieldOrderableRows('SortOrder'));
}
$gridfield = new GridField("Staff", $this->StaffCatTitle, $this->Staffs()->sort('SortOrder'), $GridFieldConfig); //->sort('SortOrder')
$gridfield->getConfig()->getComponentByType('GridFieldEditableColumns')->setDisplayFields(array(
'Display' => array(
'callback' => function ($record, $column, $gridfield) {
return new CheckboxField('Display');
},
'title' => 'Display'
),
'AdImpressum' => array(
'title' => 'Ad Impressum',
'field' => 'CheckboxField'
)
));
$fields->addFieldToTab('Root.Main', $gridfield);
return $fields;
class Staff extends DataObject
private static $belongs_many_many = array(
'StaffCatObjects' => 'StaffCatObject'
);
static $summary_fields = array(
'Thumbnail' => 'Thumbnail',
'StaffTitle' => 'Name',
'Email' => 'Email',
'CheckDisplay' => 'wird angezeigt in'
);
You are appending the end of the GridField. One solution is to empty the Actions column with the following code:
$config->removeComponentsByType('GridFieldDeleteAction');
$config->removeComponentsByType('GridFieldEditButton');
Just after creating the GridField, and then readd them after adding GridFieldEditableColumns with the following code:
$config->addComponent(new GridFieldEditButton());
$config->addComponent(new GridFieldDeleteAction());
Hint:
Your first initialization is unnecessary:
$GridFieldConfig = GridFieldConfig_RelationEditor::create();
$GridFieldConfig->removeComponentsByType('GridFieldPaginator');
$GridFieldConfig->addComponent(new GridFieldPaginator(20));
$GridFieldConfig->addComponent(new GridFieldEditableColumns());
$GridFieldConfig->addComponent( new GridFieldDeleteAction());
It can be done with just:
$GridFieldConfig = GridFieldConfig_RelationEditor::create(20);
More info here: https://github.com/silverstripe/silverstripe-framework/blob/3.4.5/forms/gridfield/GridFieldConfig.php#L232

Silverstripe 3.1 - Export Dataobject with all relations?

I need to export the whole data of an dataobject. Database fields and relations.
private static $db = array (
'URLSegment' => 'Varchar(255)',
'SKU' => 'Text',
'Title' => 'Text',
'Price' => 'Text',
'Content' => 'HTMLText',
'ItemConfig' => 'Int',
'Priority' => 'Int'
);
private static $has_one = array (
'Visual' => 'Image'
);
private static $has_many = array (
'Sizes' => 'ShopItem_Size',
'Colors' => 'ShopItem_Color'
);
private static $many_many = array (
'Visuals' => 'Image',
'Categories' => 'ShopCategory'
);
I added everything to getExportFields(). But as expected the result for the relations is "ManyManyList" or "HasManyList"
public function getExportFields() {
return array(
'SKU' => 'SKU',
'Title' => 'Title',
'Price' => 'Price',
'Content' => 'Content',
'ItemConfig' => 'ItemConfig',
'Visual' => 'Visual',
'Visuals' => 'Visuals',
'Sizes' => 'Sizes',
'Colors' => 'Colors',
'Categories' => 'Categories'
);
}
Is it possible to create such an export?
Thank you in advance
You can use any method name instead of a field/relation name in the exportFields array.
In your ModelAdmin class
public function getExportFields() {
return array(
'SKU' => 'SKU',
'Title' => 'Title',
'CategoryNames' => 'Categories'
);
}
and just have a method with that name on the DataObject, returning the relation data as a string:
public function CategoryNames(){
$catNames = array();
foreach($this->Categories() as $cat){
$catNames[] = $cat->getField('Title');
}
//use a separator that won't break the CSV file
return join("; ", $catNames);
}
I think this is even way better than the modeladmin creating magic fields in your CSV file,
that would make it inconsistent...

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.

Working with Fieldset class and ORM in FuelPHP

First : sorry for my long message.
I'm trying to learn Fuel, but I have some problems with Fieldset class and Orm.
I've create a Model which extends ORM, in order to get an automatic generated form, according to my database.
My Model
class Model_Product extends \Orm\Model
{
protected static $_table_name = 'products';
protected static $_properties = array(
'id' => array(
'data_type' => 'int'
),
'name' => array(
'data_type' => 'varchar',
'label' => 'Name',
'validation' => array(
'required', 'trim', 'max_length'=>array(30), 'min_length'=>array(3)
),
),
'description' => array(
'data_type' => 'varchar',
'label' => 'Description',
'validation' => array(
'max_length' => array(290)
),
'form' => array(
'type' => 'textarea'
),
),
'price' => array(
'data_type' => 'integer',
'label' => 'Price',
'validation' => array(
'required', 'trim', 'valid_string' => array('numeric','dots')
),
),
'pic' => array(
'data_type' => 'varchar',
'label' => 'Path to the pic',
'validation' => array(
'required', 'trim'
),
),
'registered' => array(
'data_type' => 'date',
'label' => 'Registration date',
'validation' => array(
'required', 'trim'
) //'valid_string' => array('numeric','dashes')
),
);
} //end of class Model_Product
Then I create the controller which will validate the form.
My function from the controller
function action_add()
{
$fieldset = Fieldset::forge('add_product')->add_model('Model_Product')->repopulate();
$form = $fieldset->form();
$form->add('submit', '', array('type' => 'button', 'value' => 'Add item', 'class' => 'button-link' ));
$validation = $fieldset->Validation();
if($validation->run() === true)
{
$fields = $fieldset->validated();
//create a new Product, with validated fields
$product = new Model_Product;
$product->name = $fields['name'];
$product->description = $fields['description'];
$product->price = $fields['price'];
$product->pic = $fields['pic'];
$product->registered = $fields['registered'];
try
{
//if the product is successfully inserted in the database
if($product->save())
{
Session::set_flash('success', 'Product successfully added !');
\Response::redirect('products/product_details/'.$product->id);
}
}
catch(Exception $e)
{
Session::set_flash('error', 'Unable to save the product into the database !'.$e->getMessage());
}
}
//If the validation doesn't pass
else
{
Session::set_flash('error', $fieldset->show_errors());
}
$this->template->set('content', $form->build(), false);
} // end of method add()
My first question :
How and where in my function from controller can i add a 'fieldset' tag with a specific class, in order to 'beautify' my auto-generated form ?
Let's say
<fieldset class="add_product">
Second question :
What do I have to do in order to correctly validate de 'price' field, because in MySQL is set as decimal(5,2), but when I'm trying to validate with my actual validation rule, it doesn't pass (it works only with integer values Ex.: 42, but not with decimal Ex.: 42.35). I have tried to change the type from 'integer' to 'double', but it doesn't work .
If you can point to some specific documentation regarding my problems, which I possible didn't read yet, please do feel free.
Gabriel
I can answer the first question To change the automatically generated form you will need to copy fuel/core/config/form.php to the fuel/app/config directory and edit this file to suit your needs.

Using yii with dynamic data and highcharts

Hi everybody thanks for reading i was wandering how you can insert dynamic data into the highcharts extension for example i have the highcharts extension as follows (location of code =>Reprting/index):
$this->Widget('ext.highcharts.HighchartsWidget', array(
'options'=>array(
'credits' => array('enabled' => false),
'title' => array('text' => $graphTitle),
'xAxis' => array(
'categories' => array('Apples', 'Bananas', 'Oranges')
),
'yAxis' => array(
'title' => array('text' => 'Fruit eaten')
),
'series' => array(
array('name' => 'Jane', 'data' => array(3, 6, 7)),
array('name' => 'John', 'data' => array(5, 7, 3))
) )));
And i have the following code in the controller :
public function actionIndex()
{
$model= $this->loadModel();
$dataProvider=new CActiveDataProvider('Reporting');
$graphTitle= 'Price Per Product';
$this->render('index',array(
'dataProvider'=>$dataProvider, 'graphTitle'=>$graphTitle, 'model'=>$model,
));
}
And the following code is the model :
class Reporting extends CActiveRecord
{
public static function model($className=__CLASS__)
{
return parent::model($className);
}
/**
* #return string the associated database table name
*/
public function tableName()
{
return '{{price}}';
}
/**
* #return array validation rules for model attributes.
*/
public function rules()
{
// NOTE: you should only define rules for those attributes that
// will receive user inputs.
return array(
array('id_product, id_channel', 'required'),
array('id_product, id_channel', 'numerical', 'integerOnly'=>true),
array('price_min, price_max', 'numerical'),
// The following rule is used by search().
// Please remove those attributes that should not be searched.
array('id_price, id_product, id_channel, price_min, price_max', 'safe', 'on'=>'search'),
);
}
/**
* #return array relational rules.
*/
public function relations()
{
// NOTE: you may need to adjust the relation name and the related
// class name for the relations automatically generated below.
return array(
'idChannel' => array(self::BELONGS_TO, 'Channel', 'id_channel'),
'idProduct' => array(self::BELONGS_TO, 'Product', 'id_product'),
);
}
public function attributeLabels()
{
return array(
'id_price' => __('Id Price'),
'id_product' => __('Id Product'),
'id_channel' => __('Id Channel'),
'price_min' => __('Price Min'),
'price_max' => __('Price Max'),
);
}
public function search()
{
$criteria=new CDbCriteria;
$criteria->compare('id_price',$this->id_price);
$criteria->compare('id_product',$this->id_product);
$criteria->compare('id_channel',$this->id_channel);
$criteria->compare('price_min',$this->price_min);
$criteria->compare('price_max',$this->price_max);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
}
How do i put this all together to achieve a dynamically driven graph
One sample for you:
<?php
$xAxis = array(1,2,3);
$yAxis = array(4,5,6);
$this->Widget('ext.highcharts.HighchartsWidget',
array(
'id' => 'something',
'options'=> array(
'chart' => array(
'defaultSeriesType' => 'bar',
'style' => array(
'fontFamily' => 'Verdana, Arial, Helvetica, sans-serif',
),
),
'title' => array(
'text' => 'title',
),
'xAxis' => array(
'title' => array(
'text' => 'xTitle,
),
'categories' => $xAxis,
'labels' => array(
'step' => 1,
'rotation' => 0,
'y' => 20,
),
),
'yAxis' => array(
'title' => array(
'text' => 'yTitle,
),
),
'series' => array(
array(
'name' => 'seriesName',
'data' => $yAxis,
'shadow' => false,
)
)
)
)
);
?>
To customize it, you'll have to build your own $yAxis, $xAxis arrays, and modify title and settings. For more info, take a look at the official Highcharts doc.

Categories