Support the ongoing development of Laravel.io →
Input Database Forms
Last updated 7 months ago.
0

@Lameboy, it would help a lot if you exposed your database structure here (the part responsible for storing this information). Maybe a word about your models as well (do you have a separate model for products, is there a many-to-many table between orders and products, etc).

0

do you have _token field in database? if not it will not store it. it might be you have different name for certain fields in db. we can only tell what's the issue after looking at your model and db table. issue might be how you are handling timestamps too :)

0

I do not have columnt _token in the table, but I can create it.

I'll explain more about the database. At the moment I have 3 tables: products, clients and orders. The controller sends the data to the view with:

	public function create()
		{
			$products = Product::orderBy('productId', 'asc')->get();
			$orderNum = Order::all()->last()->orderNum+1;
			$clients = Client::lists('companyName', 'companyName');
			return view('orders.create', compact('products','clients','orderNum'));
		}

I want to store the array in the orders table with columns: company, date_created, nameEn, orderNum, price, qty.

In the models I have just protected $fillable = [...] and public $timestamps = false;

Edit: When I try to submit the order I'm gettig:

  • ErrorException in helpers.php line 740:
  • preg_replace(): Parameter mismatch, pattern is a string while replacement is an array
Last updated 6 years ago.
0

So you want each "ordered product" (as I see from your first post, the form comes back with 54 "ordered products"?) to be stored as a separate row in the "orders" table - is my understanding correct?

0

Lewolf said:

So you want each "ordered product" (as I see from your first post, the form comes back with 54 "ordered products"?) to be stored as a separate row in the "orders" table - is my understanding correct?

@Lewolf, yes, correct. Later I'll add one if to check if there is value in qty column and if it's true it will store it (I want to store only the rows that have quantities).

Last updated 6 years ago.
0
Solution

@Lameboy, before we pass to answering directly your question, I feel urged to express some serious concerns about the code you've shown so far.

1/ This line:

$orderNum = Order::all()->last()->orderNum+1;

which is used to populate the "orderNum" form field represents a data mapping issue. Imagine that your database already have 4 orders. As such, the above code line, when called next time, will return "5".

Now imagine two customers who have opened your form at the same time.

  • Customer A opens the form and has "5" in the orderNum hidden field
  • Customer B opens the form at the same time and also has "5" in the orderNum hidden field, since customer A hasn't yet submitted the form
  • Now customer A submits the form, and his records are saved in orders table with orderNum =5
  • Now customer B submits the form, and her records are again saved in orders table with orderNum =5

Voila, two orders from two different customers are now merged into one and prepare a nice little future headache.

2/ This line:

{!! Form::hidden('price[]', $product->price) !!}

is a classical vulnerability, someone tinkering with your form in their browser devtools will be able to submit whatever price he wants for your products and buy all your products for 0.02 dollar (if he's generous enough) or for 0.01 dollar (if he's greedy).

==============

Ok, above being something you'll probably want to think about later, here's an answer to your original question:

$input = $request->all();

for($i=0; $i<= count($input['qty']); $i++) {

  if(empty($input['qty'][$i]) || !is_numeric($input['qty'][$i])) continue;

  $data = [ 
    'nameEn' => $input['nameEn'][$i],
    'company' => $input['company'],
    'orderNum' => $input['orderNum'][$i], // see above for why this might be a bad idea
    'price' => $input['price'][$i], // see above for why this might be a bad idea
    'date_created' => date('Y-m-d h:i:s'),
    'qty' => intval($input['qty'][$i])
  ];

  Order::create($data);
}
Last updated 6 years ago.
1

Thank you very much @Lewolf!!! Works perfectly!

I understand your concerns and I tought about them before. At first place I want to have my code working, than I'll try to fix the issues. As you can see, I'm totally new here and want to learn. At this point I'm not familiar with all the technics in Laravel. At first place I'll try to understand the code from your post above. Then I'll take a look at the problems you mentioned. I'm sure there is a way to send the data to the Model (or somewhere else) and then to store it in the database depending on the user input but I still do not know if this is realy possible and how to do it. Maybe you can point me where to read more about it.

Regarding the orderNum, maybe I can add company name before the number or I'll think for another workaround.

In my plan is to add another table 'discounts'. I want to set discount values for some of the clients. For example client_1 will have 10% discount on product_1 and 15% on product_2. Client_2 will have 5% discount on product_1 and 8% on product_2 and so on. This will be real challenge for me but I have my time and motivation. Ofcourse, I'll get back to this wonderful forum with my question when I stuck again.

Thank you once again for your help!

0

@Lameboy, you are welcome, just keep one thing in mind, NEVER trust ANY user input and NEVER rely on ANY user input (including headers such as cookies but that's a more advanced topic of course). If you can set a thing on the server, instead of accepting it from your user, do set it on the server and you will save yourself a big headache.

In your example, you might want to consider only accepting product_id, company_id, and qty from user input. After that, you can safely pull company name, product name, product price from your database and rely on that data.

Regarding orderNum, I don't see a reason why not have a separate "orders" table where you keep just order numbers (auto incrementing), and then "order_products" for the purpose that you now have "orders" for, at least that's how they usually do it.

So that your flow looks like this when a new order comes:

  • check if customer has ordered any products at all, if not, error out;
  • create a new order in orders table and pick its auto incremented id;
  • NOW for each ordered product, look up product and company values from your database (not customer input, as I detailed above) and insert a record into order_products and your orderNum will be safe unique value from above step.

I hope this information is useful or at least will save you some later restructuring by building things the right way from the start.

0

Thank you very much for the information and for your help @Lewolf.

What do you think is there any security issue if I send all the data for a table products to the view with:

   public function create()
      {
         $products = Product::orderBy('productId', 'asc')->get();  // maybe this is a problem?
	 $clients = Client::lists('companyName', 'id');
	 return view('orders.create', compact('clients', 'products'));
      }

And then the following to the viewer.

@foreach ($products as $product)
     {!! Form::label('product', $product->longName) !!}
     {!! Form::hidden('id[]', $product->id) !!}
     {!! Form::text('qty[]',Input::old('qty'), ['class' => 'form-control']) !!}
@endforeach

Thanks!

0

Fixed by replace:

$products = Product::orderBy('productId', 'asc')->get();

with

$products = Product::select('id', 'longName')->orderBy('productId','asc')->get();
0

LameBoy said:

Thank you very much for the information and for your help @Lewolf.

What do you think is there any security issue if I send all the data for a table products to the view with:

  public function create()
     {
        $products = Product::orderBy('productId', 'asc')->get();  // maybe this is a problem?
   $clients = Client::lists('companyName', 'id');
   return view('orders.create', compact('clients', 'products'));
     }

And then the following to the viewer.

@foreach ($products as $product)
    {!! Form::label('product', $product->longName) !!}
    {!! Form::hidden('id[]', $product->id) !!}
    {!! Form::text('qty[]',Input::old('qty'), ['class' => 'form-control']) !!}
@endforeach

Thanks!

No issues with passing everything to view, but in your view you should control information that is sent out to user's browser.

Another point is that, if you pull lots of rows / columns from database, it can affect performance, so it's advisable to restrict columns in your queries to only those you need, so your later fix looks reasonable.

Last updated 6 years ago.
0

Sign in to participate in this thread!

LoadForge

Your banner here too?

LameBoy lameboy Joined 22 Mar 2016

Moderators

We'd like to thank these amazing companies for supporting us

Your logo here?

Laravel.io

The Laravel portal for problem solving, knowledge sharing and community building.

© 2022 Laravel.io - All rights reserved.