Definition :
I want to send text data from the template (ctp file) to the controller but it is not working.
What I DO Until now :
I have this controller courses and it has function called search as following :
/src/Controller/CoursesController :
public function search()
{
$search = $this->request->getData('keyword');
debug($search);die;
...
The /src/Template/search:
<?= $this->Form->create(null, ['url' => ['controller'=>'courses','action' => 'search']]) ?>
<?= $this->Form->control('keyword', ['label' => false, 'type'=>'text','class'=>'form-control', 'placeholder' => __('Search for...')]); ?>
<?= $this->Form->button(__('Go'), ['class' => 'btn btn-default', 'type' => 'submit']) ?>
<?= $this->Form->end() ?>
Despite my attempts to get the text data from the form and print it using debug but unfortunately I've got empty array
try this:
public function search()
{
$data = $this->request->data;
if($this->request->is(['patch', 'post', 'put', 'get']))
{
$search = $this->request->data('keyword');
debug($search);
}
}
Related
What I am trying to do:
I have Estimates and Estimates have items "EstimateItems". When updating a Estimate the EstimateItems changed should update. (using patchEntity)
This is working with my current code, my only problem is that other users can edit the Estimate Items of other users when changing the primary key of a EstimateItem in the edit form, because when patching the existing EstimateItems CakePHP only looks at the primary key of the EstimateItem and doesn't take the association in consideration. Also it's still possible to edit the estimate_id of a EstimateItem while $protected estimate_id is set to false.
So what I need is CakePHP to validate that this EstimateItem belongs to the current association before updating or while trying to update.
I hope some one can tell me what I am doing wrong or what I am missing.
Current Query
UPDATE
estimate_items
SET
data = 'Test Query 1',
amount = 123456789,
tax_id = 3
WHERE
id = 3
Expected Query
UPDATE
estimate_items
SET
data = 'Test Query 1',
amount = 123456789,
tax_id = 3
WHERE
id = 3 AND estimate_id = 1
Current code:
Estimates -> Edit.ctp
<?php $this->Form->templates($formTemplates['default']); ?>
<?= $this->Form->create($estimate, ['enctype' => 'multipart/form-data']) ?>
<fieldset>
<legend><?= __('Offerte') ?></legend>
<?= $this->Form->input('reference', ['label' => __('#Referentie'), 'autocomplete' => 'off']) ?>
<?= $this->Form->input('client_id',
[
'type' => 'select',
'empty' => true,
'label' => __('Klant'),
'options' => $clients
]
)
?>
<?php
foreach($estimate->estimate_items as $key => $item){
?>
<div class="item">
<legend>Item</legend>
<?= $this->Form->hidden('estimate_items.'. $key .'.id') ?>
<?= $this->Form->input('estimate_items.'. $key .'.data', ['type' => 'text', 'label' => __('Beschrijving')]) ?>
<?= $this->Form->input('estimate_items.'. $key .'.amount', ['type' => 'text', 'label' => __('Bedrag'), 'class' => 'input-date']) ?>
<?= $this->Form->input('estimate_items.'. $key .'.tax_id',
[
'type' => 'select',
'empty' => true,
'label' => __('Belasting type'),
'options' => $taxes
]
)
?>
</div>
<?php
}
?>
<legend>Informatie</legend>
<?= $this->Form->input('date', ['type' => 'text', 'label' => __('Offerte datum'), 'autocomplete' => 'off']) ?>
<?= $this->Form->input('expiration', ['type' => 'text', 'label' => __('Verloop datum'), 'autocomplete' => 'off']) ?>
</fieldset>
<?= $this->Form->button(__('Save')); ?>
<?= $this->Form->end() ?>
Estimates Controller
namespace App\Controller;
use App\Controller\AppController;
use Cake\Event\Event;
use Cake\ORM\TableRegistry;
class EstimatesController extends AppController
{
public function edit($id){
$associated = ['EstimateItems'];
$estimate = $this->Estimates->get($id, ['contain' => $associated]);
$this->log($estimate);
if($this->request->is(['patch', 'post', 'put'])) {
$estimate = $this->Estimates->patchEntity($estimate, $this->request->data, [
'associated' => $associated
]);
$estimate->total = '0';
$this->log($estimate);
$this->log($this->request->data);
if($this->Estimates->save($estimate, ['associated' => $associated])){
$this->Flash->success(__('De offerte is bijgewerkt'));
return $this->redirect(['action' => 'index']);
}
}
$this->set('taxes', $this->Estimates->Taxes->find('list', [ 'keyField' => 'id', 'valueField' => 'tax_name' ]));
$this->set('clients', $this->Estimates->Clients->find('list', [ 'keyField' => 'id', 'valueField' => 'companyname' ]));
$this->set('estimate', $estimate);
}
}
EstimatesTable
<?php
namespace App\Model\Table;
use Cake\ORM\Query;
use Cake\ORM\Table;
use Cake\Validation\Validator;
use Cake\ORM\RulesChecker;
use Cake\ORM\Rule\IsUnique;
class EstimatesTable extends Table
{
public function initialize(array $config)
{
$this->addAssociations([
'hasOne' => ['Taxes'],
'belongsTo' => ['Companies', 'Clients'],
'hasMany' => ['EstimateItems' => [
'foreignKey' => 'estimate_id'
]]
]);
}
public function buildRules(RulesChecker $rules){
// A Node however should in addition also always reference a Site.
$rules->add($rules->existsIn(['estimate_id'], 'EstimateItems'));
return $rules;
}
}
EstimateItem Entity
<?php
namespace App\Model\Entity;
use Cake\ORM\Entity;
class EstimateItem extends Entity
{
protected $_accessible = [
'*' => false,
'data' => true,
'amount' => true,
'tax_id' => true,
'unit_id' => true
];
}
EstimateItemsTable
<?php
namespace App\Model\Table;
use Cake\ORM\Entity;
use Cake\ORM\Table;
use Cake\Validation\Validator;
use Cake\ORM\RulesChecker;
use Cake\ORM\Rule\IsUnique;
use Cake\ORM\Query;
class EstimateItemsTable extends Table
{
public function initialize(array $config)
{
$this->addAssociations([
'belongsTo' => ['Estimates' => ['foreignKey' => 'estimate_id']],
'hasOne' => ['Taxes' => ['foreignKey' => 'tax_id']]
]);
}
Estimate Entity
<?php
namespace App\Model\Entity;
use Cake\ORM\Entity;
class Estimate extends Entity
{
/**
* Fields that can be mass assigned using newEntity() or patchEntity().
*
* Note that when '*' is set to true, this allows all unspecified fields to
* be mass assigned. For security purposes, it is advised to set '*' to false
* (or remove it), and explicitly make individual fields accessible as needed.
*
* #var array
*/
protected $_accessible = [
'*' => false,
'id' => false,
];
}
Looks like you need to implement the check via a beforeSave callback function if you don't trust that setting fields hidden / not editable is not enough.
In the callBack you can check if the relation was already there before before you overwrite them with a wrongly edited value.
Markstory Replied to me on github with a solution credits to him:
https://github.com/cakephp/cakephp/issues/9527
In Model/Table/EstimateItemsTable.php
<?php
namespace App\Model\Table;
use Cake\ORM\RulesChecker;
....
class EstimateItemsTable extends Table
{
....
public function buildRules(RulesChecker $rules){
$rules->addUpdate(function($entity) {
if (!$entity->dirty('estimate_id')) {
return true;
}
return $entity->estimate_id == $entity->getOriginal('estimate_id');
}, 'ownership', ['errorField' => 'estimate_id']);
return $rules;
}
}
In yii2 project I have my own file structure setup. Anything uploaded will get saved as a file type. I can get the file dimensions using the file uploaded in the temp folder by yii2. Using those dimensions I set my own width and height and compare them. If the height and width is more than what I have declared It has display an error message in the form. Which I am unable to do it.
My Active Form
<div class="company-form">
<?php
$form = ActiveForm::begin([
'action'=>['company/logo', 'id'=>$model->company_id],
'validateOnSubmit' => true,
'options' =>
['enctype' => 'multipart/form-data','class' => 'disable-submit-buttons','id'=> 'companyLogoForm'],
'fieldConfig' => [
'template' => "<div class=\"row\">
<div class=\"col-xs-6 margin-top-8\">{label}</div>\n<div class=\"col-xs-6 text-right\">{hint}</div>
\n<div class=\"col-xs-12 \">{input}</div>
</div>",
],
]); ?>
<?= $form->errorSummary($model, $options = ['header'=>'','class'=>'pull-left']); ?>
<?= $form->field($model, 'company_name')->hiddenInput(['maxlength' => true])->label(false) ?>
<?= $form->field($file, 'file')->fileInput([])->label(Yii::t('app', 'Attach Logo'),['class'=> 'margin-top-8']) ?>
<div class="form-group">
<?= Html::submitButton($model->isNewRecord ? Yii::t('app', 'Save') : Yii::t('app', 'Save'), ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary','data' => ['disabled-text' => 'Please Wait']]) ?>
</div>
<?php ActiveForm::end(); ?>
</div>
My Controller Action
public function actionLogo($id)
{
$model = $this->findModel($id);
if ($model->load(Yii::$app->request->post()) && $model->validate()) {
$file = new File;
$file->load(Yii::$app->request->post());
$a = UploadedFile::getInstance($file,'file');
$size = getimagesize($a->tempName);
$maxWidth = 500;
$maxHeight = 500;
if ($size[0] > $maxWidth || $size[1] > $maxHeight)
{
$model->addError('file', $error = 'Error Message');
if($model->hasErrors()){
return ActiveForm::validate($model);
}
}
$file->file = UploadedFile::getInstance($file,'file');
$file->file_name = $file->file->name;
$file->file_user = Yii::$app->user->id;
$file->file_type = 1;
if($file->save()){
$file->file_path = Files::getFilePath($file->file_id);
$validDir = $file->file->createFileDir($file->file_path, $file->file_id);
if($validDir){
$file->file->saveAs($file->file_path, false);
if($file->save()){
$model->company_file = $file->file_id;
$model->save();
return $this->redirect(['index']);
}
}
}
}
}
How do I add error message in the controller and pass that to display on my form on the modal box.
Note: my form is displayed on the modal box.
Thank you!!
You should handle the file processing in your model - or even better, create a specific UploadForm model for this purpose.
In that case you can use File Validation or a custom validator to set errors during model validation.
The built-in yii\validators\FileValidator gives you plenty pf validation rules out of the box.
This is actually pretty well explained in the documentation: Uploading Files
See also the documentation for FileValidator
Example for validating an uploaded image file:
namespace app\models;
use yii\base\Model;
use yii\web\UploadedFile;
class UploadForm extends Model
{
/**
* #var UploadedFile
*/
public $imageFile;
public function rules()
{
return [
[['imageFile'], 'file', 'skipOnEmpty' => false, 'extensions' => 'png, jpg'],
];
}
public function upload()
{
if ($this->validate()) {
$this->imageFile->saveAs('uploads/' . $this->imageFile->baseName . '.' . $this->imageFile->extension);
return true;
} else {
return false;
}
}
}
Try this validation rule
['imageFile', 'image', 'minWidth' => 250, 'maxWidth' => 250,'minHeight' => 250, 'maxHeight' => 250, 'extensions' => 'jpg, gif, png', 'maxSize' => 1024 * 1024 * 2],
i try to save multilanguaged content
My About model
...
public function rules() {
return [
[['status', 'date_update', 'date_create'], 'integer'],
[['date_update', 'date_create'], 'required'],
];
}
...
public function getContent($lang_id = null) {
$lang_id = ($lang_id === null) ? Lang::getCurrent()->id : $lang_id;
return $this->hasOne(AboutLang::className(), ['post_id' => 'id'])->where('lang_id = :lang_id', [':lang_id' => $lang_id]);
}
My AboutLang model
public function rules()
{
return [
[['post_id', 'lang_id', 'title', 'content'], 'required'],
[['post_id', 'lang_id'], 'integer'],
[['title', 'content'], 'string'],
];
}
My About controller
public function actionCreate()
{
$model = new About();
$aboutLang = new AboutLang();
if ($model->load(Yii::$app->request->post()) && $model->save()) {
return $this->redirect(['view', 'id' => $model->id]);
} else {
return $this->render('create', [
'model' => $model,'aboutLang'=>$aboutLang]);
}
}
and my view (create form)
...
<?= $form->field($model, 'status')->textInput() ?>
<?= $form->field($aboutLang, 'title')->textInput() ?>
<?= $form->field($aboutLang, 'content')->textInput() ?>
enter code here
And when i put $aboutLang in create form i get an error "Call to a member function formName() on a non-object"
It looks like the views you are using were generated by Gii. In that case, Gii generates a partial view for the form (_form.php) and two views both for create and update actions (create.php and update.php). These two views perform a rendering of the partial view.
The problem you might have is that you are not passing the variable $aboutLang from create.php to _form.php, that must be done in create.php, when you call renderPartial():
$this->renderPartial("_form", array(
"model" => $model,
"aboutLang" => $aboutLang, //Add this line
));
Hope it helps.
Check your $aboutLang type.
It looks like it is null.
if ($aboutLang) {
echo $form->field($aboutLang, 'title')->textInput();
echo $form->field($aboutLang, 'content')->textInput();
}
Here my controller:
$model = new VehicleType();
if ($model->load(Yii::$app->request->post())) {
if($model->validate()){
$model->save();
$id = $model->id;
$model->file = UploadedFile::getInstance($model, 'file');
if($model->file){
$id = $model->id;
$imageName = "vehicletype_".$id.'_'.getdate()[0];
$model->file->saveAs('uploads/'.$imageName.'.'.$model->file->extension);
$station = VehicleType::findOne($id);
$station->image = '#web/uploads/'.$imageName.'.'.$model->file->extension;
$station->save();
}
return $this->redirect(['vehicletype/index']);
}
} else {
return $this->renderAjax('create', [
'model' => $model,
]);
}
}
My view:
<div class="row">
<div class="col-lg-5">
<?php $form = ActiveForm::begin(['id' => 'station-form', 'options' => ['enctype' => 'multipart/form-data']]); ?>
<?= $form->field($model, 'name') ?>
<?= $form->field($model, 'description')->textarea() ?>
<?= $form->field($model, 'file')->fileInput() ?>
<div class="form-group">
<?= Html::submitButton('Submit', ['class' => 'btn btn-primary', 'name' => 'contact-button']) ?>
</div>
<?php ActiveForm::end(); ?>
</div>
My model:
public function rules()
{
return [
[['description'], 'string'],
[['record_status'], 'integer'],
[['name', 'image'], 'string', 'max' => 255]
];
}
/**
* #inheritdoc
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'name' => 'Name',
'description' => 'Description',
'image' => 'Image',
'record_status' => 'Record Status',
];
}
/**
* #return \yii\db\ActiveQuery
*/
public function getVehicles()
{
return $this->hasMany(Vehicles::className(), ['vehicle_type_id' => 'id']);
}
}
With this I can upload only one picture/post, I want one post to have multiple pictures, so I create a new table call 'Image' to stored my pictures and have a one-to-many relationship.
But I run into a problem, how can I add data to 2 tables from just 1 form
I'm using Yii2 basic template
Thanks
Step 1
First create two variables in your vehicletype model.
public $uploadedImages;
public $imageforNewtable = array();
Step 2
Make sure to mention this imageforNewtable variable in your model rule.
[['imageforNewtable'], 'image', 'extensions' => 'png, jpg, JPEG'],
Step 3
In your form:
<?php $form = ActiveForm::begin(['id' => 'station-form', 'options' => ['enctype' => 'multipart/form-data']]); ?>
<?= $form->field($model, 'imageforNewtable[]')->fileInput(['accept' => 'image/*']); ?>
Step 4
In Your Controller:
$model->uploadedImages = UploadedFile::getInstances($model,'imageforNewtable');
// Make sure to put "Instances" (plural of Instance) for uploading multiple images
$model->imageforNewtable = array(); // To avoid blank entries as we have entries in $_FILES not in $_POST.
foreach ($model->uploadedImages as $singleImage)
{
$model->imageforNewtable[] = time() . '_' . $singleImage->name;
}
Now bulk insert data in Images table :
$bulkInsertforimages = array(); //defined benchInsert array for images
$columnsArray = ['blog_id', 'image']; //Column names in which bulk insert will take place.
if ($model->imageforNewtable != '') {
foreach ($model->imageforNewtable as $singleData) {
$bulkInsertforimages[] = [
'blog_id' => $model->id,
'image' => $singleData,
];
}
}
if (count($bulkInsertforimages) > 0) {
$command = \Yii::$app->db->createCommand();
$command->batchInsert('YOUR_IMAGE_TABLE', $columnsArray, $bulkInsertforimages)->execute();
}
I'm using the yii-user extension and i'm trying the add proper label to the 'placeholder' attribute. really new to Yii so still trying to get the grasp of things.
I've added the attributeLabels() method in the class in the models folder.
class RegistrationForm extends User {
/**
* Declares attribute labels.
*/
public function attributeLabels()
{
return array(
'email'=>'Email Address',
'firstname'=>'First Name',
'lastname' => 'Last Name',
'verifyPassword' = 'Retype Password'
);
}
}
Here is my code in my /views/ folder
$form=$this->beginWidget('bootstrap.widgets.TbActiveForm', array(
'id'=>'registration-form',
'type'=>'vertical',
'enableClientValidation'=>true,
'clientOptions'=>array(
'validateOnSubmit'=>true,
),
));
<?php echo $form->textField($model,'email', array('class' => 'input-block-level', 'placeholder' => 'email')); ?>
<?php echo $form->passwordField($model,'password', array('class' => 'input-block-level', 'placeholder' => 'password')); ?>
<?php echo $form->passwordField($model,'verifyPassword', array('class' => 'input-block-level', 'placeholder' => 'verifyPassword')); ?>
<?php
$profileFields=Profile::getFields();
if ($profileFields) {
foreach($profileFields as $field) {
if ($widgetEdit = $field->widgetEdit($profile)) {
//echo $widgetEdit;
} elseif ($field->range) {
echo $form->dropDownList($profile,$field->varname,Profile::range($field->range),array('class' => 'input-block-level'));
} elseif ($field->field_type=="TEXT") {
echo $form->textArea($profile,$field->varname,array('rows'=>6, 'cols'=>50));
} else {
//echo $field->varname;
if ($field->varname == 'firstname')
{
$placeholder = 'First Name';
}
else if ($field->varname == 'lastname')
{
$placeholder = 'Last Name';
}
else
{
$placeholder = $field->varname;
}
echo $form->textField($profile,$field->varname,array('size'=>60,'maxlength'=>(($field->field_size)?$field->field_size:255),'class' => 'input-block-level', 'placeholder' => $placeholder));
}
echo $form->error($profile,$field->varname);
}
}
?>
how would i make attributeLabels() work on my echo $form->textField($profile,$field->varname,array('size'=>60,'maxlength'=>(($field->field_size)?$field->field_size:255),'class' => 'input-block-level', 'placeholder' => $placeholder)); ?
You can get the text label for the specified attribute with getAttributeLabel() like:
$model->getAttributeLabel('verifyPassword');
E.x:
<?php echo $form->passwordField($model,'verifyPassword',
array('class' => 'input-block-level',
'placeholder' => $model->getAttributeLabel('verifyPassword')));
?>
you don't have to edit class RegistrationForm extends User
open protected/modules/user/model/User.php
add add/edit your custom labels in the attributeLabels() method
public function attributeLabels()
{
return array(
'id' => UserModule::t("Id"),
'username'=>UserModule::t("username"),
'password'=>UserModule::t("Password"),
'verifyPassword'=>UserModule::t("Retype Password"),
'firstname'=>UserModule::t("First Name"), //ADDED
'lastname'=>UserModule::t("Last Name"), // ADDED
'email'=>UserModule::t("Email Address"), //EDITED
'verifyCode'=>UserModule::t("Verification Code"),
'activkey' => UserModule::t("Activation Key"),
'createtime' => UserModule::t("Registration Date"),
'create_at' => UserModule::t("Registration Date"),
'lastvisit_at' => UserModule::t("Last Visit"),
'superuser' => UserModule::t("Superuser"),
'status' => UserModule::t("Status"),
);
}
and to get the label to show in your view file. use this
<?php echo $form->passwordField($model,'verifyPassword',
array('class' => 'input-block-level',
'placeholder' => $model->getAttributeLabel('email')));
?>