I've got the following validation rules for basic authentication of a Payment Method (advanced things, like CVD validation, existing card, etc. is handled afterward by Moneris).
$rules = [
"type" => "required|in:visa,mastercard",
"nickname" => "required",
"credit_card_number" => "required|numeric|digits:16",
"expiry" => "required|string|size:5|date_format:m/y|after:today",
"cvd" => "required|numeric|digits:3"
];
The rule expiry is not accepting a specific value, 04/yy, but it is accepting 03/yy and 05/yy; I have no idea why this is happening, but I need it remedied. Has anyone come across this behaviour?
For reference, the result dd($request->input(), $validator->passes(), $validator->errors()); when I pass 04/19 is as follows:
array:6 [▼
"type" => "visa"
"nickname" => "Testing"
"credit_card_number" => "4242424242424242"
"expiry" => "04/19"
"cvd" => "123"
"masked_pan" => "************4242"
]
false
MessageBag {#502 ▼
#messages: array:1 [▼
"expiry" => array:1 [▼
0 => "The expiry does not match the format m/y."
]
]
#format: ":message"
}
When I send 05/19, everything works fine:
array:6 [▼
"type" => "visa"
"nickname" => "Testing"
"credit_card_number" => "4242424242424242"
"expiry" => "05/19"
"cvd" => "123"
"masked_pan" => "************4242"
]
true
MessageBag {#502 ▼
#messages: []
#format: ":message"
}
Looks like it's an issue with how this validation rule works in Laravel 5.4. To fix, I check the date validity of the input prepended with 01/, and if it is valid, merge that into the request, with endOfMonth() to handle after:today validation:
$mergeDate = null;
$rawInput = $request->input("expiry");
try {
$mergeDate = Carbon::createFromFormat("d/m/y", "01/".$request->input("expiry"))->endOfMonth();
} catch(\Exception $ex){}
$request->merge([
"masked_pan" => str_repeat("*", 12).substr($request->input("credit_card_number", ""), -4),
"expiry" => $mergeDate ? $mergeDate->format("d/m/y") : $request->input("expiry")
]);
So now, if I pass 04/22, it will check if 01/04/22 is valid, then convert to end of month 30/04/22, then replace that as the value passed to the validation (which also needs to be updated)
"expiry" => "required|string|size:8|date_format:d/m/y|after:today",
I also have to update and pass $messages to avoid confusion to the user:
$messages = [
"expiry.size" => "The :attribute filed must be 5 characters.",
"expiry.date_format" => "The :attribute field does not match the format m/y"
];
$validator = \Validator::make($request->all(), $rules, $messages);
And finally, replace the value with the raw input if there's an error (so the user doesn't see a value they didn't enter)
if(!$validator->passes()){
$request->merge(["expiry" => $rawInput]);
return back()->withErrors($validator)->withInput();
}
A whole bunch of nonsense, but seems to handle 04/22 and other dates just fine.
Related
I have a builder which creates a select with options for hours and minutes for me:
$builder->add("startTime", 'Symfony\Component\Form\Extension\Core\Type\TimeType', [
"required" => true,
"attr" => [
"class" => "da_start",
"id" => "da_start",
"name" => "da_start"
],
"data" => new \DateTime($start),
"empty_data" => 'default',
"label_attr" => [
"class" => "da_start_label",
],
"minutes" => $options['minutes'],
"hours" => $start_hours_range,
"constraints" => [
new LessThanOrEqual([
"value" => $startCheck,
"message" => "1-2"
])
]
]);
Inside I have a constraints array and I want to validate this field so that if the value entered is greater than $startCheck variable an error message would be displayed.
$startCheck variable is generated like so:
$startCheck = new \DateTime('today' . $options['lessThan']);
and represents following dateTime Object:
DateTime {#1056 ▼
+"date": "2021-09-23 06:30:00.000000"
+"timezone_type": 3
+"timezone": "Europe/Berlin"
}
which means that if I enter 06:45 to my form the validation should not pass.
Here is a dump of the value that I get from my form:
DateTime {#52 ▼
+"date": "2021-09-23 06:45:00.000000"
+"timezone_type": 3
+"timezone": "Europe/Berlin"
}
And this value passes fine and is being written to DB. What am I doing wrong here?
Ok so it turned out that Symfony generated not the date object of today, but the one for 1970-01-01 (Unix epoche start).
That's why $startCheck variable should be initialized like:
$startCheck = new \DateTime('1970-01-01T' . $options['lessThan']);
Kind of dirty, but this wotks fine for this type of comparison.
Been trying to find a way to call to pass a multidimensional array to a Post route with no success.
The array looks like this:
"order" => array:16 [
"id" => "1"
"total" => "4825"
"neighborhood" => "Barrio Bravo"
]
"products" => array:2 [
4 => array:4 [
"id" => "4"
"name" => "Maestro Dobel 750ml"
"price" => "530"
"quantity" => "1"
]
1 => array:4 [
"id" => "1"
"name" => "Don Julio 70 700ml"
"price" => "650"
"quantity" => "1"
]
]
"grandTotal" => "1180"
"balanceToPay" => "354"
"cartTotal" => "826"
I don't have any problem asserting the route in the unit test calling the route like so:
$this->post(route('order.success', $orderInfo));
But when it comes to the controller I can't find the way to redirect to order.success with its orderInfo array.
This won't work since redirect only works with GET:
return redirect(route('order.success', $orderInfo));
Ideas?
It's not going to work with a simple redirection because you cannot choose the HTTP method. It's always GET when you make a redirection. It works in your test because you make a POST request manually.
I can see 2 solutions:
You can send data using GET method (they are added as URL parameters). If they are not confidential it can be a solution.
If you don't want to send those data in the URL, you have to save them somewhere and get them from the storage when you're on the order.success page. You can save them, for instance, in the session storage or in the local storage of your browser.
Also, your test isn't good if it tests a behavior that does not happen in your app (post request instead of redirection).
I have a form that submits an array named prazos, and I want to make sure each item is a valid datetime or null. Following the answers to this question and the Laravel docs, I have this in my Controller:
use Illuminate\Support\Facades\Validator;
// ...
$rules = array([
'prazos' => 'required|array',
'prazos.*' => 'nullable|date'
]);
$validator = Validator::make($request->all(), $rules);
$data = $validator->valid()['prazos'];
foreach($data as $id => $prazo) {
// use $data to update my database
// ...
}
The issue is, the validator is not actually stopping invalid content. If I try to submit "loldasxyz" or other gibberish, I get an error from the database. What am I doing wrong?
Note: previously I had been using validators with the syntax $data = $request->validate($rules), but for some reason it didn't work for the array-type data ($data came back empty). I'm not sure if there is some difference in how those different methods work.
Edit: this is what the parameter bag in $request looks like when I test it (the indices are ids, which is why they start at 1):
#parameters: array:3 [▼
"_token" => "Rf6mAp4lqhpZzQRxaxYsees1M0NfrFKpbGe4Hy28"
"_method" => "PUT"
"prazos" => array:5 [▼
1 => "2021-03-22 21:21"
2 => "2021-03-03 11:27"
3 => "jhbkjhg"
4 => null
5 => "2021-03-02 14:21"
]
]
And this is what the validated $data comes out as:
array:5 [▼
1 => "2021-03-22 21:21"
2 => "2021-03-03 11:27"
3 => "jhbkjhg"
4 => null
5 => "2021-03-02 14:21"
]
I wish it would tell me the third value is invalid.
Heres what youre looking for:
https://laravel.com/docs/8.x/validation#rule-date-equals
The field under validation must be equal to the given date. The dates will be passed into the PHP strtotime function in order to be converted into a valid DateTime instance.
Seems like nobody in the last 5 years has tried to get PayPal to work with a Laravel site on PHP so I am forcibly asking now.
I am using this package: https://github.com/srmklive/laravel-paypal
And I am sending PayPal this:
array:6 [▼
"items" => array:2 [▼
0 => array:3 [▼
"name" => "Product 1"
"price" => 9.99
"qty" => 1
]
1 => array:3 [▼
"name" => "Product 2"
"price" => 4.99
"qty" => 2
]
]
"return_url" => "https://github.com/payment/success"
"invoice_id" => "PAYPALDEMOAPP_1"
"invoice_description" => "Order #PAYPALDEMOAPP_1 Invoice"
"cancel_url" => "https://github.com/cart"
"total" => 19.97
]
These values are purely for testing of course but they should work.
However, I get this error:
array:3 [▼
"type" => "error"
"message" => ""
"paypal_link" => null
]
My code looks like this:
public function start()
{
$provider = new ExpressCheckout();
$data = [];
$data['items'] = [
[
'name' => 'Product 1',
'price' => 9.99,
'qty' => 1,
],
[
'name' => 'Product 2',
'price' => 4.99,
'qty' => 2,
],
];
$data['return_url'] = 'https://github.com/payment/success';
$data['invoice_id'] = 'PAYPALDEMOAPP_' . 1;
$data['invoice_description'] = "Order #{$data['invoice_id']} Invoice";
$data['cancel_url'] = 'https://github.com/cart';
// $data['return_url'] = url('/payment/success');
// $data['cancel_url'] = url('/cart');
$total = 0;
foreach($data['items'] as $item) {
$total += $item['price'] * $item['qty'];
}
$data['total'] = $total;
$response = $provider->setExpressCheckout($data);
dd($response);
return redirect($response['paypal_link']);
}
These values are exactly the same as the one used by https://github.com/srmklive/laravel-paypal-demo/
Which is a working demo!
I looked into it further an found where the requests are sent within the package and it sends a POST Request to https://api-3t.sandbox.paypal.com/nvp and when I recreate the request with the same postdata in postman, I get ACK=Failure&L_ERRORCODE0=81002&L_SHORTMESSAGE0=Unspecified%20Method&L_LONGMESSAGE0=Method%20Specified%20is%20not%20Supported&L_SEVERITYCODE0=Error which is what I believe the real error to be.
If anyone could help, that'd be great!
The package you linked to is ancient, 2 generations out of date as far as PayPal APIs go. Don't use it.
Here is the current PHP SDK (not laravel specific): https://github.com/paypal/Checkout-PHP-SDK
It should be used to create two routes on your server, one to 'Set up Transaction', and one to 'Capture Transaction'. Here is a guide: https://developer.paypal.com/docs/checkout/reference/server-integration/
Those 2 routes should be called by this front-end code: https://developer.paypal.com/demo/checkout/#/pattern/server
Double check that credentials are configured correctly.
validate_ssl may also need to be set to false: https://github.com/srmklive/laravel-paypal/issues/229#issuecomment-472755054
I wanted to use this package for geocoding in Laravel. I have added it to providers and published the config, but I am getting trouble setting it up to work.
try {
$location = Geocoder::geocode('68.145.37.34')->get();
return $location;
} catch (\Exception $e) {
return $e;
}
This returns empty object.
I have left the config file as is.
return [
'cache-duration' => 9999999,
'providers' => [
Chain::class => [
GoogleMaps::class => [
'en-US',
env('GOOGLE_MAPS_API_KEY'),
],
GeoPlugin::class => [],
],
],
'adapter' => Client::class,
];
And added valid API key to env. Is there something I'm missing?
Geocoder is imported as use Geocoder\Laravel\Facades\Geocoder;
EDIT
In case someone gets to the same problem...this is how you'd get the country from it:
app('geocoder')->geocode('5.43.168.58')->get()->first()->getCountry()->getName();
Really complicated unnecessarily in my opinion, I requested a documentation change on official repo.
did you try using dd() in tinker?? I have been try it...and it work for me..
try this :
dd(app('geocoder')->geocode('68.145.37.34')->get());
response :
Illuminate\Support\Collection {#764
items: array:1 [
0 => Geocoder\Model\Address {#753
-coordinates: Geocoder\Model\Coordinates {#755
-latitude: 51.0823
-longitude: -113.9578
}
-bounds: null
-streetNumber: null
-streetName: null
-subLocality: null
-locality: "Calgary"
-postalCode: null
-adminLevels: Geocoder\Model\AdminLevelCollection {#767
-adminLevels: array:1 [
1 => Geocoder\Model\AdminLevel {#768
-level: 1
-name: "Alberta"
-code: "AB"
}
]
}
-country: Geocoder\Model\Country {#769
-name: "Canada"
-code: "CA"
}
-timezone: null
-providedBy: "geo_plugin"
}
]
}