Custom filters - how do I make them fail? - laravel

I'm creating a package that allows users to use a custom filter.
So far I have a method called:
public function testFilter(){
return false;
}
In my filters file, in my main app I have I have:
Route::filter('test.test', MyPackage::testFilter());
And in my routes, in my main app I have:
'before'=>'test.test'
My question is, how do I do the filtering, I've done a return false to try and make the filter fail, do I need something else, like app abort?

According to Laravel filters documentation
If the filter returns a response, that response is considered the response to the request and the route will not execute. Any after filters on the route are also cancelled.
That means you do have to return a Response to cancel your route from proceeding.
It'll probably more logical for you have another view to be displayed to your visitor when the filter fails, and this is what Laravel is trying to do.
You can use App::abort() for that or App::abort(404) (with error codes) to show error page.

Related

how to implement Single Responsibility in laravel

I am so confused about how to implement and how to follow SRP (single responsibility principle ) in a Laravel controller.
Suppose we have a controller which we have to do these things:
e.g
public function StorePost() {
// check user login()
//check number of current user Post count =>which must be less than 10
//store post
//send an email to user which your post has saved
//return =>api:json /web : redirect
}
I know that I can implement some DB queries in the repository but I don't know how to implement others of my logic code to achieve SRP
Also, I know there is a Heyman package to achieve these but I want to implement it by myself.
SRP in this context basically means each class and method should only be responsible for a single behaviour/feature. A rule of thumb is a class or method should change for one reason only, if it changes for multiple reasons, it needs to be broken down into smaller parts.
Your storePost method should not bother with checking the user login, that should be handled elsewhere before invoking storePost. storePost shouldnt change if the auth mechanism changes like switching from api token to json web token or something else. Laravel does this in the middleware level with the auth middleware.
Checking the users post count, this can be checked in the validation stage. storePost shouldn't change if we add more validation logic. In Laravel you can use FormValidation for this
For storing the post, the controller doesn't need to know how to call the DB, you can use the active record style using the model class or maybe create a service or repository class if your use case requires that. storePost shouldn't change if we decide to change DB vendor like going NoSQL.
For sending email, again the controller doesnt need to know how to send the email like what the subject/body recipients are. storePost shouldnt change if we need to change the email layout. Laravel has Notification for that
For serialising the response to json, the controller doesnt need to know how to format the response. if we decide to update how our json looks, storePost shouldnt change. Laravel has API Resources for that
So, ultimately in this example, the responsibility of the controller method is basically to glue all these together. It basically does what you wrote down, it only responsible for maintaining the step by step behavior, everything else is delegated to someone else. if the behavior change, like adding new behavior e.g notify all follower, storePost will change.

laravel request return message keys translations

I have a Laravel Application and another APP making calls via API to Laravel. These 2 projects are separated.
Laravel and App have their own multilanguage system. They work independently but uses the same key translations.
So my idea was that all Laravel responses must be translations key, like: 'messages.success'.
With this response, the App can translate it.
All of these are working fine.
The problem appeared when I started working with Laravel Requests for validating forms.
In this case, the validation errors are automatically translated so the App receives the response translated with the default language of the Laravel application.
So what can I do?
I thought with 2 ideas but I don't know if they can work.
1: Passing the language into params. Don't know if it can work, how can I set the language before Laravel validates the Request?
2: Override the functionality of Requests to return messages without translate, so instead of "Felicidades" return "messages.success". I really like this approach. But how can I do it for all the rules? Overriding the messages function like this:
public function messages()
{
return [
'unique' => 'validation.unique'
];
}
For every rule works... but I feel bad.
Another approaches?
What is the best way to fix this problem?
I would suggest that you use this hacky solution in 2 lines of code. Go to /resources/lang/{code}/validation.php. You can see that it returns an array of messages by default. Modify it like so:
// Replace return in the first line
$ret = [
/* all the translations go here as normal */
];
// Add this as the last line. This will replace all values with their keys.
return array_combine(array_keys($ret), array_keys($ret));
After that you can use validation as per usual and you'll get validation message keys instead of messages. Cheers and hope this helps.

How to get the result of a asynchronous action in NGXS?

