I cannot grab a $_POST value in controller using Yii 2.0 - php

Using Yii 2.0 i'm trying to grab some $_POST values in my controller from my view but cannot do this. I will show you my code and talk you through it below.
Models/CaseSearch.php
<?php
namespace app\models;
use Yii;
use yii\base\Model;
use yii\data\ActiveDataProvider;
use app\models\Cases;
/**
* CaseSearch represents the model behind the search form about `app\models\Cases`.
*/
class CaseSearch extends Cases
{
public $category;
public $subcategory;
public $childcategory;
public $newcategory;
/**
* #inheritdoc
*/
public function rules()
{
return [
[['case_id', 'year'], 'integer'],
[['name', 'judgement_date', 'neutral_citation', 'all_ER', 'building_law_R', 'const_law_R', 'const_law_J', 'CILL', 'adj_LR'], 'safe'],
];
}
/**
* #inheritdoc
*/
public function scenarios()
{
// bypass scenarios() implementation in the parent class
return Model::scenarios();
}
/**
* Creates data provider instance with search query applied
*
* #param array $params
*
* #return ActiveDataProvider
*/
public function search($params)
{
$query = Cases::find();
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
$this->load($params);
if (!$this->validate()) {
// uncomment the following line if you do not want to any records when validation fails
// $query->where('0=1');
return $dataProvider;
}
$query->andFilterWhere([
'case_id' => $this->case_id,
'judgement_date' => $this->judgement_date,
'year' => $this->year,
]);
$query->andFilterWhere(['like', 'name', $this->name])
->andFilterWhere(['like', 'neutral_citation', $this->neutral_citation])
->andFilterWhere(['like', 'all_ER', $this->all_ER])
->andFilterWhere(['like', 'building_law_R', $this->building_law_R])
->andFilterWhere(['like', 'const_law_R', $this->const_law_R])
->andFilterWhere(['like', 'const_law_J', $this->const_law_J])
->andFilterWhere(['like', 'CILL', $this->CILL])
->andFilterWhere(['like', 'adj_LR', $this->adj_LR]);
return $dataProvider;
}
public function searchByCategory($category){
$query = Cases::find();
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
if (!$this->validate()) {
// uncomment the following line if you do not want to any records when validation fails
// $query->where('0=1');
return $dataProvider;
}
$query->andFilterWhere([
'category_id' => $category
]);
return $dataProvider;
}
}
Okay so now is my view:
<?php
$form = ActiveForm::begin();
echo $form->field($searchModel, 'category')
->dropDownList(
ArrayHelper::map($allCategory, 'id', 'name'),
[
'onchange'=>'getSubcategory()',
]
);
//To stop errors, if first category not chosen make subcategory and empty drop down.
$subcategory = array(
"empty" => ""
);
echo $form->field($searchModel, 'subcategory')
->dropDownList(
ArrayHelper::map($subcategory, 'id', 'name'),
[
'onchange'=>'getChildcategory()',
]
);
//To stop errors, if second category not chosen make childcategory and empty drop down.
$childcategory = array(
"empty" => ""
);
echo $form->field($searchModel, 'childcategory')
->dropDownList(
ArrayHelper::map($childcategory, 'id', 'name'),
[
//'onchange'=>'getChildCategory()',
'onchange'=>'submitNow()',
]
);
echo '<div class="form-group">';
echo Html::submitButton('Submit', ['class' => 'btn btn-primary']);
echo '</div>';
ActiveForm::end();
Ok, so when i click the submit button i want to capture the value in my controller so that i can use this to alter the results given in the gridview.
When i inspect the element on the drop down lists the names are weird so i am not sure if this is making a different. for example the name for subcategory is actually: CaseSearch[subcategory]
Now for my controller:
public function actionIndex()
{
//
// This is for the first render of index
//
$model = new Cases;
$searchModel = new CaseSearch();
$allCategory = Category::find()->all();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
//
// This is for when i click the submit button on the view. I want it to submit and then grab the subcategory in variable $subtest. I make $subtest = 1 so that when i first render the page it doesn't throw an error and when submitted it should change to the post value
//
$subtest = 1;
if($searchModel->load(Yii::$app->request->post())){
$subtest = $_POST['subcategory'];
}
return $this->render('index', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
'allCategory' => $allCategory,
'model' => $model,
'subtest' => $subtest
]);
}
However when i try to print_r() the variable $subtest in my view i get the error:
Undefined index: CaseSearch[subcategory]
and its for the line:
$subtest = $_POST['CaseSearch[subcategory]'];
In my controller.
Can anyone please advise as i cannot figure out why?

