How to merge and search for multiple columns in gridview? - php

Question:
I have merged 5 columns to display in a single column,which the result will look like
name.newname.newname2.newname3.5678
and when some field is empty consider newname3 it'll be like
name.newname.newname2.5678
Now i have to implement a search option which can search for cases like:
1.If someone choose to search for "newname" as search criteria then we should get results basing on comparision of joined string of all five columns.(name.newname.newname2.5678).
2.If someone will search "name.new" it should found "name.name2" as well
Sorting Works Just Fine,Help me with the sql query please.
MyCurrent searchmodel looks like this:
->andFilterWhere(['ilike', '"storeNames"."variantName"', $this->variantName])
->andFilterWhere(['"storeNames"."classId"' => $this->storeClassId])
->andFilterWhere(['"storeNames"."familyId"' => $this->storeFamilyId])
->andFilterWhere(['"storeNames"."platformId"' => $this->storePlatformId])
->andFilterWhere(['ilike', '"storeNames"."subFamilyName"', $this->subFamilyName])
Where columns classId,PlatformId,familyId represents integers that maps to a name and displays some names.
Its the getter function in base model,
public function getStoreName()
{
return $this->hasOne(StoreNames::className(), ['id' => 'storeNameId'])->via('transaction');
}

Related

Testing the numbers of rows created with Laravel

I'm making a functional test with laravel / Phpunit
What I expect is having 2 rows with championship_id = 123
But the content of each row may vary.
I only know how to check if a row exists :
$this->seeInDatabase('championship_settings',
['championship_id' => $championship->id,
]);
but I don't know how to check that there is 2 rows corresponding to criteria
Any idea how should I do it???
U can use seeNumRecords($expectedNumber, $table, $criteria).
<?php
$this->seeNumRecords(2, 'championship_settings', ['championship_id' => $championship->id]);
?>
param int $expectedNumber Expected number
param string $table Table name
param array $criteria Search criteria [Optional]
See http://codeception.com/docs/modules/Db#seeNumRecords

Yii2 search by foreign table field and total count

Im trying to search by a foreign table as follows:
2 tables:
people:
id
name
...
url:
id
peopleID
url
People.php model:
public function getUrls()
{
return $this->hasMany(Urls::className(), ['peopleID' => 'id'])->select(['url']);
}
PeopleSearch.php model:
...
$query->joinWith(['urls']);
...
$query
->andFilterWhere(['or',
['like', 'name', $this->name],
...
['like', 'url', $this->name]]
);
This works to search value entered in "name" field in several fields including foreign url one but in my view i enter a manual pagination by using something like:
$dataProvider->prepare();
if ($dataProvider->totalCount > 0)
echo Yii::t('app', 'Showing').": <b> ".($dataProvider->pagination->page*$dataProvider->pagination->pageSize+1)."-".($dataProvider->pagination->page*$dataProvider->pagination->pageSize+$dataProvider->count)."</b> ".Yii::t('app', 'of')." <b>".$dataProvider->totalCount."</b> ".Yii::t('app', 'items');
else echo Yii::t('app', 'No results found.');
echo LinkPager::widget(['pagination' => $dataProvider->pagination])
And $dataProvider->totalCount gives me the total amount of records from joined table but not the total records from people one. For instance if i have 2 records in people table and each one has 20 urls in "url" table index.php view shows "showing 1-2 of 40 items" instead of "showing 1-2 of 2 items"
Also LinkPager::widget shows a wrong number of total pages
Note that $dataProvider is passed from the controller to the view with
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
What could I do for pagination to perform the way i want?
Thank you in advance,
In People.php model my recommendation is to remove the ->select(['url']):
public function getUrls()
{
return $this->hasMany(Urls::className(), ['peopleID' => 'id']);
}
This way you can still manipulate those urls if needed.
In PeopleSearch.php model:
...
// $query->joinWith(['urls']);
// This line is the one that makes it so you get 20 results instead of 2, because you actually get one result for each url related to the people returned by the query.
$query->with(['urls']);
// This last line makes sure the model class populates the relation using only one query.
// Two queries will end up being executed to populate both the people and url models,
// however you will get the right amount for $dataProvider->totalCount.
...
if(strlen($this->url) > 0) {
$urlsPeopleIDs = \app\models\Url::find()
->select('peopleID')
->asArray()
->where(['like', 'url', $this->url])
->all();
$query->andWhere(['id' => $urlsPeopleIDs]);
}
// This way you will only filter by url when you receive a url string with lenght > 0.
// If you haven't already, you will need to create a public property called 'url' in your PeopleSearch.php model and add a 'string' or 'safe' rule so you can actually load it's value from post.

Cakephp 3.0 how to populate a select field with database values instead of numeric index