I want to perform an action based to the result of an asynchronous NGXS action.
In a Angular frontend app I'm using NGXS for state management. Some of the actions involve talking to a backend via REST calls. Those actions are implemented as asynchronous actions, with the reducer functions in my state classes returning an Observable.
What I'm looking for is a way to get hands on the result of the backend call, to be able to perform some action.
One use case I'm trying to implement is navigation to just created objects: Business objects are created in the frontend (Angular) app with a couple of domain properties. They get persisted in the backend, and as a result an ID for this object is created and returned to the frontend, and incorporated into the NGXS store. As a direct response to this, I'd like to navigate to a detail view for the new object. To do so, I need
(a) the information that the call has been returned successful, and
(b) the answer from the backend (the ID in this case).
Another slightly more complicated use case is the assignment of a number of tags to an business object. The tags are entities by themselfes, and have an ID each. In the UI, the user can either pick existing or add new tags. Either way, multiple tags can be added in a single step in the UI, which means I have to
call the backend for each new tag to create the ID
after all missing tags are created, update the business object with the list of tag IDs
In general, there are use cases in the frontend that depend on the result of a backend call, and there is no clean way to find this result in the store (although it's in there)
I know I can subscribe to the Observable returned from the store's dispatch method (as shown in asynchronous actions).
I also know about action handlers. In both cases I can attach code to the event of an action finished, but neither option enables me to get the result of the backend call. In the fist case, the Observable carries the whole store, while in the latter case I get the original Action, which is unfortunately missing the essential information (the ID).
The part you're missing here are selectors. Dispatching actions is not supposed to give you back a result. The only purpose of the Observable returned by store.dispatch() is to tell you when the action's handlers are done.
To get to the data returned by your calls to the backend, you have to patch the state inside your action handler. And then, outside of your state, you can access the data using store.select() or store.selectSnapshot() depending on what you need. Your state class should look somewhat like this (untested):
#State()
export class SampleState {
#Selector(SampleState)
sampleSelector(state) {
return state.sampleObject;
}
#Action(SampleAction)
sampleAction(ctx: StateContext<any>, action: sampleAction) {
return sampleBackendCall(/* ... */).pipe(
tap((result) => {
ctx.patchState({ sampleObject: result });
})
);
}
}
Now you can access this result where ever you need using the Store. For the use case of navigating to an element after its creation, you can combine a subscription to store.dispatch() with a store.selectSnapshot() like this:
store.dispatch(new SampleAction()).subscribe(() => {
navigateTo(store.selectSnapshot(SampleState.sampleSelector));
});
Note that in this easy case a selectSnapshot is perfectly fine, as we only want to get the value we just finished writing into the state. In most cases though, you will want to use store.select() or the #Select() decorator because they return Observables which enable you to also correctly display changes in your state.
That said, I'd like to add that if saving data inside the state is not necessary for you at all, then probably NGXS is the wrong library for you in the first place and you could as well just use an ordinary angular service directly returning the result of the backend call, like suggested in the comments.

angular 2 route to 404 page when route param is invalid

Say I have an route with a param like this (in Angular 2): /user1/products/:id, which could have child routes like /user1/products/3/reviews.
When I navigate to /user1/products/-1, I check with my server and if the product doesn't exist, I want to render a 404 page without affecting the browser history.
Using router.navigate(['/404']) or router.navigateByUrl('/404') doesn't seem to work because it adds both /user1/products/-1 and/404 to the browser history.
Meaning when I press the Back button in the browser, I go back to /user1/products/-1 which is immediately redirected to /404 and I'm essentially stuck at /404.
In ExpressJS, we would do something like next() to pass the request to our 404 handler. Is there a client-side equivalent in Angular 2?
Update
In the new Router V3 you can use guards as explained in https://angular.io/guide/router#canactivate-requiring-authentication
Original
I think you should use #CanActivate() to do the check. If you forward in #CanActivate() the invalid URL shouldn't be added to the history (not tried)
See also https://github.com/angular/angular/issues/4112 for how to use DI in #CanActivate()
Ok, this is already implemented, just not well-documented.
According to the docs:
router.navigateByUrl(url: string, _skipLocationChange?: boolean) : Promise<any>
Has a parameter _skipLocationChange that will not modify the history.
These will do the trick:
router.navigateByUrl('/404', true);
router.navigateByInstruction(router.generate(['/404']), true);
As of Angular 2 final this is the solution:
this._router.navigateByUrl('/404', { skipLocationChange: true })
Its really interesting question, perhaps you should report it as feature request. I would be nice to have access to router instruction inside loader callback of RouteDefinition.
You could try to emulate validation adding default route /** and using regex parameter of RouteDefinition to match only positive numbers.

Hiding Query String Parameters

I have a GET action for creating records. Because the page is somewhat dynamic, I don't use a model to hold the data. I go off to do some OAuth, only to return to the create screen later on. In order to pass the data back, I am redirecting with a query string. I parse the query string in the GET action, and then show the view. The thing is, the query string is showing up in the browser. This displays pseudo-sensitive data.
Since I am only using the query string for transferring data, I am wondering if I can throw the query string away to prevent it from showing up on the browser.
Otherwise, is there a way to go to another action without redirecting? I've found, if I call the "other" action method directly, it tries to find the view of the original action. I can explicitly change the return View(viewModel) line to return View("create", viewModel) but that seems really dirty.
You should consider changing the action to accept POST requests. At least this will prevent the sensitive information from appearing in the browser. For extra security, your site should be served via SSL.
The other thing you can try is encrypting the sensitive values or the entire query string. The only problem is that this, too, will be preserved in the browser's history unless you require users to log in.
It looks like your action method is trying to do too much. Authentication/authorization is a separate concern which should not be part of the action method. It is better to move the authentication work in to an action filter.
Create an class that extends authorization attribute and override its OnAuthorization method to do your authorization work.
This frees your controller action method to accept POST requests.

Resources