So I have a dataprovider which is created in a controller like this:
$modelSearch = new SearchModel();
$data_provider = $modelSearch->search(Yii::$app->request->queryParams); // returns the data provider
Then I use the $data_provider in a view like this:
GridView::widget([
'dataProvider' => $data_provider,
'export' => false,
'columns' => [
...
],
...
But now I'd like to use the same data from the $data_provider but without pagination and other sorting specifications.
Tried this but doesn't work:
$data_provider->sort = ['defaultOrder'=> ['column_a' => SORT_ASC, 'column_b' => SORT_DESC]]
$data_provider->pagination = false;
I think that's because the data is already retrieved with the ->search() method. Do I need to create a whole new search model class? just to get a different sorting?
Thanks in advance!
You should use two dataProvider eg:
$modelSearch = new SearchModel();
$data_provider = $modelSearch->search(Yii::$app->request->queryParams);
$data_provider2 = $data_provider;
$data_provider2->pagination = false;
$data_provider2->sort = ['defaultOrder'=> ['column_a' => SORT_ASC, 'column_b' => SORT_DESC]]
return $this->render('your_view', [
'searchModel' => $searchModel,
'dataProvider' => $data_provider,
'dataProvider2' => $data_provider2,
]);
Before I asked the question I didn't know the dataProvider already retrieved the data on creation. So altering properties of the dataProvider doesn't do another search, it does different sorting but with the same data it already retrieved.
Answer:
I ended up making a new method in the searchModel class like this:
public function searchByCreatedAt() {
$query = Model::find()->orderBy(['created_at' => SORT_ASC]);
$dataProvider = new ActiveDataProvider([
'query' => $query,
'pagination' => false,
]);
...
}
Related
I use yii2 and I want to make gridview column 'description' sortable in a case insensitive way. There is my code:
$dataProvider = new ArrayDataProvider([
'allModels' => $query->find(),
'sort' => [
'attributes' => ['name','description],
],
'pagination' => [
'pageSize' => $this->pageSize,
],
]);
When I click on column description to sort, it show like this:
Job Title
Doctor
Teacher
doctor
teacher
As you see it sort case sensitive I want to sort case Insensitive, how I can do that? Any idea?
In order to sort rows of ArrayDataProvider in a case-insensitive way you should extend ArrayDataProvider itself, because internally it uses ArrayHelper::multisort and if you want it sort the way you want you have to pass SORT_STRING | SORT_FLAG_CASE as fourth argument to the method. By default its value equal to SORT_REGULAR constant.
Here the implementation:
<?php
namespace app\dataproviders;
use yii\helpers\ArrayHelper;
/**
* Class ArrayDataProvider
*/
class ArrayDataProvider extends \yii\data\ArrayDataProvider
{
/** #inheritdoc */
protected function sortModels($models, $sort)
{
$orders = $sort->getOrders();
if (!empty($orders)) {
ArrayHelper::multisort(
$models,
array_keys($orders),
array_values($orders),
SORT_STRING | SORT_FLAG_CASE
);
}
return $models;
}
}
And after it use the extended class instead of \yii\data\ArrayDataProvider
Example of usage:
$dataProvider = \app\dataproviders\ArrayDataProvider([
'allModels' => $query->find(),
'sort' => [
'attributes' => ['name','description'],
],
'pagination' => [
'pageSize' => $this->pageSize,
],
]);
That is quite good what Akmal wrote!
Maybe you need to specify key to the ArrayDataProvider, to get right id if your actionColumn not working well!
$dataProvider = \app\dataproviders\ArrayDataProvider([
'allModels' => $query->find(),
'key'=> 'id',
And if you want to filter your data within your gridview, you can use this solution:
Yii2 GridView with ArrrayDataProvider search
I tried this also and it works!!
(And the last tip: if you want to filter case intensive way, you can use stripos instead of strpos).
Good luck!
I'm learning Laravel and have created a public endpoint where I want to output only certain information of some comments if a user is not authenticated from a GET request.
I have managed to filter out the comments based on whether or not they are approved. I now want to filter out the data that is returned. I have attached a screenshot of what is currently returned.
Ideally, I only want to return the id, name and the body in the json. How can I go about this? I tried the pluck() method which did not give the desired results. Any pointers would be greatly appreciated
public function index(Request $request)
{
if (Auth::guard('api')->check()) {
return Comment::all();
} else {
$comments = Comment::where('approved', 1)->get();
return $comments->pluck('id','name','body');
}
}
To select the particular columns, you can pass columns name to get as
$comments = Comment::where('approved', 1) -> get(['id','name','body']);
You can use a transformer to map the incoming data to a sensible output based on the auth state. The following example comes from the Fractal lib:
<?php
use Acme\Model\Book;
use League\Fractal;
$books = Book::all();
$resource = new Fractal\Resource\Collection($books, function(Book $book) {
return [
'id' => (int) $book->id,
'title' => $book->title,
'year' => $book->yr,
'author' => [
'name' => $book->author_name,
'email' => $book->author_email,
],
'links' => [
[
'rel' => 'self',
'uri' => '/books/'.$book->id,
]
]
];
});
Ideally, you would create 2 classes that extend from Transformer and pass the correct one to the output.
If you want to pass the result as json respose
$comments = Comment::where('approved', 1)->pluck('id','name','body')->toArray();
return Response::json($comments);
If you want to pass the result as to blade
$comments = Comment::where('approved', 1)->pluck('id','name','body')->toArray();
return view('your_blade_name')->with('comments',$comments);
I would like to add pagination to my website, but I am very new to Yii and would like some advise.
This is the page that I am looking to add pagination: https://gocar2.com/newsproducts/center
As you can see I have numerous cells for each auto news, and now I am allowing only 18 news to show on the page. I would like to add pagination here so that I can browse more news.
And this is what I tried:
newscontroller.php
<?php
use yii\data\Pagination;
class NewsproductsController extends Controller
{
public function actionCentermore()
{
$criteria = new CDbCriteria;
$criteria->addCondition("approvedStatus = '1'");
$criteria->order = 'createdDate DESC';
$product = Newsproducts::model()->findAll($criteria);
$Pagination = new Pagination([
'defaultPageSize' => 15,
'totalCount' => $product->count(),
]);
$products = $product->offset($Pagination->offset)
->limit($Pagination->limit)
->all();
$this->renderPartial('centermore',compact('products', 'Pagination'));
}
}
newsview.php will render all the top menu and banners and it will render centermore.php
$this->renderPartial('centermore', compact('products', 'Pagination'));
centermore.php (view of the news cells), I then added the LinkPager widget at the bottom.
LinkPager::widget(['Pagination' => $Pagination])
And of course, there is an error, Class LinkPager cannot be found.
Can anyone give me some advise how to solve this/implement paging?
In Yii2 pagination is usually handled via DataProvider, have a look at the:
Yii2 Guide: Data Providers, especially ActiveDataProvider:
use yii\data\ActiveDataProvider;
$query = Post::find()->where(['status' => 1]);
$provider = new ActiveDataProvider([
'query' => $query,
'pagination' => [
'pageSize' => 10,
],
'sort' => [
'defaultOrder' => [
'created_at' => SORT_DESC,
'title' => SORT_ASC,
]
],
]);
// returns an array of Post objects
$posts = $provider->getModels();
My issue is the following.
I am trying to insert multiple items to mysql database table. I use Kartik-Select2 widget for item selection.
The following code is working for me and I can select multiple items with it.
<?= $form->field($model, 'categories')->widget(Select2::className(), [
'data' => $model->availableCategories(),
'model' => $model,
'attribute' => 'categories',
'language' => 'en',
'options' => ['placeholder' => 'Select a site...'],
'pluginOptions' => [
'allowClear' => true,
'multiple' => true,
],
]) ?>
But how now to save selected items to DB table. Where selected items stored (is there some array for them inside the widget)?
My 'categories' attribute defined in Model class as:
public $categories = [];
I thought selected items will populate to it. But it does not work (array is empty after form submition). I read many similar topics but did not find complete and full explanation how it works. I am new in Yii2 and maybe lost smth. Thx for any help.
Normally a multi select items is saved this way ( this is a simplified way )
public function actionYourAction()
{
$post = Yii::$app->request->post();
if (!empty($post)){
$postModel = $post['YourModel'];
$postModelMulti= $postModel['your_multi_attribute'];
if ( !empty( $postModelMulti) ){
foreach ($postModelMulti as $key => $value) {
$newModel = new YuorModelToAdd();
$newModel->your_attribute = $value;
$newModel->save();
}
}
}
......
In my project I want to change the link url because it does not look good.
The link is as example below:
http://www.example.com/product?Product[pagesize]=24&page=2
http://www.example.com/product?Product[brand_id][]=3
so I want to the url like this
http://www.example.com/product?pagesize=24&page=2
http://www.example.com/product?brd[]=3
I use Yii framewrok, so is it possible to change it?
Thank you!
I do not know why u use difficult url instead of dataprovider of yii for paging. here is code:
controller:
$pageSize=5;
$news = News::model()->findAll(); //returns AR objects
$count = count($news);
$dataProvider= new CArrayDataProvider($news, array(
'sort'=>array('attributes'=>array('title')), //you can sort here if objects not sorted
'pagination'=>array('pageSize'=>$pageSize),
));
$models = $dataProvider->getData();
$this->render('index', array(
'models' => $models,
'dataProvider' => $dataProvider,
'itemCount' => $count,
));
on view:
<?php
$this->widget('CLinkPager', array(
'pages'=>$dataProvider->pagination,
));
?>