YII - Adding error code in form validation - json

I have a web-service and want to send a custom error-code and string in case form validation fails. We can specify error 'message' in form validation rules, but I want to add a numerical error code, that I can use later to get a text string. Extending CValidator is not an option as I want to use standard validators.
Ideally, I would like something like this in my rules() function.
array('page', 'numerical', 'integerOnly' => true, 'min' => 1, 'message' => '{attribute} is invalid', 'code' => 10079),
Later I return a JSON block like
{
'code': 10079,
'message' : 'page is invalid'
}
I am thinking of attaching a behavior to validators, but not quite able to figure out a way to make it work. Is there any other yii-way to do it?

instead of message , you just return the error code as message and on the view page just call a function to retrieve the appropriate error message.
provide $form->error(); as parameter to get errorMessage on the view page.

Related

How to route a url to include scrolling down to a div id in Laravel

I am validating a contact form. I wrapped it in a div with the id of "contactform". When validation messages appear after submission I want the redirected page to scroll down automatically to the "contactform" div so users don't have to scroll down themselves to correct the form.
I can accomplish this easily by manually typing the url:localhost:8000/#contactform
However I cannot get the routing to work in Laravel.
I tried altering the controller to:
return Redirect::to('/#contactform');
I tried:
return Redirect::to('#contactform');
return Redirect::to('/' . '#contactform');
return view('/')->with('#contactform');
return view('/#contactform');
return view('/pages.index.#contactform');
return view('/pages.index#contactform');
They all return without the #contactform in the url.
I know there is a javascript way to accomplish this, but I was really trying to stay away from javascript for now. There has to be a simpler way I just cannot see it. I'm new to Laravel and completely self-taught. Thanks
***EDIT
I tried a new controller step by step. Without validation it works. Validation seems to break it.
This works:
public function store() {
return (string) Redirect::to('/#contactform');
}
This breaks it:
public function store(Request $request) {
$this->validate($request, [
'first_name' => 'required',
'last_name' => 'required',
'email' => 'required|email',
'telephone' => 'nullable',
'comments' => 'required',
]);
return (string) Redirect::to('/#contactform');
}
The top of the controller page I call the request and redirect like this:
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Redirect;
Can anyone help me get down to the reason why I cannot validate without breaking the url route?
On validation failure it will cause a redirect 'back'. It is entirely possible that 'back' is the same URI you want to redirect to, so from your perspective it looks like it is redirecting wrong when it is correct. If you remove the validation you should get the correct redirect.
Side note: On the server side the hash is not part of the URL. It is a client side thing.
A solution that works for me is to compact() a Boolean variable through the controller.
Link example
Passing the variable to the controller
Route::get('/post={post_id}+{scroll}',[PostController::class, 'show']);
If the variable equals 'scroll' then switch the boolean variable to true
public function show($post_id, $scroll){
if($scroll == 'scroll'){
$scroll = true;
}else{
$scroll = false;
}
return view('yourview', compact('scroll'))
}
Run the script if $scroll is true
<script>
#if($scroll)
$(document).ready(function () {
$('html,body').animate({ scrollTop: 99999 }, 'slow');
});
#endif
</script>

Yii2 ActiveForm Stripe token

