CakePHP3: how to pass parameter to join()? - cakephp-3.0

I have a DefaultPermissions table, so with a default permissions set, and I want to compare this set with a permissions set affected to a specific site to see if additionnal default permissions exist.
So I wrote the following query:
$defaultPermissions = $this->DefaultPermissions
->find()
->select([
'user_id' => $selUser->id,
'role',
'sequence',
'product',
'module',
'item',
'value',
'visible',
'editable'
])
->join([
'p' => [
'table' => 'permissions',
'type' => 'LEFT',
'conditions' => [
'p.product = DefaultPermissions.product',
'p.module = DefaultPermissions.module',
'p.item = DefaultPermissions.item',
'p.site_id' => $selSite->id // My problem is here!
]
]
],
[
'p.product' => 'varchar',
'p.module' => 'varchar',
'p.item' => 'varchar',
'p.site_id' => 'integer'
])
->where([
'DefaultPermissions.role' => $selUser->role,
'p.item IS' => NULL, // item doit toujours être présent donc si null, la ligne est absente.
'OR' => [['DefaultPermissions.product' => $agplan->product->code], ['DefaultPermissions.product' => '']]
])
->all();
But despite all defaultPermissions can be found for siteselSite->id, the query gives the complete list existing in DefaultPermissions table.
If I remove the line 'p.site_id' => $selSite->id the list is empty as expected so I conclude that the passed parameter is not well interpreted.
How to do it?

