Laravel 5.8 Search function in Restful API - php

I'm implementing an API for front end and mobile apps now i'm working on search function where a user may type column phone number or any data i should be able to provide the data they request in a JSON format
i really don't know how to query based on the data they input, so for i did this
My Controller,
public function searchMember(Request $request)
{
$data = $request->get('data');
$member_info = Member::where('phone_number', 'like', "%{$data}%")
->get();
return Response()->json([
'status' => 'success',
'data' => $member_info
], 200);
}
My Model,
class Member extends Model
{
protected $fillable = ['name','member_id','service_id','batch_id','phone_number','office_name','designation','email','image','remember_token'];
}
And my routes
Route::get('search?data=phone_number', 'MemberController#searchMember');
When I run the API resource its return 404 | not found.
I can not find the solution how to solve this.
In postman I run the API something like that:
http://localhost:8000/api/v1/search?data=0179826****

I know you solved your problem but just in case some one wants to know the answer. the correct way to pass data in url in rout is:
Route::get('search/{phone_number}', 'MemberController#searchMember');
and in your controller get it like:
public function searchMember(Request $request, $phone_number)
then your url would look like:
http://localhost:8000/api/v1/search/0179826****
other than that if you are going to send variable through request you don't need to clarify it in rout. so the route would be like:
Route::get('search', 'MemberController#searchMember');
the controller and the url would be as you posted.

Related

Laravel store() method from api controller not returning updated data