In Yii2, we are using \Stripe\Charge::create following the site's documentation example:
https://stripe.com/docs/payments/accept-a-payment-charges
Everything works great as long we use straight HTML in the views, but when we embed the card-element in an ActiveForm, the stripe.js returns:
XMLHttpRequest cannot load https://api.stripe.com/v1/tokens due to
access control checks.
We would like to use ActiveForm to simplify the validation and handling of other fields on the form. Any help?
Best,
Joe
The error is CORS related, see CORS. Use the appropriate Access-Control as described there.
You can use Yii's build in behavior yii\filters\Cors in your controller.
Try first without any restriction:
public function behaviors()
{
return [
'corsFilter' => [
'class' => \yii\filters\Cors::className(),
],
];
}
If it works, than you can restrict the access by parametrising the behavior, something like that:
public function behaviors()
{
return [
'corsFilter' => [
'class' => \yii\filters\Cors::className(),
'cors' => [
'Origin' => [https://api.stripe.com'],
'Access-Control-Request-Method' => ['POST', 'PUT'],
],
],
];
}
So, for anyone landing here, the only way I can get this to work is to remove the ActiveForm scaffolding. Real bummer because I've had to validate the non-Stripe input fields with Javascript, which is lot more work.
I do challenge anyone to post working code in Yii using ActiveForm that will return a token. I don't think it can be done...but I would love to be wrong.
Best,
Joe

$.post(url, data) doesn't work

I'm creating simple twitter_clone using Rails to create json API and ReactJS in frontend.
What I need now is to save new created tweet into DB and then to update an API in json which contain list of tweets to be able to use them to render a view.
To achieve it I try to use post request:
My add tweet function in main.jsx file
addTweet(tweetToAdd){
$.post("/tweets", { body: tweetToAdd }) //after saving to database
.success( savedTweet => {
let newTweetsList = this.state.tweetsList;
newTweetsList.unshift(savedTweet);
this.setState({tweetsList: newTweetsList});
})
.error(error => console.log(error));
}
There is a problem with delivering body of the tweet to database, cause after submitting there is NULL here.
Probably it means that body isn't send to DB ,but rest of parameters there are.
in /tweets there is an json API which looks like:
[{"id":17,"user_id":1,"body":null,"created_at":"2015-12-18T10:11:25.085Z","updated_at":"2015-12-18T10:11:25.085Z","name":"Marek Czyż"}]
When I create tweet manually form console everything works. so the problem must have been in previous piece of code.
Secondly after pressing SUBMIT tweet Ive recevied a warning that
Warning: Each child in an array or iterator should have a unique "key" prop. Check the render method of TweetList. See fb.me/react-warning-keys for more information.
although Ive got a key to every Tweet:
let tweets = this.props.tweets.map(tweet => );
Please, help me.
Assuming you're passing the right value as tweetToAdd, make sure you permit the body param in your controller. If it works in the console, it's not a validation problem, rather an unpermitted param.
As for the error you're seeing, you'll need to add a key prop to each rendered tweet. Something like:
render() {
let tweets = this.props.tweets;
return <ul>
{tweets.map(tweet => {
return <li key={tweet.id}>{tweet.body}</li>;
})}
</ul>;
}

Is there an easy way to make GORM errors restful api friendly

I'm working on a simple Restful API in GRAILS, I want users to be able to create an entry on one of my domain classes, so they can hit an entry point /rest/v1/create/event?params
In the receiving controller if the GORM entry fails, !event.save()
I have code like this:
def result = [
'status' : 'error',
'data' : event.errors.fieldErrors.toList()
]
render result as JSON
Is there a way to easily make event.errors.fieldErrors JSON friendly, something with just the field error and message, or will I have to write a parser method to handle this?
Ending up writing a short method to parse through and make friendly errors
If anyone finds this useful, here it is:
def gorm_errors(results) {
results = results.fieldErrors.toList()
def errors = []
for(error in results) {
errors.add([
'type' : 'invalid_entry',
'field' : error.field,
'rejected_value' : error.rejectedValue,
'message' : error.defaultMessage
])
}
return errors
}
Here is a more "groovy-er" version of the above example:
def gorm_errors(errors) {
errors.fieldErrors.toList().collect {error ->
[
'type': 'invalid_entry',
'field': error.field,
'rejected_value': error.rejectedValue,
'message': error.defaultMessage
]
}

Codeigniter CSRF response format

I am using a predefined response format for all my ajax calls.
If the request is success then the server will respond :
{"status":true,"data":{"name":"person","age":2}}
Please note data is not necessary.
and if the request failed then i will get
{"status":false,"reason":"You are not authorised."}
SO every response have a status field , if status is FALSE then there will be reason field.
The problem is that now i enables CSRF protection in Codeigniter and if the token expired/failed the system outputs
The action you have requested is not allowed.
this is HTML content.
Is it possible to extend the security class ,so that if the request is through Ajax then it will keep json_encoded format else use the html format.(i do not want to modify the core)
Thanks.
This error message is rendered from the CI_Exceptions::show_error method (located in system/core). You can extend this class by the usual way and override this method in order to catch this error and return whatever you want.
You can get rid of the call inside the CI_Security::csrf_show_error method by overriding it so it won't simply call
show_error('The action you have requested is not allowed.');
This is probably more robust.
Alternatively you can attack this inside CI_Exceptions class. Since this errors doesn't come with specific error code you will have to match for the message which could break between updates (currently hardcoded). The resulting class could look like this:
class MY_Exceptions extends CI_Exceptions {
public function show_error($heading, $message, $template = 'error_general', $status_code = 500) {
if ($message == 'The action you have requested is not allowed.') {
// handle this error your way
} else {
// send every other error to the original handler
parent::show_error($heading, $message, $template, $status_code);
}
}
}