CGridView styling specific column, inserting <div> inside <td> elements - php

I’m trying to apply custom styling to specific columns generated by CGridView. I need to insert inside the elements, but I can’t figure out how to do it.
Here is the view file:
<div id="shortcodes" class="page">
<div class="container">
<!-- Title Page -->
<div class="row">
<div class="span12">
<div class="title-page">
<h2 class="title">Available Products</h2>
</div>
</div>
</div>
<!-- End Title Page -->
<!-- Start Product Section -->
<div class="row">
<?php
$this->widget('bootstrap.widgets.TbGridView', array(
'id' => 'products-grid',
'dataProvider' => $dataProvider,
'ajaxUpdate' => TRUE,
'pager' => array(
'header' => '',
'cssFile' => false,
'maxButtonCount' => 25,
'selectedPageCssClass' => 'active',
'hiddenPageCssClass' => 'disabled',
'firstPageCssClass' => 'previous',
'lastPageCssClass' => 'next',
'firstPageLabel' => '<<',
'lastPageLabel' => '>>',
'prevPageLabel' => '<',
'nextPageLabel' => '>',
),
'columns' => array(
'id',
'name',
'category',
'brand',
'weight_unit',
'price_unit',
'flavors',
array(
'name' => 'providers',
'htmlOptions' => array('class' => 'label label-info'),
),
),
));
?>
</div>
<!-- End Product Section -->
</div>
</div>
So I want to style the column named “providers”. Using htmlOptions does add the class to the td column, but the alignment of the column is getting out of place. That’s why I wanted to wrap it inside a <div>, to apply the proper alignments and styling.
Right now it appears like this:
<tr class="even">
<td>414</td>
<td>Owl Book</td>
<td>Night Owl Trance</td>
<td>Binaural Beats</td>
<td> 400 Grams</td>
<td>$569.66</td>
<td>Ether</td>
<td class="label label-info">Shrooms.com</td>
</tr>
What I was looking to do is this:
<tr class="even">
<td>414</td>
<td>Owl Book</td>
<td>Night Owl Trance</td>
<td>Binaural Beats</td>
<td> 400 Grams</td>
<td>$569.66</td>
<td>Ether</td>
<td><div class="label label-info">Shrooms.com</div></td>
</tr>
So, how would I do this? Is there an option for it? As far as I know, htmlOptions will only add attributes to the element.

Not tested, but I think you can use something like this.
'flavors',
array(
'name' => 'providers',
'value' => "<div class=label label-info>$data->providers</div>"
),

Ok, i first tried redGREENblue's answer, but i gives a Undefined variable: data
'value' => ''.$data->providers.'',.
Then after some advice in the Yii forums i found the solution. Basically what i did was return the value from within a function closure, and it worked,
The working code ::
<div id="shortcodes" class="page">
<div class="container">
<!-- Title Page -->
<div class="row">
<div class="span12">
<div class="title-page">
<h2 class="title">Available Products</h2>
</div>
</div>
</div>
<!-- End Title Page -->
<!-- Start Product Section -->
<div class="row">
<?php
$this->widget('bootstrap.widgets.TbGridView', array(
'id' => 'products-grid',
'dataProvider' => $dataProvider,
'filter' => $dataProvider->model,
'ajaxUpdate' => TRUE,
'pager' => array(
'header' => '',
'cssFile' => false,
'maxButtonCount' => 25,
'selectedPageCssClass' => 'active',
'hiddenPageCssClass' => 'disabled',
'firstPageCssClass' => 'previous',
'lastPageCssClass' => 'next',
'firstPageLabel' => '<<',
'lastPageLabel' => '>>',
'prevPageLabel' => '<',
'nextPageLabel' => '>',
),
'columns' => array(
'id',
'name',
'category',
'brand',
'weight_unit',
'price_unit',
'flavors',
array(
'name' => 'providers',
'value' => function($data) { //*the closure that works*
return '<div class="label label-info">'.$data->providers.'</div>';
},
'type' => 'raw',
),
),
));
?>
</div>
<!-- End Product Section -->
</div>

Related

CakePHP 4 FormProtector instance has not been created error