I'm having an issue where the store method in my UserCountries API controller is returning data that seems to be one step behind and I'm not sure why. My app has two models: Country and User, which have a many-to-many relationship with a pivot table. In my app a particular user should be able to 'like' and 'unlike' a country.
This mostly works as expected, however my issue is that the data returned on each request is one step behind - e.g., if I send a POST request to like a particular country, I get a 200 response but I am returned a UserCountriesResource which does not include that country that should have just been added. If I then immeditaely send a GET request, it returns a UserCountriesResource which does include that country. Can anyone help me figure out why?
Here are my routes:
Route::group(["prefix" => "me/countries"], function(){
Route::get("", [UserCountries::class, "index"]); // see all countries liked by user
Route::post("", [UserCountries::class, "store"]); // add or remove country from user
});
My index method in the UserCountries controller is below:
public function index()
{
return CountryResource::collection(auth()->user()->countries);
}
My store method in the UserCountries controller is below:
public function store(UserCountriesRequest $request)
{
$user = auth()->user();
$user->setCountries($request->get("countries"));
return new UserCountriesResource($user);
}
The store method calls the setCountries method in the User model:
public function setCountries(array $strings) : User
{
$countries = Country::fromStrings($strings);
$countries->map(function($country) use($countries){
if($this->countries->contains($country)){
Country::find($country->id)->users()->detach($this->id);
} else {
$this->countries()->syncWithoutDetaching($country->id);
}
});
return $this;
}
The setCountries method above in turn calls the fromStrings method in the Country model:
public static function fromStrings(array $strings) : Collection
{
return collect($strings)->map(fn($str) => trim($str))
->unique()
->map(fn($str) => Country::firstOrCreate(["NAME"=>$str]));
}
Do let me know if there's anything else I can add to make this more helpful!
You are loading the relationship before you are adding/removing any of the related records. That loaded relationship, Collection, won't include these changes. You will need to reload the relationship to get the new list of related records.
I don't know the rest of your code but you would add a call like this, if this was the case:
$user->load('countries');
This is loading the relationship (if it wasn't already loaded):
if($this->countries->contains($country))

Laravel 5 - API Resources with nested relations

First of all I've started to learn Laravel few weeks ago so sorry if I'm not using the right words while I'll explain my problem.
I'm trying to write some API to retrieve all posts in my DB and inside post's info I'd like to retrieve user's info related to every post (like username, id etc.)
User Model:
public function post()
{ return $this->hasMany(Post::class); }
Post Model:
public function user()
{ return $this->belongsTo(User::class); }
then in my PostResource I try to return the post's data from DB
Post Resource:
public function toArray($request)
{
return [
'id' => $this->id,
'user_id' => $this->user_id,
'user_info' => HERE_I_WANT_USER[USERNAME,ID ETC.]
'body' => $this->name
];
}
and in my PostController I've this function that return my collection:
public function show() {
return PostResource::collection ( Post::get() );
}
So every post is linked to every author thanks to "user_id" value.
Here is my question: What are the steps to achieve this?
I've already red Laravel Doc "https://laravel.com/docs/5.5/eloquent-resources#conditional-relationships" making and UserResource and doing the same steps that I did before, but I'm not able to retrieve any data because my user's info return empty.
I'd like to understand better what are the steps.
You would just call it like it is part of the Post model. Something similar to this:
return [
'id' => $this->id,
'user_id' => $this->user_id,
'user_info' => $this->user
'body' => $this->name
];
I'm assuming that $this is a Post Model. If its not, then you'll want to find it and use it instead like $post->user. Additionally, the name of the method will be whatever your relationship function is called (with out the parenthesis), so if that ever changes, you'll have to update this. Finally, this will return a User Model, so you can interact with it like a normal model ($post->user->username or whatever).
Here is the Laravel Relationship documentaion for further reference.

How to query db by uri id in laravel through user auth?

I'm just finished the intermediate laravel tutorial here: https://laravel.com/docs/5.2/quickstart-intermediate and am trying to push on a bit.
While I can fetch all the tasks via auth'd user id with:
public function index(Request $request)
{
$tasks = $request->user()->tasks()->get();
return view('tasks', [
'tasks' => $tasks,
]);
}
I want to create a view function... how, if I create a link to /task/7 to I query the info about the task with id 7 (for example) & send it to the view?
Define a route to match that /task/7 URL like so:
Route::get("/task/{taskId}", "TaskController#getView");
Then, in your TaskController, define getView function as:
public function getView($taskId){
$task = \App\Task::where("id", "=", $taskId)->first();
return view("tasks.view")->with(["task" => $task]);
}
This is the simplest way to pass a taskId to via a URL parameter, query your DB for the matching record and return a view to display information about it.
There's more involved, like validating the record exists for example, but this should get you on your way.

Laravel hasMany relationship returning huge amounts of data which is not a collection?

I am working on a very simple API using laravel. Users have many tasks, and a task belongs to a user. My routes file is as follows :
<?php
Route::resource('users', 'UsersController');
Route::get('users/{user_id}/tasks', 'UsersController#show_tasks');
Route::resource('tasks', 'TasksController');
I want that the second route gets all the tasks related to that particular user. It is simple. I just added a relationship in my User model as follows :
public function tasks(){
return $this->hasMany('Task');
}
And the show_tasks method in my UsersController is as follows :
public function show_tasks($id){
if(!$user = $this->user->find($id)){
return Acme::response('error', 'Resource not found.', [], 404);
}
$tasks = $user->tasks();
dd($tasks);
return Acme::response('success', [], $tasks, 200);
}
I have placed the dd method because the response was returning an empty array and I wanted to see what is in the $tasks variable first hand. I thought it must be a collection object but when I ran this in my Postman REST client, it hanged due to the large data overflow I am assuming, screenshot below :
If anyone is curious about the Acme::response method, I am also including that code :
public static function response($status = [], $messages = [], $data = [], $httpStatusCode){
return Response::json([
'status' => $status,
'messages' => $messages,
'data' => $data,
], $httpStatusCode);
}
Why is the relationship not working? I have been this for hours and still can't figure out why! I am guessing I might be doing a very silly mistake somewhere but can't get to it anyway!
You shouldn't use () here. Instead of:
$tasks = $user->tasks();
you will get your tasks using:
$tasks = $user->tasks;
EDIT
When you have relation and you use $user->tasks it works as you would use $user->tasks()->get() so we can say it's a shortcut.
You could use parantheses you get relation you can add more conditions, for example you could do something like that:
$tasks = $user->tasks()->active()->get();
and define scope in your Task model:
function activeScope($q) {
return $q->where('status',1);
}
And now you can get only active tasks for user.

Laravel 4 Users editing others information

I am having issues with Laravel 4. When a user logs in, they are able to create or edit a saved form called a "Project". I need to be able to make it where a user can only edit the forms "projects" that they created. Currently, anyone can edit anyone elses project by changing the project id in the url.
Example: projects/3/edit edits the project with an id of 3
I tried using the following code but it returns an error "Trying to get property of non-object" but project is an object. Any advice is much appreciated.
filter.php
Route::filter('auth', function()
{
if (Auth::guest()) return Redirect::guest('login');
});
Route::filter('auth.project', function($route, $request)
{
if($route->parameter('project')->user_id !== Auth::user()->id)
{
return Redirect::route('/')->with('error','sorry, you can only access projects that you created');
}
return Redirect::route('/');
});
Route::filter('auth.basic', function()
{
return Auth::basic();
});
routes.php
Route::get('/projects/{projects}/edit','ProjectsController#edit', ['before' => 'auth.project']);
You have this filter:
Route::filter('auth.project', function($route, $request)
{
if($route->parameter('project')->user_id !== Auth::user()->id)
{
return Redirect::route('/')->with('error','sorry, you can only access projects that you created');
}
return Redirect::route('/');
});
Here if($route->parameter('project')->user_id !== Auth::user()->id) is not right because the first thing is that, your route is declared as given below:
// This is not right
Route::get('/projects/{projects}/edit','ProjectsController#edit', ['before' => 'auth.project']);
Try this:
Route::get('/projects/{projects}/edit', ['before' => 'auth.project', 'uses' => 'AuthorsController#edit']);
Also, the parameter is projects not project but you are using project in your filter and then, the second problem is that, you are trying to get property of non-object because $route->parameter('project') returns null and even if you use projects then it may return the 3 but still that will throw an error because 3 is not an object. You need to grab that Project whose id is 3 or you may use a route model binding. So, if you use something like this:
$project = Project::find($route->parameter('projects')); // Assumed that 3 is id
if($project->user_id !== Auth::user()->id) {
//...
}
Also you may use a route model binding like this:
Route::model('projects', 'Project'); // Project Model must be existed
Route::get('/projects/{projects}/edit', ['before' => 'auth.project', 'uses' => 'AuthorsController#edit']);
Then in your edit method:
public function edit(Project $project)
{
// $project is an Eloquent Object, will be injected automatically...
});
Well, just looking at what you've posted here, I see a couple issues.
First, you named your parameter projects in your route and try to access project in your filter, which is non-existent.
Second, $route is of type Illuminate\Routing\Route which has a method called getParameter, not parameter. More can be found in the documentation linked here.
Hope this helps.

Categories