How to populate a select dropdown in cakephp3 from a database table.
Currently Cakephp produces an array (list of options) which is numeric indexed.
The option values should have id of database records (should not be the numeric keys generated by Cakephp)
Departments(table) is a taxonomy to classify events.
Events(table) which should store department based list of events.
A event may belongs to many departments. How do I achieve this?
EventsController.php
<?php $department_results = $connection->execute('SELECT departmentname FROM department')->fetchAll('assoc'); // list of departments
$this->set('departmentvalues', $department_results );
Events: add.ctp
<?php echo $this->Form->input('department', array('label' => false,
'div' => false,
'type' => 'select',
'multiple'=>'checkbox',
'legend' => 'false',
'options' => $departmentvalues,
'empty' => 'Please select a Department'
));
Objective:
A select dropdown with values from database, option values should be id of the database record
Expected result:
<select name="department"><option value="2">Maths</option><option value="4">Physics</option></select>
Issue:
cakephp generates numeric indexed array of options.
<select name="department"><option value="0">Maths</option><option value="1">Physics</option></select>
You should really use the CakePHP standard for querying your models, instead of raw SQL, especially in the case of a simple list.
Something like the below should do what you need:
$department_results = $this->Departments->find('list')
->hydrate(false)
->fields(['id','departmentname'])
->toArray();
$this->set('departmentvalues', $department_results);
Note that you will need to include the fields as you have named your column departmentname. By default, a find('list') should return id and name fields.
Another option is to set the displayField this way :
`class DepartmentsTable extends Table {
public function initialize(array $config) {
parent::initialize($config);
$this->displayField('departmentname');
}
}`
In the controller you may just call the method find('list') this way :
$departments= TableRegistry::get("Departments");
$departmentvalues=$departments->find('list')
->hydrate(false)
->toArray();
$this->set('departmentvalues', $department_results);

How to KeyBy where multiple items have the same key

I am using Laravel Collections methods and am trying to key my query results (which are a collection) by the id. The problem is I have multiple entries with the same id, but point to different countries and I want to have all of the values, not just the last one.
Here is my code that i am using so far:
$allCountries = new Collection($allCountries);
$offerCountries = $allCountries->keyBy('id');
dd($offerCountries);
foreach ($offer as $o) {
$o->countries = $allCountries->get($o->id);
}
To explain, my query puts the results in $allCountries which contains ids and countries and those results looks something like this
id=>225, country=>US
id=>225, country=>IT
id=>3304, country=>NZ
Just to give you a quick idea. I want to key this by the id which results in $offerCountries. I then loop thru a previous Collection that contains offers which have a certain ID that relates to the country result by id. So for the offer 225, the countries it contains are US and IT. I loop thru each offer and set the countries object equal to all the $allCountries id that it equals. The problem I have here is keyBy overwrites the value and only takes the last one. I am hoping to get some results like this:
[
225 => countries: {'id' => 225, 'country' => 'US'}, {'id' =>
'225', 'country' => 'IT'}
3304 => ['id' => 3304, 'country' => 'NZ'],
]
Is there a laravel method to do this, or do I need to write my own keyBy so it does not overwrite. If so, how can I get started to write this method?
Thanks
Instead of using keyBy, use groupBy:
$countriesById = collect($allCountries)->groupBy('id');
You could use filter and create a custom filter
$filtered = $allCountries->filter(function ($item) use ($id) {
return $item->id == $id;
});
$filtered->all();

HABTM with Pagination

At first take a look at the following model structure:
Model Building:
id
name
Model BuildingRange:
id
building_id
postalcode
Ok, so BuildingRange $belongsTo Building and Building $hasMany BuildingRange. Should be clear til' here.
Now let
$current_postalcode="12345";
I know want to do something like this in the BuildingController:
$this->paginate('Building',array('Building.BuildingRange.postalcode'=>$current_postalcode));
In text: I want to select all buildings for that an entry "BuildingRange" with $current_postalcode exists. How do you do that?
I appreciate your help!
When dealing with such a hasMany association, CakePHPs auto-magic needs two queries, one on the Building table, and one on the BuildingRange table. When passing conditions via the pagiante method, these conditions will be passed to the first query, and thus this it will fail since the associated models table isn't joined.
This problem can be solved on a few different ways, one would be using an ad-hoc join, for example:
$this->paginate = array
(
'joins' => array
(
array
(
'table' => 'building_ranges',
'alias' => 'BuildingRange',
'type' => 'LEFT',
'conditions' => array('BuildingRange.building_id = Building.id')
)
)
);
$this->paginate('Building', array('BuildingRange.postalcode' => $current_postalcode));
This would result in a query that looks something like this:
SELECT `Building`.`id`,
`Building`.`name`
FROM `buildings` AS `Building`
LEFT JOIN `building_ranges` AS `BuildingRange`
ON ( `BuildingRange`.`building_id` = `Building`.`id` )
WHERE `BuildingRange`.`postalcode` = '12345'
LIMIT 20
Note that in the conditions passed to the paginate method there is no need to reference the BuildingRange model through the Building model, ie no need to use Builduing.BuildingRange (that wouldn't work anyway).
ps, it's always good to mention the CakePHP version you are using!

Categories