Best way to integrate searching with pagination in cake php 3.0 - cakephp-3.0

I have a web application build on cakephp 3.x and i want to implement searching on that data also, and pagination should work according to search result.
Can anybody give the best solution ?

Let's assume you have a Articles controller and you want to paginate the articles with search as optional:
class ArticlesController extends AppController
{
public $paginate = [
'limit' => 25,
'order' => [
'Articles.title' => 'asc'
]
];
public function initialize()
{
parent::initialize();
$this->loadComponent('Paginator');
}
public function index($search = null)
{
$query = $this->Articles->find();
if($search){
$query->where(['title LIKE' => '%'.$search.'%']);
}
$this->set('articles', $this->paginate($query));
}
}

I don't know if this is the best solution.
But I'm doing this way.
In my index.ctp, I put an search form
<?= $this->Form->create('search') ?>
<fieldset>
<?php
echo $this->Form->input('Search');
?>
</fieldset>
<?= $this->Form->button(__('Submit')) ?>
<?= $this->Form->end() ?>
And in my controller
if ($this->request->is('post')) {
$pes = '%'.$this->request->data('search').'%';
$customers = $customers->where(['OR' => ['name LIKE' => $pes, 'lastname LIKE' => $pes]]);
}
Hope it works for you

Related

How to update field in user table yii2

I have modified user table to add one column, the column's name is id_periode, I have advanced template, so from backend controler i want update that column value. I create controller like this
public function actionPindahPeriode($id)
{
$model2 = $this->findModel2($id);
if ($model2->load(Yii::$app->request->post()) ) {
$model2->save();
return $this->render('view',
'model2' => $this->findModel2($id),
]);
}
date_default_timezone_set('Asia/Makassar');
$jam_sekarang = date('h:i:s', time());
$tgl_sekarang=date('Y-m-d');
$model_periode = Periode::find()
->andWhere(['>','mulai_daftar_ulang',$tgl_sekarang ])
->asArray()
->all();
return $this->renderAjax('pindah_periode', [
'model_periode' => $model_periode,
'model2' => $this->findModel2($id),
]);
}
The findModel2 function is like this
protected function findModel2($id)
{
if (($model = User::findOne($id)) !== null) {
return $model;
}
throw new NotFoundHttpException('The requested page does not exist.');
}
I render that model into a form
<?php $form = ActiveForm::begin(); ?>
<?php $listData=ArrayHelper::map($model_periode,'id',function($model_periode){
return $model_periode['nama_periode'].' Tahun '.$model_periode['tahun'];});?>
<?= $form->field($model2, 'id_periode')->dropDownList($listData, ['prompt' => '']) ?>
<div class="form-group">
<?= Html::submitButton('Save', ['class' => 'btn btn-danger']) ?>
</div>
<?php ActiveForm::end(); ?>
The form is working but i can not update the value id_periode column in table user. There is not error showing, any suggestion?
Make sure your new attribute id_periode has a rule defined in the public function rules(){} function, this way $model2->load(Yii::$app->request->post()) will assign this value from the data submitted.
$model->save() returns a bool value whether the record was saved or not. You can use this to your advantage and check whether there are any validation errors.ie:
if($model2->save()) {
return $this->render('view',
'model2' => $this->findModel2($id),
]);
} else {
return $this->renderAjax('pindah_periode', [
'model_periode' => $model_periode,
'model2' => $this->findModel2($id),
]);
}
Option 1 : Check your column fields in User model's validation rules. You need to shift unwanted column fields from required attribute to safe attribute.
Option 2 : try $model2->save(false);. false will override your model rules.

How to upload several files using Yii2

