I am very much new to laravel framework.
I have one form , which i need to update on submit button click.
when submit button clicks control goes to controller.php 's update() function .
But I am unable to edit any field's value.
here is my code.
public function update($id)
{
//echo "<pre>";print_r(Input::all());exit;
$product = $this->product->find($id);
$input = Input::only('designer', 'sku', 'name', 'display_name', 'description', 'price', 'main_category', 'sub_category', 'lead_time', 'sizing', 'woven', 'body_fabric', 'lining_fabric', 'fit', 'primary_color', 'secondary_color', 'care_label', 'neck_type', 'closure', 'trims', 'special_finishings', 'image1', 'image2', 'image3', 'image4', 'image5','top', 'combo_products', 'keywords', 'visibility', 'featured');
//echo "<pre>";print_r($input);exit;
try
{
$this->adminNewProductForm->validate($input);
} catch(\Laracasts\Validation\FormValidationException $e)
{
return Redirect::back()->withInput()->withErrors($e->getErrors());
}
$slug = Str::slug(Input::get('name'));
$slug = $this->product->getSlug($slug);
$input = array_add($input, 'slug', $slug);
DB::transaction(function() use($product, $input)
{
$product->fill($input)->save();
$stock_count = 0;
if(!empty(Input::get('xsmall_size')))
{
$rows = DB::table('products_variants')->where('product_id', $product->id)->where('variant_name', 'XS')->get();
$stock_count += Input::get('xsmall_stock');
if(!empty($rows))
{
DB::table('products_variants')->where('product_id', $product->id)->where('variant_name', 'XS')->update(array('variant_specs' => Input::get('xsmall_size'), 'price_change' => Input::get('xsmall_price'), 'total_stock' => Input::get('xsmall_stock'), 'stock_used' => 0));
} else {
DB::table('products_variants')->insert(array('product_id' => $product->id, 'variant_name' => 'XS', 'variant_specs' => Input::get('xsmall_size'), 'price_change' => Input::get('xsmall_price'), 'total_stock' => Input::get('xsmall_stock'), 'stock_used' => 0));
}
}
$input = array();
$input['flagship_status'] = Input::get('flagship_status');
if(Input::get('flagship_status'))
{
$input['stock_count'] = Input::get('small_stock');
}else {
$input['stock_count'] = $stock_count;
}
$product->fill($input)->save();
});
//echo "<pre>";print_r(Input::all());exit;
return Redirect::back()->withFlashMessage('Product Updated Successfully!');
}
Also I cant understand , what is going on by this line ? because i did not find validate function anywhere in my code.
$this->adminNewProductForm->validate($input);
I need to update table products not products_variants.
validate is inherited from the FormRequst class.
https://laravel.com/api/5.0/Illuminate/Foundation/Http/FormRequest.html#method_validate
You've provided too much code and too little information. You said you need to update a specific table, but yet there are two lines where you are very intentionally manually updating a database entry.
This is one of them:
DB::table('products_variants')->where('product_id', $product->id)->where('variant_name', 'XS')->update(array('variant_specs' => Input::get('xsmall_size'), 'price_change' => Input::get('xsmall_price'), 'total_stock' => Input::get('xsmall_stock'), 'stock_used' => 0));
When you call this:
$product->fill($input)->save();
It also saves 'dirty' (modified) models that also belong to it, which can include products_variants relationships. From the sound of it, you are incorrectly applying changes directly through SQL, and then the model's save method is overwriting it.
You seem unclear about what your code is actually doing, and I would strongly suggest simplifying it down and adding in code as you begin to understand what each line does. I think your question is the byproduct of copying an example and adding your own work without understanding how Laravel handles relationships and models. There is almost never a good reason to use raw SQL or DB statements.
Related
I am working on my first project using Laravel 5.1. Uses a selectbox in a form.
{!!Form::select('animal_parent[]', array('1' => 'opt1', '2' => 'opt2', '3' => 'opt3', '4' => 'opt4',), null, ['id' => 'animal_parent', 'disabled' => 'disabled', 'multiple' => 'multiple', 'class' => 'form-control'])!!}
Selection limited to two options which need to saved in two columns, male_parent and female_ parent of the animal table.
There are no male_parent and female_ parent element names in the form. Similarly no animal_parent field in animal table.
Values are set as expected in the code given below. However, the insert command does not reflect the newly set values and throws an error.
"ErrorException in helpers.php line 671: preg_replace(): Parameter mismatch, pattern is a string while replacement is an array."
Any help would be much appreciated.
First attempt using mutators
public function setMaleParentAttribute()
{
$parent = Input::get('animal_parent');
$this->attributes['male_parent'] = intval($parent[0]);
}
public function setFemaleParentAttribute(AddAnimalRequest $request)
{
$parent = Input::get('animal_parent);
if (isset($parent[1])) {
$this->attributes['female_parent'] = intval($parent[1]);
} else {
$this->attributes['female_parent'] = intval($parent[0]);
}
unset($request->animal_parent);
}
Second attempt using the store() method in the controller.
$animal = new Animal($request->all());
$parent = Input::get('animal_parent');
$animal['male_parent'] = intval($parent[0]);
if (isset($parent[1])) {
$animal['female_parent'] = intval($parent[1]);
} else {
$animal['female_parent'] = intval($parent[0]);
}
unset($request->animal_parent);
Auth::user()->animals()->save($animal);
return redirect('animals');
The problem was then solved with a change in UI. I feel the problem could have been solved using the below method. Hope that helps someone.
$input = $request->all();
$parent = $input['animal_parent'];
$input['male_parent'] = intval($parent[0]);
if (isset($parent[1])) {
$input['female_parent'] = intval($parent[1]);
} else {
$input['female_parent'] = intval($parent[0]);
}
unset($input['animal_parent']);
$animal = new Animal($input);
$animal->save();`
I am using the MultiForm module to submit a long form with SilverStripe. The logic for this form is in 'CampaignBriefForm.php' whereas the gridfield CMS field is being added in 'CampaignBriefPage.php'. I have a Data Object for a CampaignBriefLead which is what the form creates.
Campaign Brief Page
private static $has_many = array(
'CampaignBriefLeads' => 'CampaignBriefLead'
);
public function CampaignBriefForm() {
return new CampaignBriefForm($this, 'CampaignBriefForm');
}
Campaign Brief Lead (DO)
private static $has_one = array( "Page" => "CampaignBriefPage" );
As you can see the Campaign Brief page has the correct relationship with the Data Object and also you can see the the form itself (done in a sepearate file) is correctly returning (as it's being saved in the DB). For some reason however, the gridfield will not show me what is in the database for that Data Object. The grid field code is as follows.
$fields = parent::getCMSFields();
$contactConfig = GridFieldConfig_RelationEditor::create();
$contactConfig->getComponentByType('GridFieldDataColumns')->setDisplayFields(
array(
'CompanyName' => 'Company Name',
'StartDate' => 'Start Date',
'Duration' => 'Duration',
'WebsiteURL' => 'Website',
'Budget' => 'Budget'
));
$contactGrid = new GridField(
'CampaignBrief',
'Campaign Enquiries',
$this->CampaignBriefLeads(),
$contactConfig
);
$fields->addFieldToTab("Root.Enquiries", $contactGrid);
To me this all looks correct and should work but for some reason it is not working.
Note
The link existing option on the gridfield allows me to link one of the entries from the DO with the gridfield weirdly?? So it saves one entry but I have to do it manually, this tells me it can see the DB but won't pull for some reason.
For reviewing reasons, here is the code for the multiform where the campaign brief lead is actually saved to the DB after the form is submitted.
public function finish($data, $form) {
parent::finish($data, $form);
$steps = DataObject::get(
'MultiFormStep',
"SessionID = {$this->session->ID}"
);
$enquiry = new CampaignBriefLead();
foreach($steps as $step) {
$data = $step->loadData();
foreach($data as $key => $value) {
if($key == 'url' || $key == 'MultiFormSessionID' || $key == 'action_finish') {
continue;
}
if(isset($data[$key])) {
$enquiry->$key = $data[$key];
error_log($data[$key]);
}
}
}
$enquiry->write();
$this->controller->redirect('/campaign-brief/');
}
If you need anything more let me know. Thanks.
I would take a guess that the CampaignBriefLead PageID is not being set on your form submission.
Check the CampaignBriefLead table in your database and check the PageID column. If it is blank, null or 0 for each row then it is not being set.
One way to fix this problem for any new submission is to set the PageID for the $enquiry:
public function finish($data, $form) {
// ...
$enquiry = new CampaignBriefLead();
if ($campaignBriefPage = CampaignBriefPage::get()->first()) {
$enquiry->PageID = $campaignBriefPage->ID;
}
// ...
}
For the existing entries you will need to update the entries to have the correct PageID.
I'm searching for a cleaner way to validate tags when storing a Post.
All of the input validation takes place within my custom request StorePostRequest. The problem is that I need to check whether the given tags exist in the database, only existing tags are allowed. The function $request->input('tags') returns a string with comma seperated values, for example: Tag1,Tag2,Tag3.
Here is the code:
/**
* Store a newly created resource in storage.
*
* #param StorePostRequest $request
* #return Response
*/
public function store(StorePostRequest $request)
{
//THIS PIECE OF CODE
$tags = explode(',', $request->input('tags'));
$tags = Tag::whereIn('title', $tags)->lists('id');
if(count($tags) < 1)
{
return redirect()->back()->withInput()->withErrors([ trans('tags.min') ]);
}
else if(count($tags) > 5)
{
return redirect()->back()->withInput()->withErrors([ trans('tags.max') ]);
}
//TILL HERE
$post = $request->user()->posts()->create([
'slug' => unique_slug('Post', $request->input('title')),
'title' => $request->input('title'),
'description' => $request->input('description'),
'summary' => $request->input('summary'),
]);
$post->tags()->attach($tags);
return redirect(route('theme.post.show', [$theme->slug, $post->slug]))->with(['success', trans('messages.post.store')]);
}
The code is a little sloppy and redundant when using it in multiple controllers.
In order to solve this, I've created a ValidationServiceProvider to extend the core validator rules. Something like this:
$this->app['validator']->extend('tags', function ($attribute, $value, $parameters)
{
$tags = explode(',', $value);
$tags = Tag::whereIn('title', $tags)->lists('id');
if(count($tags) < 1 || count($tags) > 5))
{
return false;
}
});
Pretty neat. The thing is I still need to be able to access the $tags variable within the controller (because of ->attach($tags)).
Is there a better way of tackling this problem? Or should I stop thinking and just use (and repeat) the code I have?
Thanks in advance, hope it makes some sence.
I am assuming that you understand the use of this class because I have seen that you have defined StorePostRequest class. So, just for clarify, the rules method could looks like:
public function rules()
{
return [
'tags' => ['required', 'tags'] //kb
];
}
Finally, with all the tools in correct place, you only make manipulate the data in your controllers like this:
public function store(StorePostRequest $request)
{
// at this point, the tags are already validated, so we, proceed get them:
$tags = explode(',', $$request->get('tags'));
$post = $request->user()->posts()->create([
'slug' => unique_slug('Post', $request->input('title')),
'title' => $request->input('title'),
'description' => $request->input('description'),
'summary' => $request->input('summary'),
]);
$post->tags()->attach($tags);
return redirect(route('theme.post.show', [$theme->slug, $post->slug]))->with(['success', trans('messages.post.store')]);
}
Keep in mind that inyecting StorePostRequeststore in the controller's function it is already validating and running the rules.
That is enough if you really has defined the StorePostRequest's rules correctly.
foreach($request->tags as $k=>$tags){
$this->validate($request, [
'tags.'.$k => 'required|string|max:20'
]);
}
I'm converting a database from being managed by SQL dumps to being managed by schemas and migrations. Part of this is seeding data. I've based what I'm doing from the schema example on CakePhp's page about Schemas.
The weird thing is that the first table to be seeded with data works without problem, and the second fails with an error like Table users for model User was not found in datasource default. This happens even if I change which table will be seeded: the first one succeeds (and I've checked in the database that the data is there) and the next one to be seeded fails.
I've also checked the error message against the database, and every table it complains about not existing does actually exist.
My 'schema.php' looks like this:
class AppSchema extends CakeSchema {
public function before($event = array()) {
return true;
}
private function create_many($class_name, $entries){
App::uses('ClassRegistry', 'Utility');
$class = ClassRegistry::init($class_name);
foreach($entries as $entry){
$class->create();
$class->save(array($class_name => $entry));
}
}
private function create_many_kv($class_name, $keys, $values_matrix){
$entries = array();
foreach($values_matrix as $values){
array_push($entries, array_combine($keys, $values));
}
$this->create_many($class_name, $entries);
}
public function after($event = array()) {
if (isset($event['create'])) {
switch ($event['create']) {
case 'users':
$this->create_many('User', array(
array('emailaddress' => 'email',
'password' => 'hash',
'role_id' => 1
),
array('emailaddress' => 'email2',
'password' => 'hash',
'role_id' => 3)
));
break;
case 'other_table':
$this->create_many('OtherTable', array(
array('id' => 1,
'name' => 'datum'),
array('id' => 2,
'name' => 'datum2')
));
break;
etc.
The answer for me here was to populate all of the tables after the last table has been created.
My best hypothesis for why this didn't work as described in the question is that Cake is caching the database structure in memory, and this isn't updated when the new tables are added. I can't find any documentation about clearing that structure cache so a workaround is the closest thing to a solution for now.
When inserting data to more than one table you’ll need to flush the database cache after each table is created. Cache can be disabled by setting $db->cacheSources = false in the before action().
public $connection = 'default';
public function before($event = array()) {
$db = ConnectionManager::getDataSource($this->connection);
$db->cacheSources = false;
return true;
}
I am creating a basic CMS to teach myself the fundamentals of Laravel and PHP.
I have a 'pages' table and I am storing a url_title. I want this URL title to be unique for obvious reasons. However, whatever I do to validate it, fails. It just saves anyway. I'm sure it is something simple. Can you spot what is wrong with this code?
I am also using Former in the view, that doesn't validate either. I have tried hard-coding a value as the last option in the unique method and it fails also.
http://anahkiasen.github.io/former/
http://laravel.com/docs/validation#rule-unique
States: unique:table,column,except,idColumn
Here is my Controller:
public function store()
{
$validation = Pages::validate(Input::all());
if($validation->fails()) {
Former::withErrors($validation);
return View::make('myview');
} else {
Pages::create(array(
'title' => Input::get('title'),
'url_title' => Input::get('url_title'),
'status' => Input::get('status'),
'body' => Input::get('body'),
'seo_title' => Input::get('seo_title'),
'seo_description' => Input::get('seo_description')
));
//check which submit was clicked on
if(Input::get('save')) {
return Redirect::route('admin_pages')->with('message', 'Woo-hoo! page was created successfully!')->with('message_status', 'success');
}
elseif(Input::get('continue')) {
$id = $page->id;
return Redirect::route('admin_pages_edit', $id)->with('message', 'Woo-hoo! page was created successfully!')->with('message_status', 'success');
}
}
}
Here is my model:
class Pages extends Eloquent {
protected $guarded = array('id');
public static $rules = array(
'id' => 'unique:pages,url_title,{{$id}}'
);
public static function validate($data) {
return Validator::make($data, static::$rules);
}
}
I have tried the following:
public static $rules = array(
// 'id'=> 'unique:pages,url_title,{{$id}}'
// 'id'=> 'unique:pages,url_title,$id'
// 'id'=> 'unique:pages,url_title,:id'
// 'id'=> 'unique:pages,url_title,'. {{$id}}
// 'id'=> 'unique:pages,url_title,'. $id
);
Any ideas? I spoke to the guy who created Former. He can't make head nor tail about it either. He suggested tracking it back to find our what query Laravel uses to check the uniqueness and try running that directly in my DB to see what happens. I can't find the query to do this. Does anyone know where to track it down?
Many thanks
Your rule should be:
public static $rules = array(
'url_title' => 'unique:pages,url_title,{{$id}}'
);
As I guessed from your code Input::get('url_title')
You have to use the field name used in the form.
Thanks peeps. I have been using the Laravel unique solutions and it hasn't been working well. I found this package which solves the issue brilliantly.
https://github.com/cviebrock/eloquent-sluggable#eloquent
Definitely worth a look.
Thanks for your feedback.