I am returning an API response inside a Categories controller in Laravel 5.5 like this...
public function get(Request $request) {
$categories = Category::all();
return Response::json(array(
'error' => false,
'categories_data' => $categories,
));
}
Now I am trying to also have the option to return a specific category, how can I do this as I am already using the get request in this controller?
Do I need to create a new route or can I modify this one to return a specific category only if an ID is supplied, if not then it returns all?
Better case is to create a new route, but you can also change the current one to retrieve all models if the parameter is not supplied. You first gotta choose which approach you will be using. For splitting it into multiple calls you can see Resource controllers and for using one method you can follow Optional Route Parameters
It will be much cleaner if you will create another route. For example
/categories --> That you have
/categories/{id} -> this you need to create
And then add method at same controller
public function show($id) {
$categories = Category::find($id);
return Response::json(array(
'error' => false,
'categories_data' => $categories,
));
}
But if you still want to do it at one route you can try something like this:
/categories -> will list all categories
/categories?id=2 -> will give you category of ID 2
Try this:
public function get(Request $request) {
$id = $request->get('id');
$categories = $id ? Category::find($id) : Category::all();
return Response::json(array(
'error' => false,
'categories_data' => $categories,
));
}
Related
I am sending a update request like:
Route::put('user/{user}/edit-user-education', 'UpdateUserEducationController#editUserEducation');
My controller is :
class UpdateUserEducationController extends Controller
{
public function editUserEducation(UserEducation $education, User $user, EditUserEducationRequest $request)
{
$education->school = $request->school;
$education->degree = $request->degree;
$education->user_id = $user->id; // here to validate
$education->save();
return response()->json([
'message' => 'Education Updated'
]);
}
}
Now how I can validate the request user_id with the user_id already in inserted in DB ? I want to ensure that the only user can update the record who created that one.
How to do so ? Thanks in advance
Check out the docs on validation here:
https://laravel.com/docs/8.x/validation
Specifically, I think you want the exists rule:
https://laravel.com/docs/8.x/validation#rule-exists
The quick and dirty way is to add your validation in the controller but there are some better methods as explained in the docs. I usually opt for Form Requests, which it looks like you've already done as your request is an instance of EditUserEducationRequest.
In the controller you can add:
$validated = $EditUserEducationRequest->validate([
'user_id' => 'required|exists:users',
]);
I assume your user table is called users.
You could alternatively state the exists validation rule for user_id in the rules array of your Form Request as per the docs.
EDIT:
I actually missed a requirement in your original post that is that the user sending the request must be the same user as the one being updated.
That can be handled in the the authorize method of your form request with something like:
public function authorize()
{
return $this->user()->id == $this->user_id;
}
Simply make a check that current user is the same user who is trying to update record.
class UpdateUserEducationController extends Controller
{
public function editUserEducation(UserEducation $education, User $user, EditUserEducationRequest $request)
{
if($user->id==Auth::user()->id){
$education->school = $request->school;
$education->degree = $request->degree;
$education->user_id = $user->id; // here to validate
$education->save();
return response()->json([
'message' => 'Education Updated'
]);
}
else{
return response()->json([
'error' => 'Invalid User'
]);
}
}
}
I'm using composer require gloudemans/shoppingcart I am not sure how to maintain amount.
When i'm using one route that says add item when i'm using this route adding multiple item
How can i conditionally setup to add item in cart if this is unique
public function bookItem($id) {
$item = Item::where([
'status' => '1',
'id' => $id
])->first();
$product = Cart::add($item->id, $item->name, 1, $item->price); // This should not call always if it has not generated a row id then it should call
Cart::update($product->rowId, ['price' => 200]); // Will update the price if it is differ
return redirect()->route('book.item', ['id' => $item->id]);
}
I am not sure how to manage it. please guide
Looks like the package has a getContents() function that gathers all items into a collection. It also has a search(Closure) function that calls getContents() and then uses Laravel's filter function on the collection and returns the result.
$search = Cart::search(function($key,$value) use ($item) {
return $value === $item->id;
})->first();
if(!empty($search)){
Cart::update($search->rowId, ['price' => 200]);
}
else {
$product = Cart::add($item->id, $item->name, 1, $item->price);
}
Definitely check out the Laravel collection docs if you aren't familiar. This is the entey on filters:
https://laravel.com/docs/5.8/collections#method-filter
I'm creating url friendly in my app, but it's not working, the app is giving me some issues related with "-".
It's giving me an error of:
ErrorException in PostController.php line 60:
Trying to get property of non-object
My ideal URL is:
http://domain.com/CATEGORY-title-of-post-ID
My route is:
Route::get('{category}-{title}-{id}', 'PostController#show');
PostController show function:
public function show($category,$title,$id)
{
$post = Post::find($id);
$user = Auth::user();
$comments = Comment::where('post_id',$id)
->where('approved',1)
->get();
return view('posts.show',compact('post','comments','user'));
}
Blade View:
<?php
$title_seo = str_slug($feature->title, '-');
?>
<a href="{{url($feature->categories[0]->internal_name."-".$title_seo."-".$feature->id)}}" rel="bookmark">
...</a>
There's a library called Eloquent-Sluggable that will create a unique slug for each post and correctly URL encode it.
To install (taken from the docs):
composer require cviebrock/eloquent-sluggable:^4.1
Then, update config/app.php by adding an entry for the service provider.
'providers' => [
// ...
Cviebrock\EloquentSluggable\ServiceProvider::class,
];
Finally, from the command line again, publish the default configuration file:
php artisan vendor:publish --provider="Cviebrock\EloquentSluggable\ServiceProvider"
To use, add the Sluggable trait to your model:
use Cviebrock\EloquentSluggable\Sluggable;
class Post extends Model
{
use Sluggable;
/**
* Return the sluggable configuration array for this model.
*
* #return array
*/
public function sluggable()
{
return [
'slug' => [
'source' => 'title'
]
];
}
}
When you save an instance of your model, the library will automatically create a slug and save it to the newly created slug column of your model's table. So to access the slug you'd use $model->slug
To achieve your desired slug, rather than create it from title set by default. You can pass the source attribute of the sluggable method an array of field names, using a dot notation to access the attributes of a related model, like so:
public function sluggable()
{
return [
'slug' => [
'source' => ['category.name','title','id']
]
];
}
}
Why are you genering your "friendly URL" manually?
You have route helper function that builds for you a URL based on the given parameters.
Route::get('{category}-{title}-{id}', [
'as => 'post.show',
'uses' => 'PostController#show'
]);
echo route('post.show', ['testing', 'title', 'id']); // http://domain.dev/testing-title-id
This is not the best approach to implement SEO friendly URLs, anyway.
In your controller you ALWAYS use your ID to find a post, that means that category and title are completely useless to determine which resource needs to be served to the user.
You can make your life easier by doing something like:
Route::get('{id}-{slug}', [
'as => 'post.show',
'uses' => 'PostController#show'
]);
echo route('post.show', ['id', 'slug']); // http://domain.dev/id-slug
In your model you create an helper function that generates the slug for your post:
class Post
{
[...]
public function slug()
{
return str_slug("{$this->category}-{$this->title}");
}
}
Then, in your controller you need to check that the slug used to access the article is correct or not, since you don't want Google to index post with wrong slugs. You essentially force a URL to be in a certain way, and you don't lose index points.
class PostController
{
[...]
public function show($id, $slug)
{
$post = Post::findOrFail($id);
$user = Auth::user();
if ($post->slug() !== $slug) {
return redirect()->route('posts.show', ['id' => 1, 'slug' => $post->slug()]);
}
$comments = Comment::where('post_id', $id)->where('approved', 1)->get();
return view('posts.show', compact('post', 'comments', 'user'));
}
}
I have RESTful API built on Laravel.
Now I'm passing parameter like
http://www.compute.com/api/GetAPI/1/1
but I want to pass parameter like
http://www.compute.com/api/GetAPI?id=1&page_no=1
Is there a way to change Laravel routes/functions to support this?
you can use link_to_route() and link_to_action() methods too.
(source)
link_to_route take three parameters (name, title and parameters). you can use it like following:
link_to_route('api.GetAPI', 'get api', [
'page_no' => $page_no,
'id' => $id
]);
If you want to use an action, link_to_action() is very similar but it uses action name instead of route.
link_to_action('ApiController#getApi', 'get api', [
'page_no' => $page_no,
'id' => $id
]);
href text
with these methods anything after the expected number of parameters is exceeded, the remaining arguments will be added as a query string.
Or you can use traditional concatination like following:
create a route in routes.php
Route::get('api/GetAPI', [
'as' => 'get_api', 'uses' => 'ApiController#getApi'
]);
while using it append query string like this. you can use route method to get url for required method in controller. I prefer action method.
$url = action('ApiController#getApi'). '?id=1&page_no=1';
and in your controller access these variables by following methods.
public function getApi(Request $request) {
if($request->has('page_no')){
$page = $request->input('page_no');
}
// ...your stuff
}
Or by Input Class
public function getApi() {
if(Input::get('page_no')){
$page = Input::get('page_no');
}
// ...your stuff
}
Yes you can use those parameters, then in your controllers you can get their values using the Request object.
public function index(Request $request) {
if($request->has('page_no')){
$page = $request->input('page_no');
}
// ...
}
Im a big 'ol newbie at Laravel, and im trying to do a query scope but it doesnt seem to be working, i keep getting this error
Argument 1 passed to Letters::scopeForUser() must be an instance of User
My user IS logged in, but it still doesnt seem to be working.
This is my Letters model
<?php
class Letters extends Eloquent {
protected $table = 'letters';
public function scopeForUser(User $u)
{
return $query->where('userid', '=', $u->id);
}
}
and in my controller i have the following
Route::get('myletters', array(
'before' => 'auth|userdetail',
function()
{
// Grab the letters, if any, for this user
$letters = Letters::forUser(Auth::user())->get();
$data = [
'letters' => $letters
];
return View::make('myletters', $data);
}
));
Any help would be greatly appreciated.
Cheers
You should pass a variable $query as the first argument to your method in the Model. For example:
public function scopeForUser($query, User $u)
{
return $query->where('userid', '=', $u->id);
}
The first argument doesn't necessarily need to be $query, but it should be the same variable that you are using inside the scope method ($query in this case).