I am currently in the process of updating a (rather big) application from CakePHP 3 to 4.
I have this template:
<?= $this->Form->create(
$dmpLayer,
[
'url' => [
'controller' => 'DmpLayers',
'action' => 'edit',
],
]
); ?>
<div class="row">
<div class="col-4">
<?= $this->element('DataLayers/layer-table'); ?>
</div>
<div id="form-div" class="col-6">
<div class="layer-form">
<?= $this->element('DataLayers/form') ?>
</div>
</div>
<div class="col-2">
<div class="layer-form">
<h2>Form Actions</h2>
<?= $this->Form->submit('Create/Update Layer', ['class' => 'btn btn-success']); ?>
</div>
</div>
</div>
<?= $this->Form->end(); ?>
<?= $this->Html->script('data-layers'); ?>
which includes the DataLayers/form element:
<div class="row">
<div class="col-12">
<h4>Artist Layer</h4>
<?php
echo $this->Html->tag('fieldset', $this->element(
'actions/add',
[
'url' => [
'prefix' => 'Admin',
'plugin' => false,
'controller' => 'SegmentCores',
'action' => 'add',
],
]
)
. $this->Form->control('artist_layer.segment_cores[]', [
'multiple',
'options' => $segmentCores,
'label' => 'Segment Core',
'value' => $selectedValues['segment_cores'],
])
. $this->Form->control('artist_layer.segment_potentials[]', [
'multiple',
'options' => $segmentPotentials,
'label' => 'Segment Potential',
'value' => $selectedValues['segment_potentials'],
])
. $this->Form->control('artist_layer.layer_tags[]', [
'multiple',
'options' => $layerTags,
'label' => 'Artist Tag',
'value' => $selectedValues['artist_tags'],
])
. $this->Form->control('artist_layer.genres[]', [
'empty' => 'No genre set',
'options' => $genres,
'label' => 'Genre',
'value' => $selectedValues['genres'],
]);
?>
</div>
</div>
<?php
$this->Form->unlockField('artist_layer.genres');
$this->Form->unlockField('artist_layer.segment_cores');
$this->Form->unlockField('artist_layer.segment_potentials');
$this->Form->unlockField('artist_layer.layer_tags');
?>
In the initialize function of the AppController I have this:
$this->loadComponent('Security');
When I visit the page, it doesn't render and I immediately get this error:
FormProtector instance has not been created. Ensure you have loaded the FormProtectionComponent in your controller and called FormHelper::create() before calling FormHelper::unlockField()
This is the only form in my application for which this error happens. Every other form is working fine, and I am calling the Form->unlockField() function in many of them.
I am obviously calling Form->create() in my code, so is this because I am including an element to add fields to the form that is defined in the "main" template? Or is there some other explanation?
I have already attempted adding
$this->loadComponent('FormProtection');
to my AppController, but this causes a whole lot more problems in many other places in the app, and it doesn't solve the problem anyway (the page renders, but I get an error when submitting the form to save the data).

Active Record in Yii2, Joining multiple table, find the rating of a thread, and retrieve the rating in ListView

I am confused with how to retrieve data that has been averaged after joining multiple tables.
Problem:
I have 3 tables i want to join, User, Thread, and Rate.
I need all data from the tables and for rate table, i need to do average operation to get the rating value
My code is:
MyController looks like this:
public function actionHome(){
$dataProvider = new ActiveDataProvider([
'query' => Thread::retrieveAll(),
'pagination' => [
'pageSize' =>5,
],
]);
return $this->render('home', ['listDataProvider' => $dataProvider]);
}
My active record class (model class) looks like this:
public static function retrieveAll(){
return Self::find()->joinWith('user')
->joinWith('rate')
->select(['AVG(rate.rating) as rating, thread.*, user.*'])
->groupBy('rate.thread_id');
}
public function getUser(){
return $this->hasOne(User::className(), ['id' => 'user_id']);
}
public function getRate(){
return $this->hasMany(Rate::className(), ['thread_id' =>'thread_id']);
}
Retrieve all is used in the data provider query
My home class looks like this:
<div class="col-md-6">
<?= ListView::widget([
'dataProvider' => $listDataProvider,
'options' => [
'tag' => 'div',
'class' => 'list-wrapper',
'id' => 'list-wrapper',
],
'layout' => "{summary}\n{items}\n{pager}",
'itemView' => function ($model, $key, $index, $widget) {
return $this->render('_list_thread',['model' => $model]);
},
'pager' => [
'firstPageLabel' => 'first',
'lastPageLabel' => 'last',
'nextPageLabel' => 'next',
'prevPageLabel' => 'previous',
'maxButtonCount' => 3,
],
]) ?>
</div>
my item for the listview looks like this:
<article>
<div class="box col-md-12">
<div class="row">
<?= Html::a($model->title, Url::to('thread/index.php?id='. $model->thread_id))?>
</div>
<div class="row">
<p> <?= $model->content ?> </p>
</div>
<div class="row">
<div class="col-md-5">
<?= StarRating::widget([
'name' => 'rating_2',
'value' => 2.5,
'readonly' => true,
'pluginOptions' => [
'showCaption' => false,
'min' => 0,
'max' => 5,
'step' => 1,
'size' => 'xs',
]])?>
</div class="col-md-7" align="center center-vertical">
<p align="right" style="font-size:8px">Created by <?= $model->user->first_name?> <?=$model->user->last_name?> at <?= $model->date_created ?></p>
</div>
</div>
<br><br><br>
<br><br><br><br><br><br><br><br><br>
</article>
I can retrieve $model->user->first_name and lst_name but i cannot retrieve $model->rate->rating
Any suggestion for this?
$this::select('AVG(rate.rating) as rating',*)->innerJoin('rate','your codition on you have to take a join')->innerJoin('thread','your codition on you have to take a join')->all()->groupBy('rate.thread_id');

links__system_main_menu in drupal

what is the use of links__system_main_menu in drupal?
<?php if ($main_menu): ?>
<div id="main-menu" class="navigation">
<?php print theme('links__system_main_menu', array(
'links' => $main_menu,
'attributes' => array(
'id' => 'main-menu-links',
'class' => array('links', 'clearfix'),
),
'heading' => array(
'text' => t('Main menu'),
'level' => 'h2',
'class' => array('element-invisible'),
),
)); ?>
</div> <!-- /#main-menu -->
This is a pattern for theme hook, in the form [base hook]__[context]. When links theme with theme('links__system_main_menu', $variables), theme() function search for *theme_links__system_main_menu()* and use it. Otherwise, if it doesn't find, it will use *theme_links()*. For more information check the theme Doc

Passing data from gridview button to modal window

I am trying to pass data from a button within a gridview to a modal window. I need to pass the ID of the record in order to be able to reference it after submitting the form within the modal window.
I am struggling with this quite a bit. First I need to be able to pass the ID variable to the modal, and then upon clicking the submit button make an ajax call to create a new record within the DB.
The Gridview
if(isset($results)){
$this->widget('bootstrap.widgets.TbExtendedGridView', array(
'id'=>'searchgrid',
'fixedHeader' => true,
'headerOffset' => 40, // 40px is the height of the main navigation at bootstrap
'type'=>'condensed',
'dataProvider'=>$results,
'responsiveTable' => true,
'template'=>"{items}",
'columns'=>array(
array('name'=>'title', 'header'=>'Name'),
array('name'=>'city', 'header'=>'City'),
array('name'=>'state', 'header'=>'State'),
array('name'=>'leads', 'header'=>'Leads', 'value'=>'Parkslist::model()->leadRange($data["leads"])'),
array('name'=>'pastbid', 'header'=>'Previous', 'value'=>'Parkslist::model()->pastBid($data["pasthighbid"])'),
array('name'=>'currentbid', 'header'=>'Current', 'value'=>'Parkslist::model()->highBid($data["currenthighbid"], $data["secondhighbid"], $data["countcurrenthighbid"])'),
array('name'=>'minimumbid', 'header'=>'Minimum', 'value'=>'Parkslist::model()->minimumBid($data["currenthighbid"], $data["secondhighbid"], $data["countcurrenthighbid"])'),
array('name'=>'userhighbid', 'header'=>'Your Bid'),
array('name'=>'placebid', 'header'=>'Bid', 'value'=>'CHtml::textField("bid" . $data["id"])', 'type'=>'raw'),
array('name'=>'report', 'header'=>'Report',
'value'=>function($data){
$this->widget('bootstrap.widgets.TbButton', array(
'label' => 'Click me',
'type' => 'primary',
'htmlOptions' => array(
'data-toggle' => 'modal',
'data-target' => '#myModal',
'data-id' => '$data["id"]',
),
));
}
),
),
));
}
The Modal
<?php
$this->beginWidget('bootstrap.widgets.TbModal', array('id' => 'myModal')); ?>
<div class="modal-header">
<a class="close" data-dismiss="modal">×</a>
<h4>Why should this park be removed?</h4>
</div>
<form>
<div class="modal-body">
<select>
<option>Duplicate</option>
<option>Closed</option>
</select>
</div>
<div class="modal-footer">
<?php $this->widget('bootstrap.widgets.TbButton', array(
'type' => 'primary',
'buttonType'=>'submit',
'label' => 'Save changes',
'url' => '#',
'htmlOptions' => array('data-dismiss' => 'modal'),
)); ?>
<?php $this->widget('bootstrap.widgets.TbButton', array(
'label' => 'Close',
'url' => '#',
'htmlOptions' => array('data-dismiss' => 'modal'),
)); ?>
</div>
</form>
<?php $this->endWidget(); ?>
I was able to get this working. I would assume there might be a better solution but this seems to work.
First, inside of the button in the gridview I made the button ID = to the id of the record. Next, I created a javascript function called includeData and included the button ID.
Button Code
array('name'=>'report', 'header'=>'Report',
'value'=>function($data){
$this->widget('bootstrap.widgets.TbButton', array(
'label' => 'Click me',
'type' => 'primary',
'htmlOptions' => array(
'id'=>$data["id"],
'data-toggle' => 'modal',
'data-target' => '#myModal',
'data-id' => '$data["id"]',
'onClick' => 'includeData(this.id);'
),
));
}
),
JS Code
<script type='text/javascript'>
function includeData(parkid){
$('#reportparkid').val(parkid);
}
</script>
The JS function just sets the value of a hidden field equal to the buttonid. I would love to see some better ways to handle this.
Thanks

Using CakePHP FormHelper with Bootstrap Forms

CakePHP's FormHelper is how you generate forms when making CakePHP applications. As one might assume, this includes generating input elements, like so:
$this->Form->input('abc');
Which will produce HTML something like this:
<div class="input text">
<label for="ModelAbc">Abc</label>
<input name="data[Model][Abc]" class="" maxlength="250" type="text" id="ModelAbc">
</div>
Now, sadly, Bootstrap wants something like the following:
<div class="control-group">
<label for="ModelAbc" class="control-label">Abc</label>
<div class="controls">
<input name="data[Model][Abc]" class="" maxlength="250" type="text" id="ModelAbc">
</div>
</div>
How do I make CakePHP produce this output?
Inspired by lericson's answer, this is my final solution for CakePHP 2.x:
<?php echo $this->Form->create('ModelName', array(
'class' => 'form-horizontal',
'inputDefaults' => array(
'format' => array('before', 'label', 'between', 'input', 'error', 'after'),
'div' => array('class' => 'control-group'),
'label' => array('class' => 'control-label'),
'between' => '<div class="controls">',
'after' => '</div>',
'error' => array('attributes' => array('wrap' => 'span', 'class' => 'help-inline')),
)));?>
<fieldset>
<?php echo $this->Form->input('Fieldname', array(
'label' => array('class' => 'control-label'), // the preset in Form->create() doesn't work for me
)); ?>
</fieldset>
<?php echo $this->Form->end();?>
Which produces:
<form...>
<fieldset>
<div class="control-group required error">
<label for="Fieldname" class="control-label">Fieldname</label>
<div class="controls">
<input name="data[Fieldname]" class="form-error" maxlength="255" type="text" value="" id="Fieldname"/>
<span class="help-inline">Error message</span>
</div>
</div>
</fieldset>
</form>
I basically added the 'format' and 'error' keys, and added the control-label class to the label element.
Here's a solution for Bootstrap 3
<?php echo $this->Form->create('User', array(
'class' => 'form-horizontal',
'role' => 'form',
'inputDefaults' => array(
'format' => array('before', 'label', 'between', 'input', 'error', 'after'),
'div' => array('class' => 'form-group'),
'class' => array('form-control'),
'label' => array('class' => 'col-lg-2 control-label'),
'between' => '<div class="col-lg-3">',
'after' => '</div>',
'error' => array('attributes' => array('wrap' => 'span', 'class' => 'help-inline')),
))); ?>
<fieldset>
<legend><?php echo __('Username and password'); ?></legend>
<?php echo $this->Form->input('username'); ?>
<?php echo $this->Form->input('password'); ?>
</fieldset>
<?php echo $this->Form->end(__('Login')); ?>
In case a field needs its own label:
<?php echo $this->Form->input('username', array('label' => array('text' => 'Your username', 'class' => 'col-lg-2 control-label'))); ?>
Here's one way:
<?php echo $this->Form->create(null, array(
'inputDefaults' => array(
'div' => array('class' => 'control-group'),
'label' => array('class' => 'control-label'),
'between' => '<div class="controls">',
'after' => '</div>',
'class' => '')
)); ?>
Your answer is correct, but for the benefit of other users there's some other tweaks you can do to take advantage of the error/help text:
Add form-horizontal to class in the Form->create() for more compact forms (labels on the left of the input, rather than on top)
Here's how to put help text underneath a field (has to be done for each field), not forgetting to close the </div>.
echo $this->Form->input('field_name', array(
'after'=>'<span class="help-block">This text appears
underneath the input.</span></div>'));
and to correctly display errors:
// cake 2.0
echo $this->Form->input('abc', array(
'error' => array('attributes' => array('class' => 'controls help-block'))
));
Outputs:
<div class="control-group required error">
<label for="ModelAbc" class="control-label">Abc</label>
<div class="controls">
<input name="data[Model][Abc]" class="" maxlength="250" type="text" id="ModelAbc">
</div>
<!-- error message -->
<div class="controls help-block">This is the error validation message.</div>
<!-- error message -->
</div>
It's extra mark-up and not as neat as bootstrap but it's a quick fix. The alternative is to do each error message individually.
and it lines up nicely. I haven't discovered an easy way to make use of inline messages yet however.
Applying the same principle as above to the form->end function as follows:
<?php echo $this->Form->end(array(
'label' => __('Submit'),
'class' => 'btn',
'div' => array(
'class' => 'control-group',
),
'before' => '<div class="controls">',
'after' => '</div>'
));?>
To produce:
<div class="control-group">
<div class="controls">
<input class="btn" type="submit" value="Submit">
</div>
</div>
small add for another comments:
if you whant add class and change label base text, you can write next
<?php echo $this->Form->input('Fieldname', array(
'label' => array('class' => 'control-label','text'=>'HERE YOU LABEL TEXT')
)); ?>
I had the same problem using slywalker / cakephp-plugin-boost_cake, I open a ticket and he had it fix in a few hours, he updated to 1,03 and told me to use it like this
<?php echo $this->Form->input('email', array(
'label' => array(
'text' => __('Email:'),
),
'beforeInput' => '<div class="input-append">',
'afterInput' => '<span class="add-on"><i class="icon-envelope"></i></span></div>'
)); ?>
I hope it helps some one else too
To get it working with a horizontal form in bootstrap with bootswatch I had to use:
echo $this->Form->create(
'User',
array(
'action' => 'add',
'admin' => 'false',
'class' => 'form-horizontal',
'inputDefaults' => array(
'format' => array( 'before', 'label', 'between',
'input', 'error', 'after' ),
'class' => 'form-control',
'div' => array( 'class' => 'form-group' ),
'label' => array( 'class' => 'col-lg-2 control-label' ),
'between' => '<div class="col-lg-10">',
'after' => '</div>',
'error' => array( 'attributes' => array( 'wrap' => 'span',
'class' => 'text-danger' ) ),
)
)
);
Then you can just use it as normal:
echo $this->Form->input( 'User.username' );
Luc Franken posted this link in his comment: http://github.com/slywalker/cakephp-plugin-boost_cake
It took me a while to notice it, so for those who are still looking for the simplest solution:
Simply add the CakePHP Bootstrap plugin from GitHub and let the helper do the job for you!

Categories