Following code just uploads one file instead several files.
Any ideas, how to fix that?
Here is my model:
<?php
//Code programmed by Thomas Kipp
//Change it, learn it, do as u please!
///path:/models/
namespace frontend\models;
use Yii;
use yii\base\Model;
class myScriptForm extends Model{ // A new Class programmed by Thomas Kipp
...
public $avatar;
...
public function rules() {
$avatar=array();
return [
['avatar[]','file']]
}
}
//End of class
?>
Here is my method of SiteController:
public function actionScript() { //A new method, programmed by Thomas Kipp
$model = new myScriptForm();
if ($model->load(Yii::$app->request->post()) && $model->validate()) {
$model->avatar = UploadedFile::getInstances($model, 'avatar[]');
if ($model->avatar) {
echo "<font size='4'><br><center>File <font color='red'> "
. "$model->avatar<font color='black'> successfully uploaded."
. "<br>It's available in folder 'uploadedfiles' </font></font color></center>";
$model->avatar->saveAs(Yii::getAlias('#uploadedfilesdir/' . $model->avatar->baseName . '.' . $model->avatar->extension));
} else
echo"<font size='4'><br><center>No Upload-file selected.<br>"
. "Nothing moved into folder 'uploadedfiles' </font></center>";
return $this->render('myScript', ['model' => $model]);
}
else {
return $this->render('myScript_Formular', ['model' => $model]);
}
}
and still my Formular, which is not uploading several files:
<?=
$form->field($model,'avatar[]')->widget(FileInput::classname(), ['options' => ['accept' => 'image/*', 'multiple' => true],])
?>
First of all, if you have something like echo (...) in controller - youre doing something wrong.
In your code youre not doing any foreach over uploaded files, so it's saving only one.
Yii2 - Uploading Multiple Files - here you have full guide how to upload multiple files, with examples etc.
Below code works for me, hope this will help you,
View file =>
<?= $form->field($model, 'image_files[]')->fileInput(['multiple' => true,'accept' => 'image/*']) ?>
Controller =>
$imagefiles = UploadedFile::getInstances($model, 'image_files');
$model->image_files = (string)count($imagefiles);
if (!is_null($imagefiles)) {
$dirpath = dirname(getcwd());
foreach ($imagefiles as $file) {
$productimage = new ProductImages();
$productimage->image_name = '/admin/uploads/'.$file->baseName.'.'.$file->extension;
$productimage->product_id = $model->id;
if ($productimage->save()) {
$file->saveAs($dirpath . '/admin/uploads/' . $file->baseName . '.' . $file->extension);
}
}
}

How to create a new input field which would offer values stored in different database table? Yii2

