I'm working with Yii 2, and it's grid view to show information.
Now, my problem is that whenever a user scans two identical serial numbers and/or mac addresses, it should highlight the row (change color to red), and show some error sign or whatever.
Screenshot:
What I want it to look like:
I'm new to Yii2 and don't exactly know how they do it with the grid view. I've been researching on this specific problem but couldn't find anything.
Code for Gridview
<?= GridView::widget([
'id' => 'scan-batch-grid',
'dataProvider' => $dataProvider,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
['class' => 'yii\grid\CheckboxColumn'],
[
'attribute' => 'product_ID',
'value' => 'product.name'
],
'SN',
'MAC',
[
'class' => 'yii\grid\ActionColumn',
'urlCreator' => function ($action, $model, $key, $index) {
return Url::to(['scan-batch/view', 'id' => $key, 'scan' => $model->scan_batch_ID]);
},
'buttons' => [
'update' => function ($url, $model, $key) {
return '';
},
'delete' => function ($url, $model, $key) {
return '';
},
],
],
],
]); ?>
EDIT
I only want to know how to change the color of only one row.
Got it!
Yii2 : Adding Classes to Rows in the GridView (YouTube)
Yii2 Gridview row by row css expression
Simply add rowOptions to your gridview.
<?= GridView::widget([
'id' => 'scan-batch-grid',
'dataProvider' => $dataProvider,
'rowOptions'=>function($model){
if($a == $b){
return ['class' => 'danger'];
}
},
Thanks for posting your answer Paramone. Worked great.
Here is my implementation:
<?= GridView::widget([
'dataProvider' => $dataProvider,
'rowOptions' => function ($model) {
if ($model->name == 'test') {
return ['class' => 'info'];
}
},
Related
I am building a Widget for Elementor. It's a 'basic' widget where I need to grab the value of a control. Like, if I choose a select control a method will be called and will show another select control or something. Here is what I am doing:
protected function register_controls()
{
$this->start_controls_section(
'new_section',
[
'label' => esc_html__('Settings', 'textdomain'),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
// New Select settings
$this->add_control(
'data_types',
[
'label' => esc_html__('Testimonial Type', 'textdomain'),
'type' => \Elementor\Controls_Manager::SELECT,
'options' => [
'static' => 'Static',
'dynamic' => 'Dynamic',
],
'default' => 'static',
]
);
// I want to get 'data_types' value here to call the *get_data_by_type($type)*
$this->end_controls_section();
}
public function get_data_by_type($type){
// Something will be done with the data type.
}
Maybe I'm in over my head but I'm trying to create an extension for WpGraphQL to just gather the YITH WooCommerce Product Add-Ons info for each product but I've gotten to the point of banging my head against the desk in frustration. Is there a fairly easy way to just output the array into nodes? The following is what I have so far, currently I'm only getting one product with a set ID (later, hopefully it will get the one associated with that query). I can get a simple string output but I can't get it to output the array into nodes? What am I doing wrong? I commented out ideas I had for an output but it just usually results in an error or null. I do see the graphql_debug working and outputting $fields as an array though? Thanks!
register_graphql_object_type('MyNewType', [
'description' => __('Describe the Type and what it represents', 'replace-me'),
'fields' => [
'nodes' => [
'type' => 'String',
'description' => __('Describe what this field should be used for', 'replace-me'),
'fields' => [
'form_type' => [
'type' => 'String',
'description' => __('Describe what this field should be used for', 'replace-me'),
],
],
],
],
]);
register_graphql_field(
'Product',
'YITH_fields',
[
'type' => 'MyNewType',
'description' => __('Example field added to the Post Type', 'replace-with-your-textdomain'),
'resolve' => function (\WPGraphQL\Model\Post $post) {
global $wpdb;
$sql = "SELECT wp_live_yith_wapo_types.type, wp_live_yith_wapo_types.options FROM wp_live_yith_wapo_groups JOIN wp_live_yith_wapo_types on wp_live_yith_wapo_groups.id = wp_live_yith_wapo_types.group_id WHERE FIND_IN_SET(13, products_id)";
$results = $wpdb->get_results($sql);
if ($results) {
$array = array('nodes');
//$array = array();
foreach ($results as $result) {
$type = array('form_type' => $result->type);
$options = maybe_unserialize($result->options);
$result = array_merge($type, $options);
$array[] = $result;
}
//$array = wp_json_encode($array);
$fields = !empty($array) ? $array : null;
} else {
$fields = null;
}
graphql_debug($fields, ['type' => 'ARGS_BREAKPOINT']);
//return $fields['nodes'];
return $fields;
}
]
);
Probably it's good enough to return an array of Info 'records' (without embedding into nodes subfield - it would require some, own 'InfoList' type def.), then you need a type for single Info, like:
register_graphql_object_type('MyInfoItem', [
'description' => __('Describe the Type and what it represents', 'replace-me'),
'fields' => [
'form_type' => [
'type' => 'String',
'description' => __('Describe what this field should be used for', 'replace-me'),
],
// options field - list of some scalar or custom type
'options' => [
'type' => [ 'list_of' => 'String' ],
'description' => __('Describe what this field should be used for', 'replace-me'),
],
],
]);
extend Product with:
register_graphql_field(
'Product',
'YITH_fields',
[
'type' => [ 'list_of' => 'MyInfoItem' ],
'description' => __('Example field added to the Post Type', 'replace-with-your-textdomain'),
'resolve' => function (\WPGraphQL\Model\Post $post) {
// ...
return [
['form_type' => 'some_value'],
[
'form_type' => 'other_value',
'options' => ['opt_1', 'opt_2'],
],
];
Any, not trivial data 'nesting level' requires a separate type definition.
For more complex options 'records' you need to register another type - e.g. ids required for optional option selection.
If you don't want to explicitely express these [unknown/dynamic] structures, you can use custom JSON scalar type.
I have a problem with Yii2 (as usual). I'm trying to show many buttons in a cell in GridView. I have one ticket with four possible states:
1: OPEN
2: IN PROCESS
3: CLOSED
4: EDIT
In a column (ActionColumn?) I want to display many buttons to change it's state like this:
If the state is '1', I want to show two buttons: 'In process' and 'Close Ticket'.
If state is 2, I want to show only 'Close Ticket' button -> That's OK
If it's closed (state = 3), I want to show 'Edit Ticket' button -> That's OK
If state is 4, the I'll show 'Close Ticket' button -> That's OK
This is my code of that column in my GridView. I'm only able to show one button, don't know how to do it for showing more buttons, as you can't return more than one element, or an array:
[
'label' => 'Change State:',
'format' => 'raw',
'value' => function($dataProvider){
if($dataProvider->state== '1'){
return Html::a('In Process', ['/tickets/inprocessticket', 'id' => $dataProvider->id], ['class'=>'btn btn-warning', 'id' => 'btn_inProcessTicket']);
}else if($dataProvider->state== '2'){
return Html::a('Close Ticket', ['/tickets/closeticket', 'id' => $dataProvider->id], ['class'=>'btn btn-danger', 'id' => 'btn_closeTicket']);
}else if($dataProvider->state== '3'){
return Html::a('Edit Ticket', ['/tickets/editticket', 'id' => $dataProvider->id], ['class'=>'btn btn-info', 'id' => 'btn_editTicket']);
}else if($dataProvider->state== '4'){
return Html::a('Close Ticket', ['/tickets/closeticket', 'id' => $dataProvider->id], ['class'=>'btn btn-danger', 'id' => 'btn_closeTicket']);
}
},
],
Thank you all for your help!
If you want to use yii\grid\ActionColumn you should define the buttons in $buttons property and use $visibleButtons callbacks to determine which buttons should be displayed. You can use $template property to set their order.
[
'class' => \yii\grid\ActionColumn::class,
'template' => '{process} {edit} {close}' //here will be all posible buttons
'buttons' => [
'process' => function($url, $model, $key) {
return Html::a(
'In Process',
[
'/tickets/inprocessticket',
'id' => $model->id
],
[
'class'=>'btn btn-warning',
'id' => 'btn_inProcessTicket'
]
);
},
'edit' => function($url, $model, $key) {
return Html::a(
'Edit Ticket',
[
'/tickets/editticket',
'id' => $dataProvider->id
],
[
'class'=>'btn btn-info',
'id' => 'btn_editTicket'
]
);
},
'close' => function ($url, $model, $key) {
return Html::a(
'Close Ticket',
[
'/tickets/closeticket',
'id' => $dataProvider->id
],
[
'class'=>'btn btn-danger',
'id' => 'btn_closeTicket'
]
);
},
],
'visibleButtons' => [
'process' => function($model, $key, $index) {
//the in process button should only be shown if state == 1
return $model->state == 1;
},
'edit' => function($model, $key, $index) {
//the edit button should only be shown if state == 3
return $model->state == 3;
},
'close' => function($model, $key, $index) {
//the close button should be shown in each state except of state == 3
return $model->state != 3;
},
],
]
You can find more information about ActionColumn and it's callbacks in documentation.
I am constructing a form with Drupal FAPI and is a little bit complex one. What I want to do is to put a button and add some information when the user clicks it, so I need to skip validations with that button. I'm trying to use the #limit_validation_errors property but doesn't seem to work and is executing all validations.
I've noticed that when I put the element at the root level of the form tree it does work. This is what I have:
$form['application']['education']['add_education'] = array(
'#type' => 'submit',
'#value' => 'Add',
'#submit' => array('_education_submit'),
'#limit_validation_errors' => array(),
);
The code above doesn't work, the code below works though:
$form['add_education'] = array(
'#type' => 'submit',
'#value' => 'Add',
'#submit' => array('_education_submit'),
'#limit_validation_errors' => array(),
);
It looks like Drupal is looking for the triggering_element using the value attribute to compare; as I have another button with the same value, the system is messing up the values and taking the other button as the clicked one.
To fix the code, I only have had to change the #value property of the button. It was working when I changed the position on the tree because in that case Drupal took the right button.
Here is the example of using this property:
$form['add_education'] = array(
'#type' => 'submit',
'#value' => 'Add',
'#submit' => array('submit_function'),
'#limit_validation_errors' => array(array('_education_submit')),
);
For Drupal 8, I had to switch from a type="submit" to type="button" in order to disable errors + use Ajax.
public function buildForm(array $form, FormStateInterface $form_state) {
// ...
// Create Draft Button
$form['#prefix'] = '<div id="send-emails-manual-send-by-role-wrapper">';
$form['#suffix'] = '</div>';
$form['actions']['save_draft'] = [
'#type' => 'button',
'#value' => $this->t('Save Draft'),
'#name' => 'submit__save_draft', // TODO: Make constant
'#limit_validation_errors' => [],
'#ajax' => [
'callback' => [$this, 'ajaxSubmitForm'],
'wrapper' => 'send-emails-manual-send-by-role-wrapper',
'method' => 'replace',
'effect' => 'fade',
],
];
return $form;
}
/**
* Submit the form using ajax
*/
public function ajaxSubmitForm(array &$form, FormStateInterface $form_state) {
$this->submitForm($form, $form_state);
return $form;
}
I found a great way to put the customer email address on the Magento Admin Sales Order grid via this Q&A (http://stackoverflow.com/questions/6416864/how-to-add-customer-email-to-order-grid-in-magento-1-4/6906254#6906254) by Ben Incani and it works great.
My question is: Using this method, how can I add the Ship to information (name, address, city, state, zip)?
I've tried doing two versions (that sort of work) but do not work fully so I am a bit stuck...
This is the code that works for customer emails:
$collection->getSelect()->joinLeft(array('sfo'=>'sales_flat_order'),'sfo.entity_id=main_table.entity_id',array('sfo.customer_email', 'sfo.shipping_description'));
Now, when trying to go into the database table that has the Ship to information I tried this:
$collection->getSelect()->joinLeft(array('sfoa'=>'sales_flat_order_address'),'sfoa.parent_id=sfo.entity_id',array('sfoa.postcode'));
This returns an error log with the message:
a:5:{i:0;s:68:"Item (Mage_Sales_Model_Order) with the same id "10860" already exist";i:1;s:5104:"#0
Trying this code (which most closely follows the original customer email code):
$collection->getSelect()->joinLeft(array('sfoa'=>'sales_flat_order_address'),'sfoa.entity_id=main_table.entity_id',array('sfoa.postcode'));
yields a grid that I can view with a populated column. However, the values in the column are NOT the correct Postal Codes - I can't even figure out what values it is pulling???
I guess one of my issues is that I don't exactly know what main_table.entity_id refers to (although I have a guess).
Anyway, I feel that I'm close and if someone can answer how I successfully get the information with this method, I'd be eternally grateful! Can anyone
Revised Answer (Due to two problematic errors)
I'm rewriting this answer in a more friendly, step by step way to hopefully help someone else out.
Note: This is for a local change at app/code/local/Mage/Adminhtml/Block/Sales/Order/Grid.php
A. In order to get everything working correclty, you first need to change the _getCollectionClass() from this:
protected function _getCollectionClass()
{
return 'sales/order_grid_collection';
}
to this:
protected function _getCollectionClass()
{
//return 'sales/order_grid_collection';
return 'sales/order_collection';
}
I ran into a major headache when doing this which was this:
SQLSTATE[23000]: Integrity constraint violation: 1052 Column ‘created_at’ in where clause is ambiguous
This happens when you try to filter/search the grid by the Purchase On column.
In order to avoid/fix this error, you need to change the collectioin AND add the following to _prepareCollection() AND add a filter_index to each of the columns added to the grid.
You'll also run into another headache
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'billing_name' in 'where clause'
IF in the _prepareCollection() you try to dynamically create the columns of the Billing Name or Shipping Name which looks like this:
$collection->getSelect()->columns(new Zend_Db_Expr("CONCAT(s2.firstname, ' ',s2.lastname) AS billing_name"));
$collection->getSelect()->columns(new Zend_Db_Expr("CONCAT(s1.firstname, ' ',s1.lastname) AS shipping_name"));
When this is done, there is no real easy way (that I came across to fix this), if it all.
In order to avoid these headaches (after you change the _getCollectionClass() to the above) do the following:
B. Change the _prepareCollection() to this:
protected function _prepareCollection()
{
$collection = Mage::getResourceModel($this->_getCollectionClass());
$collection->getSelect()->joinLeft(array('sfog' => 'sales_flat_order_grid'),'main_table.entity_id = sfog.entity_id',array('sfog.shipping_name','sfog.billing_name'));
$collection->getSelect()->joinLeft(array('sfo'=>'sales_flat_order'),'sfo.entity_id=main_table.entity_id',array('sfo.customer_email','sfo.weight','sfo.discount_description','sfo.increment_id','sfo.store_id','sfo.created_at','sfo.status','sfo.base_grand_total','sfo.grand_total'));
$collection->getSelect()->joinLeft(array('sfoa'=>'sales_flat_order_address'),'main_table.entity_id = sfoa.parent_id AND sfoa.address_type="shipping"',array('sfoa.street','sfoa.city','sfoa.region','sfoa.postcode','sfoa.telephone'));
$this->setCollection($collection);
return parent::_prepareCollection();
}
C. Then for the existing columns in _prepareColumns() add a filer_index to each:
Example:
$this->addColumn('billing_name', array(
'header' => Mage::helper('sales')->__('Bill to Name'),
'index' => 'billing_name',
'filter_index' => 'sfog.billing_name',
));
D. Then add the columns you want to add like this:
Example:
$this->addColumn('customer_email', array(
'header' => Mage::helper('sales')->__('Customer Email'),
'index' => 'customer_email',
'filter_index' => 'sfo.customer_email',
'width' => '50px',
));
I have a similar requirement some time back, where I need to add customer email and shipping region to the sales order grid.
For achieving the requirement I have rewritten class Mage_Adminhtml_Block_Sales_Order_Grid as below in my custom module.
class Custom_OrderGrid_Block_Adminhtml_Sales_Order_Grid extends Mage_Adminhtml_Block_Sales_Order_Grid {
protected function _getCollectionClass() {
return 'sales/order_collection';
}
protected function _prepareCollection() {
$collection = Mage::getResourceModel($this->_getCollectionClass());
$collection->getSelect()->joinLeft(array('sfog' => 'sales_flat_order_grid'), 'main_table.entity_id = sfog.entity_id', array('sfog.shipping_name', 'sfog.billing_name'));
$collection->getSelect()->joinLeft(array('sfo' => 'sales_flat_order'), 'sfo.entity_id=main_table.entity_id', array('sfo.customer_email', 'sfo.increment_id', 'sfo.store_id', 'sfo.created_at', 'sfo.status', 'sfo.base_grand_total', 'sfo.grand_total'));
$collection->getSelect()->joinLeft(array('sfoa' => 'sales_flat_order_address'), 'main_table.entity_id = sfoa.parent_id AND sfoa.address_type="shipping"', array('sfoa.region'));
$this->setCollection($collection);
return Mage_Adminhtml_Block_Widget_Grid::_prepareCollection();
}
protected function _prepareColumns() {
$this->addColumn('real_order_id', array(
'header' => Mage::helper('sales')->__('Order #'),
'width' => '80px',
'type' => 'text',
'index' => 'increment_id',
'filter_index' => 'sfo.increment_id'
));
if (!Mage::app()->isSingleStoreMode()) {
$this->addColumn('store_id', array(
'header' => Mage::helper('sales')->__('Purchased From (Store)'),
'index' => 'store_id',
'type' => 'store',
'store_view' => true,
'display_deleted' => true,
'filter_index' => 'sfo.store_id'
));
}
$this->addColumn('created_at', array(
'header' => Mage::helper('sales')->__('Purchased On'),
'index' => 'created_at',
'type' => 'datetime',
'width' => '100px',
'filter_index' => 'sfo.created_at'
));
$this->addColumn('billing_name', array(
'header' => Mage::helper('sales')->__('Bill to Name'),
'index' => 'billing_name',
'filter_index' => 'sfog.billing_name'
));
$this->addColumn('shipping_name', array(
'header' => Mage::helper('sales')->__('Ship to Name'),
'index' => 'shipping_name',
'filter_index' => 'sfog.shipping_name'
));
$this->addColumn('customer_email', array(
'header' => Mage::helper('sales')->__('Customer Email'),
'index' => 'customer_email',
'filter_index' => 'sfo.customer_email',
'width' => '50px',
));
$this->addColumn('region', array(
'header' => Mage::helper('sales')->__('Shipping State'),
'index' => 'region',
'filter_index' => 'sfoa.region',
'width' => '50px',
));
$this->addColumn('base_grand_total', array(
'header' => Mage::helper('sales')->__('G.T. (Base)'),
'index' => 'base_grand_total',
'type' => 'currency',
'currency' => 'base_currency_code',
'filter_index' => 'sfo.base_grand_total'
));
$this->addColumn('grand_total', array(
'header' => Mage::helper('sales')->__('G.T. (Purchased)'),
'index' => 'grand_total',
'type' => 'currency',
'currency' => 'order_currency_code',
'filter_index' => 'sfo.grand_total'
));
$this->addColumn('status', array(
'header' => Mage::helper('sales')->__('Status'),
'index' => 'status',
'type' => 'options',
'width' => '70px',
'filter_index' => 'sfo.status',
'options' => Mage::getSingleton('sales/order_config')->getStatuses(),
));
if (Mage::getSingleton('admin/session')->isAllowed('sales/order/actions/view')) {
$this->addColumn('action', array(
'header' => Mage::helper('sales')->__('Action'),
'width' => '50px',
'type' => 'action',
'getter' => 'getId',
'actions' => array(
array(
'caption' => Mage::helper('sales')->__('View'),
'url' => array('base' => '*/sales_order/view'),
'field' => 'order_id'
)
),
'filter' => false,
'sortable' => false,
'index' => 'stores',
'is_system' => true,
));
}
$this->addRssList('rss/order/new', Mage::helper('sales')->__('New Order RSS'));
$this->addExportType('*/*/exportCsv', Mage::helper('sales')->__('CSV'));
$this->addExportType('*/*/exportExcel', Mage::helper('sales')->__('Excel XML'));
return Mage_Adminhtml_Block_Widget_Grid::_prepareColumns();
}
}
I hope this will help others.
The reason about that error "Mage_Sales_Model_Order) with the same id "10860" already exist" it's because sales_flat_order_address creates two records for every order, one for shipping address and another one for billing address, if you add this filter on the _prepareCollection() you can make it work
$collection->getSelect()->where("address_type='shipping'");