I think your application design is improvable. Read the Yii guide.
However I think the solution to the question is:
$subtest = $_POST['CaseSearch']['subcategory];

Don't use $_GETand $_POST directly in your controller there are some abstraction layer which filter that input.
$get = $request->get();
// equivalent to: $get = $_GET;
$post = $request->post();
// equivalent to: $post = $_POST;
You should use that classes and methods to get your params.
http://www.yiiframework.com/doc-2.0/guide-runtime-requests.html

Related

Value not updated in databases after validation and save success

Hi everyone i'm having trouble with my software developed with yii2.
I Have a model called Anagrafica and with its primary key id. With this model everything works.
I also have a model called AnagraficaOpzioniCarriera which extend the first one.
I have a view anagrafica/index that show a Kartik grid with the data of people enrolled that you can find in anagrafica. Admin user can update the data of an Anagrafica model by clicking on an the attribute "cognome" that render to anagrafica/update.
this is the command that call the controller AnagraficaController to reach anagrafica/update
'cognome'=>Grid::Labels('cognome',['anagrafica/update'],\app\helpers\Permits::allow('anagrafica','update'),'id','btn','info','10%'),
This is AnagraficaController
public function actionUpdate($id,$error=0,$message='')
{
$id = (int)$id;
$model = Anagrafica::findOne(['id' => $id]);
$model->scenario = 'update';
if ($model->load(Yii::$app->request->post())) {
if($model->validate()){
}
if($model->save(false)){
return $this->redirect(['anagrafica/update','id'=>$model->id]);
}
}
}
return $this->render('update', ['model' => $model, 'extended'=>true]);
}
i removed some portions of code to semplify it, but this is the core.
One time the view anagrafica/update is reached in this page i have an ActiveForm to modify data of the model and i have a render to a grid that show the attributes contained in AnagraficaOpzioniCarriera about the $model that i'm updating.
<?= $this->render('_opzioni_carriera',['parent'=>$model]); ?>
anagrafica/_opzioni_carriera view contain a Kartik grid that shows the column in the model AnagraficaOpzioniCarriera
<?php
use kartik\grid\GridView;
use kartik\select2\Select2;
use kartik\widgets\ActiveForm;
use kartik\editable\Editable;
use kartik\widgets\SwitchInput;
use yii\helpers\ArrayHelper;
use app\helpers\Autoconfigurazione;
use app\models\AnagraficaOpzioniCarriera;
use app\helpers\Grid;
use yii\helpers\Html;
use app\helpers\UserInfo;
/* #var $this yii\web\View */
/* #var $model app\models\AnagraficaOpzioniCarriera*/
$model = new AnagraficaOpzioniCarriera(['scenario'=>'search']);
?>
<div class="">
<?php
echo GridView::widget([
'options'=>[
'id'=>'opzioni_carriera',
],
'dataProvider'=> $model->search($parent->id,Yii::$app->request->queryParams),
'showPageSummary'=>false,
'headerRowOptions'=>['class'=>'kartik-sheet-style'],
'pjax'=>true, // pjax is set to always true for this demo
'pjaxSettings'=>[
'neverTimeout'=>true,
],
'toolbar'=> [
[
'content'=>''
],
],
'panel'=>[
'heading'=>false,
'footer'=>false,
'after'=>false,
],
'columns' => Grid::gridColumns([
'model'=>$model,
'checkbox'=>false,
'remove'=>Grid::gridRemove($model),
'extraOptions' =>[
'cashback' =>Grid::YNColumn('cashback',['anagrafica-opzioni-carriera/update', 'id' => $parent->id],'left',true,'5%'),
'compensa'=>Grid::YNColumn('compensa',['anagrafica-opzioni-carriera/update', 'id' => $parent->id],'left',true,'5%'),
'associazione'=>Grid::YNColumn('associazione',['anagrafica-opzioni-carriera/update', 'id' => $parent->id],'left',true,'5%'),
'formazione'=>Grid::YNColumn('formazione',['anagrafica-opzioni-carriera/update', 'id' => $parent->id],'left',true,'5%'),
],
]);
?>
</div>
cashback, compensa etc.. are the attributes in the model AnagraficaOpzioniCarriera.
Here when i try to update this attributes everything looks fine, the function model->validate() and model->load returns true value, but at the end of the process doesn't works.
Honestly i don't know what i have to return from the function of the controller.
public function actionUpdate($id)
{
$model = AnagraficaOpzioniCarriera::findOne(['id_anagrafica' => $id]);
if (!$model) {
// Se l'anagrafica opzioni carriera non esiste, genera un'eccezione 404
throw new \yii\web\NotFoundHttpException(Yii::t('app', 'The requested page does not exist.'));
}
$model->scenario = 'update';
if ($model->load(Yii::$app->request->post()) && $model->validate()) {
if(Yii::$app->request->post('cashback') != null) $model->cashback = Yii::$app->request->post('cashback');
if(Yii::$app->request->post('compensa') != null) $model->cashback = Yii::$app->request->post('compensa');
if(Yii::$app->request->post('associazione') != null) $model->cashback = Yii::$app->request->post('associazione');
if(Yii::$app->request->post('formazione') != null) $model->cashback = Yii::$app->request->post('formazione');
if ($model->save()) {
return Json::encode(["success" => true, 'message' => 'Dati aggiornati']);
}
}
// Mostra il form di modifica
return $this->render('_opzioni_carriera', [
'parent' => $model,
]);
}
anyone can help me? i hope i explained my problem in a good form, but my english is not the best, i know. Anyway thanks in aadvance to everyone who want to try to help me, if you need anything other you can easily ask.
I tried every everything, also a logger but nothing worked
Like someone suggest these are the rules of the model AnagraficaOpzioni, but like i said prevously model->validate() works, for this reason i think the problem is not over there
public function rules()
{
return [
[['id_anagrafica'], 'required'],
[['id_anagrafica'], 'integer'],
[['cashback', 'compensa', 'associazione', 'formazione'], 'required', 'on'=>['update']],
[['cashback', 'compensa', 'associazione', 'formazione'], 'integer'],
[['id_anagrafica', 'cashback', 'compensa', 'associazione', 'formazione',], 'safe', 'on'=>['search']],
];
}

Laravel Orchid Editing an entry in a list

I have a list, in which I have a delete button for each entry, which works flawlessly, as do the create function. I'm trying to add an edit button, and can manage to create the popup that requests the new name.
When I create a new entry and try to edit it, it shows me the create form again. When I try to edit an older entry, it tells me that
Oh snap! Change a few things up and try submitting again.
The category.name field is required.
My full code is here, for completion:
namespace App\Orchid\Screens;
use Orchid\Screen\Screen;
use Orchid\Screen\Fields\Input;
use Orchid\Support\Facades\Layout;
use Orchid\Screen\TD;
use Orchid\Screen\Actions\ModalToggle;
use App\Models\Category;
use Illuminate\Http\Request;
use Orchid\Screen\Actions\Button;
class CategoryScreen extends Screen
{
/**
* Fetch data to be displayed on the screen.
*
* #return array
*/
public function query(): iterable
{
return [
'categories' => Category::latest()->get(),
];
}
/**
* The name of the screen displayed in the header.
*
* #return string|null
*/
public function name(): ?string
{
return 'Category Screen';
}
/**
* The screen's action buttons.
*
* #return \Orchid\Screen\Action[]
*/
public function commandBar(): iterable
{
return [
ModalToggle::make('category')
->icon('plus')
->method('create')
->modal('createCategory'),
];
}
/**
* The screen's layout elements.
*
* #return \Orchid\Screen\Layout[]|string[]
*/
public function layout(): iterable
{
return [
Layout::table('categories', [
TD::make('name'),
// Create a delete button
TD::make('Actions')
->alignRight()
->render(function (Category $category) {
return Button::make('')
->icon('trash')
->confirm(
'After deleting, the category will be gone forever.'
)
->method('delete', [
'category' => $category->id,
]);
}),
TD::make('Actions')
->alignRight()
->render(function (Category $category) {
return Button::make('')
->icon('pencil')
->modal('editCategoryModal', [
'category' => $category,
])
->method('edit', [
'category' => $category->id,
]);
}),
]),
Layout::modal('createCategory', [
Layout::rows([
Input::make('category.name')
->title('Name')
->placeholder('Enter category name'),
]),
])
->title('Create category')
->applyButton('Create'),
];
}
// Make a create method that validates name field
public function create(Request $request)
{
$request->validate([
'category.name' => 'required|max:255',
]);
// Create a new category
$category = new Category();
$category->organisation_id = auth()->user()->organisation_id;
$category->name = $request->category['name'];
$category->save();
}
// Make a delete method that deletes the category
public function delete(Request $request)
{
$category = Category::find($request->category);
$category->delete();
}
// Make an edit method that validates name field
public function edit(Request $request)
{
$request->validate([
'category.name' => 'required|max:255',
]);
// Update the category
$category = Category::find($request->category->id);
$category->name = $request->category['name'];
$category->save();
}
public function editCategoryModal(): iterable
{
return [
Layout::modal('editCategory', [
Layout::rows([
Input::make('category.name')
->title('Name')
->placeholder('Enter category name'),
]),
])
->title('Edit category')
->applyButton('Save')
];
}
}
And my site, as it looks:
And the form, when I press the edit button (the pencil):
I am quite new to Laravel Orchid, so I admit that I might be going about this the totally wrong way, but the documentation does not include an example on how to do this.
Thank you.
You should use async functions to edit a Model on the same page (with modal)
Link : https://orchid.software/en/docs/modals/#asynchronous-data-loading
and you should also define all modals in the layouts section, not in a separate function.

Laravel Validation not returning error

I am new in Laravel.
This is my laravel controller:
public function store()
{
$validator = Validator::make($data = Input::all(), City::$rules);
if ($validator->fails())
{
return Redirect::back()->withErrors($validator)->withInput();
}
$image_temp=Input::file('image');
$name = Input::file('image')->getClientOriginalName();
$data['image']='';
if(Image::make($image_temp->getRealPath())->save('public/up/city/'.$name)){
$data['image']='up/city/'.$name;
}
City::create($data);
return Redirect::route('admin.cities.index');
}
and This is my model:
class City extends \Eloquent {
protected $primaryKey='city_id';
// Add your validation rules here
public static $rules = [
'title' => 'required',
'image' => 'mimes:jpeg',
'parent_id' => 'required',
'name' => 'required',
'english_name'=>'unique:cities,english_name|required'
];
// Don't forget to fill this array
protected $fillable = ['name', 'parent_id', 'english_name','population','phone_prefix','image'];
}
And I have a form I use {{ $errors->first('inputName','<p class="error">:message</p>') }} bellow my form inputs, when I send form without filling inputs I get error under each form input. But when I fill out all form inputs and then submit the Laarvel validation return fail (I mean mass assignment not working and not registering, and redirects back to create page.) what is the problem?
Almost always the reason for a mass assignment error is a missing attribute in the $fillable array. In your case it is title.
protected $fillable = ['title', 'name', 'parent_id', 'english_name','population','phone_prefix','image'];
^
Edit
Apparently the problem was actually that the title in the $rules array, which should have been name...

laravel belongstomany with condition

I have the following model.
class Training extends \Eloquent {
// Add your validation rules here
public static $rules = [
'name' => 'required',
'city' => 'required',
'province' => 'required',
'budget_year' => 'required|integer',
's_date' => 'required|date',
'e_date' => 'required|date'
];
// Don't forget to fill this array
protected $fillable = [
'name',
'city',
'province',
'budget_year',
's_date',
'e_date'
];
public function material(){
return $this->hasMany('Material');
}
public function budget(){
return $this->belongsToMany('Budget')->withPivot('amount');
}
public function budgetById($training_id){
$this->belongsToMany('Budget')->where('training_id', '=', $training_id)->get();
}
}
when I debug the budgetById method using DB::getQueryLog, the query is as follow
select budgets.*,
budget_training.training_id as pivot_training_id,
budget_training.budget_id as pivot_budget_id
from budgets inner join budget_training on budgets.id = budget_training.budget_id
where budget_training.training_id is null and training_id='6'
which return 0 rows, but when I try to modify the query and run it in pgadmin, the following script works well.
select budgets.*,
budget_training.training_id as pivot_training_id,
budget_training.budget_id as pivot_budget_id
from budgets inner join budget_training on budgets.id = budget_training.budget_id
where budget_training.training_id='6'
notice I remove training_id is null and from Laravel generated query. What is wrong with my budgetById method?
You have called get() and didn't use return here:
public function budgetById($training_id){
// = in where is optional in this case
$this->belongsToMany('Budget')->where('training_id', '=', $training_id);
}
You should use like this:
public function budgetById($training_id){
// = in where is optional in this case
return $this->belongsToMany('Budget')->where('training_id', '=', $training_id);
}
In Lavarel 7.X, you can use the wherePivot method to filter columns on the pivot table, like this:
return $this->belongsToMany('Budget')->wherePivot('training_id', '=', $training_id);
or
return $this->belongsToMany('Budget')->wherePivotNotNull('training_id');

laravel test fail in route redirection

i am testing a form. Upon success it must redirect to a route.
Here is the route excerpt
<?php
Route::group(array('prefix'=>'categories'), function(){
Route::get('/', array('as'=>'categories', 'uses'=>'CategoryController#getCategory'));
Route::get('addcategory',array('as'=>'getcategoryform', 'uses'=>'CategoryController#getCategoryForm'));
Route::post('addcategory', array('as'=>'postcategoryform', 'uses' => 'CategoryController#postCategoryForm'));
});
This is the controller
class CategoryController extends BaseController {
// adding Category model instance in the controller through the constructor
public function __construct(Category $category){
$this->category = $category;
}
public function getCategoryForm(){
return View::make('dashboard.addcategoryform');
}
public function postCategoryForm(){
$rules = ['category_name' => 'required|between:3,20', 'options' =>'required'];
$validator = Validator::make(Input::all(), $rules);
if($validator->passes()){
$category = new Category;
$category->category_name = Input::get('category_name');
$category->options = Input::get('options');
$category->save();
Session::flash('message', 'Category Added Successfully');
return Redirect::route('categories');
}else return Redirect::route('getcategoryform')->withErrors($validator);
}
here's the view
#extends('layouts.main')
#section('content')
<div class="g12">
<h1>Add Category</h1>
{{Form::open(array('route'=>'postcategoryform'))}}
{{ Form::text('category_name', Input::old('category_name'), array('placeholder' => 'eg article') )}}
<textarea id="textarea_auto" name="options" value="Input::old('options')" placeholder="eg. author, facts, tags, reference, book"></textarea>
{{Form::submit('Add')}}
{{Form::close()}}
</div>
#stop
This is the test that i tried:
public function testPassedPostCategoryForm(){
Input::replace(['category_name' => 'dummycat', 'options' => 'dummyoption']);
$this->mock
->shouldReceive('create')
->once();
$this->app->instance('Category', $this->mock);
$this->call('POST', 'categories/addcategory');
$this->assertRedirectedToRoute('categories');
}
The test is failing. This is the error i'm, receiving:
There was 1 failure:
1) CategoryControllerTest::testPassedPostCategoryForm
Failed asserting that two strings are equal.
--- Expected
+++ Actual
## ##
-'http://localhost/categories'
+'http://localhost/categories/addcategory'
In your code, the validator is not passed.
So the redirect back to http://localhost/categories leads to fail result.
It goes well if you delete the validator, and simply return such that
public function postCategoryForm(){
$rules = ['category_name' => 'required|between:3,20', 'options' =>'required'];
$validator = Validator::make(Input::all(), $rules);
return Redirect::route('categories');
}
Or you can rewrite the test code as follows,
$this->call('POST', 'categories/addcategory', array( 'category_name'=> 'dummycat' ,
'options' => 'dummyoption'));
or
$this->route('POST','getcategoryform',array( 'category_name'=> 'dummycat' ,
'options' => 'dummyoption'));
instead of
$this->call('POST', 'categories/addcategory');
[Edit] Further, delete followings
$this->mock
->shouldReceive('create')
->once();
,because the 'create' method is not called in the controller.

Categories