It's pretty hard to formulate the question correctly, but I'll try to explain it more here. I have an Item, Category and Sale models. In category and Item models I manually stored data. Now I've created a form, which has some input fields and dependent drop-down, which is:
According to the selected category, items are loaded.
Now I need to create a new input field, which would be price and it has to be taken from the database as a offer (f.e if the user selects Item1 -> Item1 price has to be loaded up as a offer in the input field, which I could edit it and store in different database table.
How should I do that?
Here is my SaleController action:
/**
* Creates a new sale
*
* #return string
*/
public function actionCreate()
{
$model = new Sale();
$model->scenario = Sale::SCENARIO_CREATE;
$category = new Category();
$category->scenario = Category::SCENARIO_CREATE;
$categoryList = ArrayHelper::map(Category::find()->all(), 'id', 'name');
if ($model->load(Yii::$app->request->post())) {
if ($model->save()) {
return $this->redirect(['index']);
}
}
return $this->render('create', [
'model' => $model,
'category' => $category,
'categoryList' => $categoryList,
]);
}
And here is my view:
<?= $form->field($category, 'id')->dropDownList($categoryList, [
'id' => 'category-id',
'prompt' => 'Choose a category',
]); ?>
<?= $form->field($model, 'item_id')->widget(DepDrop::classname(), [
'options'=>['id'=>'item-id'],
'pluginOptions'=>[
'depends'=>['category-id'],
'placeholder'=> 'Choose an item',
'url'=>Url::to(['/sale/subcat'])
]
]); ?>
<?= $form->field($model, 'price') ?>
Thank you for any help. I hope you understand the question
First you must add an input field in your view from model:
<?= $form->field($model, 'item_price')->textInput([
'maxlength' => true,
'id' => 'input-price-id'
]) ?>
Then you need to add some javascript:
<?php
$item_price=<<<JS
$('#item-id').on('change', function(event) {
var id = $(this).attr('id');
var val = $(this).val();
.get(
// you must code function actionRefreshPrice wtih parameter named item_id in
// your controller with fetch from any table you want
'refresh-price',
{
item_id: val // this is id from your item
},
function (data) {
// here you set a value returned from ajax call
// you must have an input element with id input-price-is (change as you like)
$('#input-price-id').val(data);
}
);
});
JS;
$this->registerJs($item_price);
?>
Then you must add a controller action something like this:
public function actionRefreshPrice($item_id) {
// I asume you have table with Price for items prices
$price = Price::findOne(['item_id'=>$item_id]);
return ($price?0:$price->price_field);
}
I hope I have given you enough guidelines. And a comment learn more about models and relations. I think you overthought problem a little bit. Happy learning and coding.

Yii2: How to map a CSV string in an attribute to CheckboxList in a form?

I have a model with an attribute that holds a CSV string.
(The model is actually an ActiveRecord object but I guess this is not important. Correct me if I'm wrong.)
/**
* #property string $colors Can be something like "red" or "red,green,blue" or ""
*/
class Product extends Model {
}
And I have a form in which I'd like to display this attribute as a checkboxList so that the user can select the possible values with simple clicks instead of typing into a textInput.
Theoretically, it should look similar to this:
<?php $availableColors = ['red' => 'Red', 'green' => 'Green', 'blue' => 'Blue']; ?>
<?php $form = ActiveForm::begin([]); ?>
<?= $form->field($model, 'colors')->checkboxList($availableColors) ?>
<?php ActiveForm::end(); ?>
This does obviously not work since the field colors would need to be an array. But in my model it is a string.
What would be a good way to achieve that? With JS or pseudo attributes? The colors attribute must not be changed since it is already used in other contexts that shouldn't be modified.
You can override beforeValidate method in your model, to implode your colors array into string. In your view you can use following:
<?= $form->field($model, 'colors')->checkboxList($availableColors,
[
'item'=> function ($index, $label, $name, $checked, $value) use ($model) {
$colors = explode(';', $model->colors);
$checked = in_array($value, $colors);
return Html::checkbox($name, $checked, [
'value' => $value,
'label' => $label,
]);
}
]) ?>
CSV is a file format used for moving tabular data between programs that natively operate on incompatible formats. Using it as a model attribute is not very elegant (to say it nicely). In my opinion you should have started out storing your colors in an array.
That being said you can achieve converting the array data from the dropdown list to CSV using the beforeValidate() function in your model:
public function beforeValidate() {
$this->colors = explode(';', $this->colors);
return parent::beforeValidate();
}
I think this is a PHP question, but anyway you can use PHP explode for build the array you need. See here for more details and then user the array inside the checkboxList
Now I solved it with an extra model for the form. This seems to me a proper solution.
/**
* #property string $colors Can be something like "red" or "red,green,blue" or ""
*/
class Product extends Model {
}
/**
* #property string[] $colorsAsArray
*/
class ProductForm extends Product {
public function rules() {
return array_merge(parent::rules(), [
['colorsAsArray', 'safe'] // just to make it possible to use load()
]);
}
public function getColorsAsArray() {
return explode(',', $this->colors);
}
public function setColorsAsArray($value) {
$this->colors = self::implode($value);
}
protected static function implode($value) {
if ($value == 'none-value') return '';
return implode(',', $value);
}
/* - - - - - - - - - - optional - - - - - - - - - - */
public function attributeLabels() {
$attributeLabels = parent::attributeLabels();
return array_merge($attributeLabels, [
'colorsAsArray' => $attributeLabels['colors'],
]);
}
}
With this I can use the form that way:
<?php $availableColors = ['red' => 'Red', 'green' => 'Green', 'blue' => 'Blue']; ?>
<?php $form = ActiveForm::begin([]); ?>
<?= $form->field($model, 'colorsAsArray')
->checkboxList($availableColors, ['unselect' => 'none-value']) ?>
<?php ActiveForm::end(); ?>
Of course, now the controller has to use the inherited model class.
The solution deals also with the issue if no checkbox is selected. That is why 'none-value' is introduced.

How to send parameter from a Create Form to the Action in yii2

Ok, i'm trying to make a survey tool.
So, i have a Model of the survey which reference to N questions. This is part of this model:
<?php
namespace app\models;
use Yii;
/**
* #return \yii\db\ActiveQuery
*/
public function getIdmateria0()
{
return $this->hasOne(Monmateria::className(), ['id' => 'idmateria']);
}
/**
* #return \yii\db\ActiveQuery
*/
public function getMonpreguntas()
{
return $this->hasMany(Monpregunta::className(), ['idencuesta' => 'id']);
}
}
Of course, the questions's model Monpregunta references the survey's model. Then i have a 1 to N relations between the survey and his questions.
In my ActionView i have a survey with N questions on it. Then i call a view of survey, which have a Create Form View rendered on it, in order to create the N answers of the survey. So, once question is responded, I need to know which number of question was. I need to keep the track of which number of questions i am responding, but for it i need to send a parameter from the form to my controller. But i do not know how to do it.
The Controller (here i need to keep the track of which questions is responded)
public function actionView($id)
{
//this is my id's survey
$model = $this->findModel($id);
//here i pre create my answer
$modelResultado = $this->crearResultado($id);
//here i call the view with a Create Form embedded. When the form action it's triggered
return $this->render('view', [
'model' => $model,
'modelResultado'=>$modelResultado,
'orden'=>$model->orden,
]);
}
//create the answer and setting the reference
protected function crearResultado($id) {
$modelResul = new \app\models\Monresultado;
$modelResul->idmonresultadocab = $id;
if ($modelResul->load(Yii::$app->request->post()) && $modelResul->save()) {
//flash
}
return $modelResul;
}
The view
<?php
use yii\helpers\Html;
use yii\widgets\DetailView;
/**
* #var yii\web\View $this
* #var app\models\Monresultadocab $model
*/
?>
<div class="monresultadocab-view">
<?= DetailView::widget([
'model' => $model,
'attributes' => [
'id',
'idencuesta',
],
]) ?>
<?php
echo $this->render('_formResultado', [
'model' => $modelResultado
]); ?>
</div>
[b]This is the _formResultado view, and here i wish to tell to the action which id's questions has been responded but i don't know how to send the parameter to the action!![/b]
<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
use yii\helpers\ArrayHelper;
/**
* #var yii\web\View $this
* #var app\models\Monresultado $model
* #var yii\widgets\ActiveForm $form
*/
?>
<div class="monresultado-form">
<?php $form = ActiveForm::begin(); ?>
<?= $form->field($model, 'idrespuesta')->dropDownList(ArrayHelper::map(\app\models\Monrespuesta::find()->all(),'id','nombre'))?>
<?= $form->field($model, 'libre')->textInput(['maxlength' => 2000]) ?>
<div class="form-group">
[b]<?= Html::submitButton($model->isNewRecord ? 'Siguiente' : 'Siguiente', ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>[/b]
</div>
<?php ActiveForm::end(); ?>
</div>
If i send a parameter in the Html::submitButton tag, it doesn't work.
Thanks
i think u should pass the id of corresponding question in actionView of controller
like:
return $this->render('view', [
'model' => $this->findModel($id),
......
......
]);
hope it works!