I have a typical ListView widget in a view as follows:
public function actionView($id)
{
$model = $this->findModel($id);
$dataProvider = new \yii\data\ActiveDataProvider(['query' => \app\models\Verses::find()->where(['sura_id' =>$id])->with('sura')]);
return $this->render('view', [
'model' => $model,
'dataProvider' => $dataProvider,
]);
}
In the view a list of Verses model is rendered and the pager of the ListView is available too.
I want to add some details to the page title. Those details are data from the first and last records of the Verses model rendered in the list.
I have tried to use min() and max() PHP functions to get the first and the last records in the view as follows:
$min = min($model->verses);
echo $min->verse_id;
However, it returns the ultimate first record regarding-less the current pager page. In other words, it does not return the verse_id value of the first item of the list.
Is there any way to get the first, last or even a specific nth item of the ListView?
You should simply try :
$models = $dataProvider->getModels();
$first = reset($models);
$last = end($models);
Read more about reset and end.
You could access to the models array of dataProvider a get the firts and the last
public function actionView($id)
{
$model = $this->findModel($id);
$dataProvider = new \yii\data\ActiveDataProvider(['query' => \app\models\Verses::find()->where(['sura_id' =>$id])->with('sura')]);
$first = $dataProvider['models'][0];
$last = $dataProvider['models'][$dataProvide['totalCount']-1];
or you can use
$myModels = $dataProvider->gestModels();
$first = myModels[0];
$last = myModels[$dataProvide['totalCount']-1];
and for the page you can use count instead of total count
return $this->render('view', [
'model' => $model,
'dataProvider' => $dataProvider,
]);
}
Related
I am new to CakePHP but I have been using PHP for a while. I am trying to create a helper that would provide the level of access of a user (ACL).
Here is my ACLHelper.php so far
<?php
namespace App\View\Helper;
use Cake\View\Helper;
use Cake\ORM\TableRegistry;
class ACLHelper extends Helper{
public function getACL($id, $acl_field, $level){
$members = TableRegistry::get('groups_member');
$group = $members->find()->where(['user_id' => $id]);
$acls = TableRegistry::get('acls');
$acl = $acls->find('all', [ 'fields' => $acl_field ])->where(['group_id' => $group->first()->group_id]);
return $acl->first();
}
}
I call this function in my view this way
<?= $this->ACL->getACL($user->id, 'is_items', '4') ?>
And this is the output
{ "is_items": "4" }
What I need is the function to return true or false if the value of the field equals or is higher then the value of $level provided to the function. Now if I do this :
<?= $this->ACL->getACL($user->id, 'is_items', '4')->is_item ?>
it will return just the value. My problem is that I do not want to specify the field twice.
Thanks in advance for any help
public function getACL($id, $acl_field, $level){
$members = TableRegistry::get('groups_member');
$group = $members->find()->where(['user_id' => $id]);
$acls = TableRegistry::get('acls');
// Get the first ACL record right here
$acl = $acls->find('all', [ 'fields' => $acl_field ])->where(['group_id' => $group->first()->group_id])->first();
// Compare the requested field against the provided level
return $acl->$acl_field >= $level;
}
public function actionIndex()
{
$searchModel = new SubjectSearch();
$searchModel->search()->query->andFilterWhere(['in','subjectID',[1,2,3]]);
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
return $this->render('index', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
]);
}
I've tried different ways like
$searchModel->subjectID = [1,2,3]
$searchModel->search()->query->andFilterWhere(['in','subjectID',[1,2,3]]);
But they doesn't work for me.
Actually, ArrayDataprovider might seem to be a better solution in this case, but Array Dataprovide won't work with filters.
BTW, the real question is to search with ManyToMany Relationship.
many Users to many Groups.
many Groups to many Subjects.
UserGroupTbl contains UserID and GroupID
SubjectGroup contains SubjectID and GroupID
I'm trying to do that with:
$groups = $appUser->getGroups();
$subjectIDs = [];
foreach ($groups as $group) {
$subjectIDs[] = $group->getSubjectIDs
}
$searchModel = new SubjectSearch();
$searchModel->subjectID = $subjectIDs;
But that doesn't work and is certainly not a good method
Please help me a little bit with it.
================Update==============
$searchModel = new SubjectSearch();
$searchModel->subjectID = [1,2];
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
Result in "Array to string conversion" error.
$searchModel = new SubjectSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
$dataProvider->query->andFilterWhere(['in','subjectID',[1,2]]);;
This method actually worked.
BTW, do you have a little bit advice about handling many to many searching?
You will not believe that today I was also stuck in same situation.
Where I thought IN will work as how I wanted. But, strangely not worked for me.
I tried.
$dataProvider->query->andFilterWhere(['IN','subjectID', $this->subjectID]);
In Yii Debugger, this query was changed to:
SELECT * FROM tableName WHERE (condition) AND (subjectID = '1,2') ...
Then, I Changed my query to
$query->andFilterWhere(['subjectID' => $this->subjectID]);
And, checked in Yii Debugger, the query was automatically changed to:
SELECT * FROM tableName WHERE (condition) AND (subjectID IN ('1,2'))
...
Which I was looking for.
Updated Code
I will suggest you to follow the code given below. It will work. #Ed209's Answer is right too.
public function actionIndex(){
$searchModel = new SubjectSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
return $this->render('index', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
]);
}
SubjectSearch.php
class SubjectSearch {
.
.
.
public function search($params) {
$query = SubjectSearch::find();
$this->load($params);
if($this->subjectID != null){
$query->andFilterWhere(['subjectID' => $this->subjectID]);
}
// You can add more clauses here to make your data more appropriate.
$dataProvider = new ActiveDataProvider([
'query' => $query,
'pagination' => array('pageSize' => 20),
]);
if (!$this->validate()) {
return $dataProvider;
}
return $dataProvider;
}
}
Each time you call search you will get a new query object so you can't add parameters to it, use this method:
$searchModel = new SubjectSearch();
$searchModel->subjectID = [1,2,3];
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
In the SubjectSearch model you should have this in the search function:
$query->andFilterWhere(
[
...
'subjectId' => $this->subjectID,
...
]
);
The best way i suggest you to use the following in which you don't need to add some extra condition like where or andWhere
public function actionIndex()
{
$searchModel = new SubjectSearch();
$queryData = Yii::$app->request->queryParams;
$conditionData = [\yii\helpers\StringHelper::basename(($searchModel) => ['IN','subjectID'],[1,2,3]];
$searchData = array_merge_recursive($queryData, $conditionData);
$dataProvider = $searchModel->search($searchData);
return $this->render('index', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
]);
}
This code works for me very smoothly. I hope it will help you too
I set up editable column for the GridView in Yii2 with Kartik Editable extension. The problem I am facing is that I cannot find a way to update multiple table cell from one editable column.
The things I did:
GridView column
[
'class' => 'kartik\grid\EditableColumn',
'attribute'=>'post_title',
'editableOptions'=> function ($model, $key, $index) {
return [
'inputType' => \kartik\editable\Editable::INPUT_TEXT,
'size'=>'sm',
'afterInput'=>function ($form, $widget) use ($model, $index) {
return $form->field($model, 'post_description')->textInput(['placeholder'=>'Enter post title']);
}
];
}
],
By clicking edit post title column it shows edit fields for title and description
PostsController action
public function actionIndex()
{
$searchModel = new PostsSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
if (Yii::$app->request->post('hasEditable')) {
$postId = Yii::$app->request->post('editableKey');
$model = Posts::findOne($postId);
$out = Json::encode(['output'=>'', 'message'=>'']);
$post = [];
$posted = current($_POST['Posts']);
$post['Posts'] = $posted;
if ($model->load($post)) {
$output = '';
$out = Json::encode(['output'=>$output, 'message'=>'']);
$model->save();
}
echo $out;
return;
}
return $this->render('index', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
]);
}
So, when I edit post title and description only post title is saved into database.
I think it is because current saves only one value
$posted = current($_POST['Posts']);
What is the proper way to save both
$model->post_title and $model->post_description ?
This is an Ajax editable column. At a time only one value would be sent to the controller.
So the class of post_title and post_description column must be editable in the view.
This should work everytime you edit those columns.
Also change this
if ($model->load($post)) {
if (isset($model->post_title)){
// here you can format the value of the attribute
and display on the screen
$output = $model->post_title;
}
if (isset($model->post_description)){
$output = $model->post_description;
}
$model->save();
// Here you send a message that the value has been saved
$out = Json::encode(['output'=>$output, 'message'=>'Saved']);
}
Using yii2 I have created a Model and CRUD using gii.
I want to use a foreach or while loop in my VIEW to display the data in the following format
For each row in database table
echo("addMarker($lat_field, $lon_field);\n");
I have an index page which is rendered using the following controller action.
public function actionIndex()
{
$this->layout = 'directory';
$searchModel = new ShopDirectorySearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
return $this->render('index', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
]);
}
I can use the following to display the data using listview which displays all the data/rows within database however it has html around it and obviously isn't outputted in the format I wish it to be.
<?= ListView::widget([
'dataProvider' => $dataProvider,
'itemOptions' => ['class' => 'col-xs-6 col-sm-3'],
'itemView' => '_index',
]);?>
No need to use ListView here, you should simply try :
foreach ($dataProvider->models as $model) {
echo "addMarker({$model->lat_field}, {$model->lon_field});";
}
If you really want to use ListView, you could simply edit _index view file.
if(!empty($st_data))
{
foreach($st_data as $row)
{
echo 'Country Name: '.$row['country_name'].'</br>';
echo 'State Name: '.$row['state_name'].'</br>';
echo 'City Name: '.$row['city_name'].'</br>';
echo '</br>';
}
exit;
}
$rows = ShopDirectory::findAll();
if(!empty($rows))
{
foreach($rows as $row)
{
$lat = $row->lat;
$lon = $row->lon;
$this->view->registerJs('addmarker("'.$lat.'", "'.$lon.'"."\n");', yii\web\View::POS_END);
...
}
}
http://www.yiiframework.com/forum/index.php/topic/61940-simple-while-loop-to-list-all-rows/page__view__findpost__p__274731
I am new in yii. I want to search by attribute (field name) from my model and need to view in view page or another page by zii.widgets.grid.CGridView.
how can I create a search() function in model by findByAttribute()
so that we can show the results by attribute without any search
here is my model function but it is not working.. :: ERROR Undefined variable: pp_requisitionno
public function searchView()
{
$criteria=new CDbCriteria();
$criteria->select= 'pp_requisitionno';
$criteria->addSearchCondition('pp_requisitionno',$pp_requisitionno);
$criteria->compare('pp_requisitionno',$this->pp_requisitionno);
$criteria->condition = 'pp_requisitionno=:pp_requisitionno';
$criteria->params = array(':pp_requisitionno'=>Yii::app()->Request->Getpost('pp_requisitionno'));
$model = Requisitiondt::model()->find();
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
Any help please...
It's probably going to be more useful to define a general search function that can be reused for different searches. This can be done in the following way:
/**
* Retrieves a list of models based on the current search/filter conditions.
* #return CActiveDataProvider the data provider that can return the models based on the search/filter conditions.
*/
public function search() {
$criteria = new CDbCriteria;
//Define all your searchable fields here
$criteria->compare('t.title', $this->title, true);
$criteria->compare('t.type', $this->type, true);
$criteria->compare('t.published', $this->published, true);
$criteria->compare('category.id', $this->category_id, true);
//Add any other criteria, like the default sort order etc.
return new CActiveDataProvider($this, array(
'criteria' => $criteria,
));
}
Then in your controller you can use the search like this;
pubic function actionSearch(){
$model = new Requisitiondt;
if (isset($_POST)){
$model->attributes = $_POST;
$dataProvider = $model->search();
$this->render('searchView', array('dataProvider' => $dataProvider));
}
}
The view 'searchView' then looks like this;
<?php
$this->widget('CGridView', array(
'dataProvider' => $dataProvider,
'columns' => array(
//Add in whatever columns you want the grid to show
)
));
?>
Obviously you'll need to replace your own model names and field names, but this is the general idea. This way will search for any attributes you include in the POST request,and is more reusable.
You need use Relations in your model, read here.
Then add 'filter' => $model, in your GridView Widget options array