There was just a syntax error in the join:
->join([
'p' => [
'table' => 'permissions',
'type' => 'LEFT',
'conditions' => [
'p.product = DefaultPermissions.product',
'p.module = DefaultPermissions.module',
'p.item = DefaultPermissions.item',
'p.site_id = ' => $selSite->id // '=' was missing
]
]
],
....

Related

Cakephp: exposed virtual field are not included in query

I read some other questions but they are very old. I'm using CakePHP 3.7.9.
I read the documentation about virtual fields, here and here.
So far:
Proforma.php
class Proforma extends Entity
{
protected $_accessible = [
'customer_id' => true,
'proforma_number' => true,
'proforma_date' => true,
'payment_date' => true,
'proforma_state_id' => true,
'customer' => true,
'proforma_state' => true,
'item_proformas' => true
];
protected $_virtual = [
'total'
];
protected function _getTotal()
{
$q = TableRegistry::getTableLocator()->get('item_proformas')->find();
$v = $q
->select(['total' => $q->func()->sum('total')])
->where(['proforma_id' => $this->id])
->first()['total'];
if ($v == null) $v = 0;
return $v;
}
}
In views I can easily access to this field:
<td class="text-right"><?= $proforma->item_proformas ? $this->Number->currency($proforma->total) : '' ?></td>
But when I try to make a query in Controller, i.e.:
$query = $this->Proformas->find();
debug($query);
$query->select(['value' => $query->func()->sum('total')]);
The field total is not found. Here the output of the debug:
object(Cake\ORM\Query) {
'(help)' => 'This is a Query object, to get the results execute or iterate it.',
'sql' => 'SELECT Proformas.id AS `Proformas__id`, Proformas.customer_id AS `Proformas__customer_id`, Proformas.proforma_number AS `Proformas__proforma_number`, Proformas.proforma_date AS `Proformas__proforma_date`, Proformas.payment_date AS `Proformas__payment_date`, Proformas.proforma_state_id AS `Proformas__proforma_state_id` FROM proformas Proformas',
'params' => [],
'defaultTypes' => [
'Proformas__id' => 'integer',
'Proformas.id' => 'integer',
'id' => 'integer',
'Proformas__customer_id' => 'integer',
'Proformas.customer_id' => 'integer',
'customer_id' => 'integer',
'Proformas__proforma_number' => 'string',
'Proformas.proforma_number' => 'string',
'proforma_number' => 'string',
'Proformas__proforma_date' => 'date',
'Proformas.proforma_date' => 'date',
'proforma_date' => 'date',
'Proformas__payment_date' => 'date',
'Proformas.payment_date' => 'date',
'payment_date' => 'date',
'Proformas__proforma_state_id' => 'integer',
'Proformas.proforma_state_id' => 'integer',
'proforma_state_id' => 'integer'
],
'decorators' => (int) 0,
'executed' => false,
'hydrate' => true,
'buffered' => true,
'formatters' => (int) 0,
'mapReducers' => (int) 0,
'contain' => [],
'matching' => [],
'extraOptions' => [],
'repository' => object(App\Model\Table\ProformasTable) {
'registryAlias' => 'Proformas',
'table' => 'proformas',
'alias' => 'Proformas',
'entityClass' => 'App\Model\Entity\Proforma',
'associations' => [
(int) 0 => 'customers',
(int) 1 => 'proformastates',
(int) 2 => 'invoices',
(int) 3 => 'itemproformas'
],
'behaviors' => [],
'defaultConnection' => 'default',
'connectionName' => 'default'
}
}
Why even if the virtual field is exposed it's not inserted into the query?
The documentation linked above says:
Do bear in mind that virtual fields cannot be used in finds. If you want them to be part of JSON or array representations of your entities, see Exposing Virtual Fields.
and then:
By default virtual fields are not exported when converting entities to arrays or JSON. In order to expose virtual fields you need to make them visible. When defining your entity class you can provide a list of virtual field that should be exposed
So exposing virtual fields should let me to use them in finds.
Sadly Virtual fields are not calculated at the point the query is run. Here are some alternative approaches you may find helpful.
Create View of the actual table ( handle the sum at the DB level)
Create A beforeFind event in the table model.

Yii2 captcha always incorrect

Whan I add 'on' => 'create' in my rule my captcha always incorrect
Off that work good why?
I try to let it to other controller support/captcha but still incorrect
MyView
<?= Captcha::widget([
'id' => 'captcha',
'model' => $model,
'attribute' => 'verifyCode',
'options' => ['class' => 'form-control',
'data-v-rule' => '',
'captchaAction' => 'support/captcha',
'data-v-msg' => $i18n->t('please.input.verify.code'),
'placeholder' => $i18n->t('please.input.verify.code', '', false)]
]); ?>
Myrule
...
[['verifyCode'], 'captcha', 'message' => $i18n->t('error.verifyCode'),'captchaAction' => 'support/captcha' , 'on' => 'create'],
...
I get seesion
$_SESSION = [
'__flash' => [],
'__captcha/site/captcha' => 'nnbioo',
'__captcha/site/captchacount' => 1,
'__captcha/support/captcha' => 'cacijq',
'__captcha/support/captchacount' => 1,
];
Mycontroller
public function actions()
{
return [
'error' => [
'class' => 'yii\web\ErrorAction',
],
'captcha' => [
'class' => CaptchaAction::className(),
],
];
}
$customerServiceModel->load($post) is not working, because attribute verifyCode is not safe in this case. Your rule is specified with 'on' => 'create' - so it means, it's save on scenario create. You didn't assigned this scenario to the model so there's 2 solutions:
Remove 'on' => 'create' from rule
Assign create scenario to model by $customerServiceModel->scenario = 'create'; before using load().

kartik DynaGrid select2 filter not render

my setup column using kartik DynaGrid Widget to display data on yii2. but filter (FILTER_SELECT2) not render on my table. Can someone help me? Please.
'class' => 'kartik\grid\DataColumn',
'attribute' => 'city_id',
'label' => 'City',
'hAlign' => 'center',
'vAlign' => 'middle',
'width' => '70px',
'filterType' => GridView::FILTER_SELECT2,
'filter' => [
1 => 'filter 1',
2 => 'filter 2',
],
'format' => 'html',
'value' => function($data){
$cities = \app\models\City::getData();
if(isset($cities[$data->city_id])){
return $cities[$data->city_id];
}
return $data->city_id;
}
Post your grid config. Maybe you turn off filter in config. Default config is this
....
'gridOptions'=>[
'dataProvider'=>$dataProvider,
'filterModel'=>$searchModel,
....
],

Yii2 sort object defaultOrder

I have a table of policies that belong to chapters. When I view the policies in my grid view I want the default order be policy title within chapter title. I see how to set up sort attributes to enable this, but I can't figure out how to set the defaultOrder to be based on chapter title and then policy title. When ever I try to set policy.title as an attribute in the defaultOrder setting I get an error.
If Policy is model class of policy table that has a relation with chapter table named 'chapter' and linked by chapter_id field, such as:
public function getChapter()
{
return $this->hasOne(Chapter::className(), ['chapter_id' => 'chapter_id']);
}
Now you build query object with policy joined with chapter:
$query = Policy::find()
->joinWith(['chapter']);
$dataProvider = new ActiveDataProvider([
'query' => $query,
'sort'=> ['defaultOrder' => ['chapter.title'=>SORT_ASC, 'policy.title' => SORT_ASC]]
]);
I could not get Fabrizio's answer to work, because my chapter table is policy_chapter, not just chapter and so is not the same as the relation name. When I tried to use the relation name, I got errors. I finally figured out in the sort, you have to use the names of the related tables, not the relations, and add them as attributes. e.g.:
$dataProvider = new ActiveDataProvider([
'query' => $query,
'pagination' => ['pageSize' => 50],
'sort' => [
'defaultOrder' => ['policy_chapter.sort' => SORT_ASC,'policy_chapter.title' => SORT_ASC],
'enableMultiSort' => true,
'attributes' => [
'id' => [
'asc' => ['policy.id' => SORT_ASC],
'desc' => ['policy.id' => SORT_DESC],
'default' => SORT_ASC
],
'chapter_id' => [
'asc' => ['policy_chapter.sort' => SORT_ASC,'policy_chapter.title' => SORT_ASC],
'desc' => ['policy_chapter.sort' => SORT_DESC,'policy_chapter.title' => SORT_DESC],
'default' => SORT_ASC,
],
'reference' => [
'asc' => ['reference' => SORT_ASC],
'desc' => ['reference' => SORT_DESC],
'default' => SORT_ASC
],
'title' => [
'asc' => ['policy.title' => SORT_ASC],
'desc' => ['policy.title' => SORT_DESC],
'default' => SORT_ASC
],
'policy_chapter.sort',
'policy_chapter.title',
],
],
]);
Use the relation name or leave out the attributes and you get errors. Before I was writing
'defaultOrder' => ['policy_chapter.sort' => SORT_ASC,'policy_chapter.title' => SORT_ASC],
and Yii was not happy

Yii2 DateControl: How to set default value (date)

I have in views/example/_form.php the following date field:
use yii\widgets\ActiveForm;
use kartik\datecontrol\DateControl;
...
$form = ActiveForm::begin();
...
echo $form->field($model, 'date')->widget(DateControl::className(), [
'type' => DateControl::FORMAT_DATE,
// 'value' => date('Y-m-d'),
// 'value' => date('d.m.Y'),
// 'value' => time(),
// 'value' => '02.12.2015',
// 'value' => '2015-12-02',
// 'value' => '2015-12-02 00:00:00 0000',
// 'value' => date('Y-M-d'),
// 'value' => date('d.M.Y'),
// 'value' => date('dd.MM.yyyy'),
]);
...
ActiveForm::end();
None of my attempts to set the default date was successfull (see the commented lines above). I have always received no error message and no default value. The resulting HTML input field looks always the same (the 'value' is empty):
<input type="text" id="yiiversion-date-disp" class="form-control" name="date-yiiversion-date" value="" data-krajee-datecontrol="datecontrol_1e107159" data-datepicker-source="yiiversion- date-disp-kvdate" data-datepicker-type="2" data-krajee-kvdatepicker="kvDatepicker_0aa71c62">
Configuration in config/main.php looks like this:
'modules' => [
'datecontrol' => [
'class' => 'kartik\datecontrol\Module',
'autoWidget' => true,
'autoWidgetSettings' => [
'date' => [
'pluginOptions' => [
'autoclose' => true,
'todayHighlight' => true,
'todayBtn' => true,
],
],
],
],
],
The dates are displayed as 01.01.2015 ('dd.MM.yyyy') and saved as 2015-01-01 ('Y-M-d') - MySQL datatype DATE.
More information:
https://github.com/kartik-v/yii2-datecontrol
http://demos.krajee.com/datecontrol
As suggested by InsaneSkull the solution is quite simple. I had to add to the correspondig controller only: $model->date = date('Y-m-d');
The resulting action could look e.g. like this:
public function actionCreate()
{
$model = new YiiTask();
if ($model->load(Yii::$app->request->post()) && $model->save()) {
return $this->redirect(['view', 'id' => $model->id]);
} else {
$model->date = date('Y-m-d');
return $this->render('create', [
'model' => $model,
]);
}
}