Associate relationship afterwards - laravel

Version used: Laravel 5.4
We have a post and that post can have several pictures associated with it. We use a controller to store the post and an other one to store the pictures.
We set the relationship in the models like so:
class Post extends Model
{
public function pictures()
{
return $this->hasMany(Picture::class);
}
}
class Picture extends Model
{
public function post()
{
return $this->belongsTo(Post::class);
}
}
When I go to the form to create a new post, I can add pictures to that post before I actually store the post. Which means that when I store a picture I still don't have a post id to associated it to.
My questions is:
Using only php, is there a clean way to associate the pictures to the post before or afterwards ?
The solution I am currently using is that when I go to the form to create a new post, a blank new post is created before hand and I pass the id on the url. It has to be a better way to do it.

You can try this
First create the form when user access the create post page (as you are already doing).
Suppose this is your function which is showing the create post view
public function showCreatePost()
{
$post = Post::create(['field_name' => '', // put your attributes]);
// pass other data as well if you want.
return view('your_create_view',compact('postId',$postId));
}
change your route of imageupload which will have postid . for example
Route::post('post/image/{postId}','SomeController#somefunction');
create one route for editing the post and use it for editing the post which will have post id.
Route::post('post/edit/{postId}','SomeController#someOtherfunction');
Now use these two routes as form action and you can edit the post and upload the image. route example below
Showing the id in url is not a good idea. so by this way you can try and let me know if you face any problem.

Related

How do I pass a value in my Route to the Controller to be used in the View in Laravel?

I have 2 entities called Match and Roster.
My Match routes are like this
http://localhost:8888/app/public/matches (index)
http://localhost:8888/app/public/matches/14 (show)
In order to view/create the teams for each specific match I added the routes for the match roster like this:
Route::get('/matches/'.'{id}'.'/roster/', [App\Http\Controllers\RosterController::class, 'index']);
Now I need that {id} i have in my URL to pass it to the Controller here:
public function index()
{
return view('roster.index');
}
I need that for a couple of things. First I need to do a search on the Roster table filtering by a column with that value, so I can display only the players that belong to that match.
Second, I need to pass it on to the view so I can use it on my store and update forms. I want to add or remove players from the roster from that same index view.
How can I do that?
#1 You can get the route parameter defined on ur routes via request()->route('parameter_name').
public function index()
{
// get {id} from the route (/matches/{id}/roster)
$id = request()->route('id');
}
#2 You can pass the data object via using return view(file_name, object)
public function index()
{
// get {id} from the route (/matches/{id}/roster)
$id = request()->route('id');
// query what u want to show
// dunno ur models specific things, so just simple example.
$rosters = Roster::where('match_id', '=', $id);
// return view & data
return view('roster.index', $rosters);
}
#3 It can be done not only index but also others (create, store, edit, update)
In addition, STRONGLY RECOMMEND learn Official Tutorial with simple example first.
Like a Blog, Board, etc..
You need to know essentials to build Laravel App.
Most of the time, I prefer named routes.
Route::get('{bundle}/edit', [BundleController::class, 'edit'])->name('bundle.edit');
In controller
public function edit(Bundle $bundle): Response
{
// do your magic here
}
You can call the route by,
route('bundle.edit', $bundle);

Can a Laravel POST route return a view instead of redirecting to another route?

I have seen/worked on lot of projects where a Laravel POST route looking like this:
Route::post('/some-url', [SomeController::class, 'someMethod']);
And the controller with its method which takes care of the route looking like this:
class SomeController extends Controller
{
public function someMethod(Request $request) {
// My Logic to do something with the post data - $request
return redirect("/some-other-url");
}
}
have always redirected to a specific URL after doing something with the POST data, by convention.
I would like to know, if after processing a POST request, if it's okay to just return a view like what we do with GET requests? I know it works, but is it just convention or are there any issues in doing so?
Eg:
class SomeController extends Controller
{
public function someMethod(Request $request) {
// My Logic to do something with the post data - $request
return view("somebladeview")->with(["result" => $result ]);
}
}
The pattern is called post-redirect-get, or PRG. It is convention because POST should be used for requests that change data, whereas GET should be used to simply display data.
If you return a view after a POST, the user can hit reload, and (probably unintentionally) change data again, eg buy something a second time. By using PRG, the user hitting reload simply reloads the last GET, which just re-displays something.
NOTE: There is some advice in the comments on your question to ignore this convention. I think that is unwise and dangerous, these conventions exist for good reasons.

How can I get data from multiple controllers into a Laravel Blade view?

I'm new with Laravel (and programming) and I'm a bit confused.
Using the Eloquent ORM I store in the database a list of pets and their info in a pets table with a Pet model and a Pet controller.
I also have a users table with User model.
Then I have an owner_pet table that contains foreing keys to user_id and pet_id, with an OwnerPet model and controller.
I have a view called 'pets' and I want there to be a form and a list of the user pets, only accesible by authenticated users.
I have this route:
Route::get('/pets', [App\Http\Controllers\HomeController::class, 'index'])->name('pets');
There, using the auth middleware it checks the user is logged in and returns the view 'pets', that contains a form to add pets.
public function __construct()
{
$this->middleware('auth');
}
public function index()
{
return view('pets');
}
This works fine.
Then I have a pet controller with an add pet function, I use it with a form in the 'pets' view that calls this route:
Route::post('/add', 'PetController#addPet')->name('add');
When the pet is added I return the 'pets' view with a success message.
return view('pets')->with('success', $success);
This works fine.
Then I have a ownerPets index function where I get all the info I need and store it as $pets and call the 'list' view:
public function index()
{
$ownerPets = OwnerPet::leftjoin('pets', 'pets.id', '=', 'owner_pets.pet_id')
->where('user_id', Auth::user()->id)->paginate(20);
return view('list')->with('pets', $pets);
}
I call the function with this route:
Route::get('/list', 'OwnerPetController#index')->name('list');
This works fine, I can see the list of the user's pets.
But I need to have everything in the same view, and I can only call a single function from the route.
Do I need to make another controller and call all the functions from there and then send all the data to the view? I was told calling a controller from another controller was a bad practice, but I can't think of another way to do this.
Can I maybe make a view that contains the other 2 views? But I don't know how would I get the functions to pass the data to them.
Please I need some advice. Thanks.
This mean that you want a page which have add form at the right side and list of pet with owner information at the left (for example).
so, you just
This Route::get('/list', 'OwnerPetController#index')->name('list'); will return list pet and add from for the same page.
Create another route like Route::post('/add', 'PetController#addPet')->name('add'); (in the same controller or other controller, it up to you) for adding pet.
after you fill up the form and click submit, addPet function must return view('pets');
Hope martch your question.
Thanks

Laravel Pagination on POST request

Im using Laravel v7 and i have a question about pagination.
So far im using 2 routes, 1rst to return a view with all rows from database, and 2nd receives an input and returns that view with the rows filtered by that input value.
But im using pagination, and on the 2nd route, when i try to go to 2nd page it gives me an error:
Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException
The GET method is not supported for this route. Supported methods: POST.
I've tried to change my form method to GET but i need that the token doesn't appear on the page URL and beside that, when i go to 2nd page, it returns all the rows again.
Thats my code so far:
Routes:
Route::get('concessions', 'ConcessionController#index')->name('concessions.index');
Route::post('concessions/search', 'ConcessionController#search')->name('concessions.search');
Controller
class ConcessionController extends Controller
{
public function index()
{
$concessions = DB::table('concessions')->paginate(12);
return view('admin.concessions.index', compact('concessions'));
}
public function search(Request $request)
{
$name = $request->name;
$concessions = Concession::where('name', 'like', '%' . $name . '%')->paginate(12);
return view('admin.concessions.index', compact('concessions', 'name'));
}
}
Any way to do that?
Laravel pagination only works with get parameters.
You should use GET method for your search page. POST requests aren't meant for the purpose of displaying data. Why? There are many reasons, but to be short I will give you three examples :
1. When you access the first page, you get the data by GET request,
not POST request. So if you want to use POST request, you
need to access the page as POST request by sending data with
POST method.
2. With GET parameters, let's say you are on 5th page - you can
copy the link and paste it to friend and he will be able to view
the same content as you. With POST this is impossible.
3. You can not use back button with POST requests, if you manage to
get pagination to work.
POST requests are useful when you need to submit data to the server, in order to create new record, for example.
So I suggest you to change your route type to GET.
From my perspective, if you change your route code similar to below code, it will work properly with both methods of GET and POST.
Route::any('concessions/search', 'ConcessionController#search')->name('concessions.search');

Laravel route difference between {id} vs {tag}

I am new in Laravel pardon me if question is silly. I have seen a doc where they used
For get request
Route::get("tags/{id}","TagsController#show");
For put request
Route::put("tags/{tag}","TagsController#update");
What is the difference and benefit between this ? I understood 1st one, confusion on put route.
There’s no real difference as it’s just a parameter name, but you’d need some way to differential parameters if you had more than one in a route, i.e. a nested resource controller:
Route::get('articles/{article}/comments/{comment}', 'ArticleCommentController#show');
Obviously you couldn’t use just {id} for both the article and comment parameters. For this reason, it’s best to use the “slug” version of a model for a parameter name, even if there’s just one in your route:
Route::get('articles/{article}', 'ArticleController#show');
You can also use route model binding. If you add a type-hint to your controller action for the parameter name, Laravel will attempt to look up an instance of the given class with the primary key in the URL.
Given the route in the second code example, if you had a controller that looked like this…
class ArticleController extends Controller
{
public function show(Article $article)
{
//
}
}
…and you requested /articles/123, then Laravel would attempt to look for an Article instance with the primary key of 123.
Route model binding is great as it removes a lot of find / findOrFail method calls in your controller. In most instances, you can reduce your controller actions to be one-liners:
class ArticleController extends Controller
{
public function show(Article $article)
{
return view('article.show', compact('article'));
}
}
Generally there's no practical difference unless you define a custom binding for a route parameter. Typically these bindings are defined in RouteServiceProvider as shown in the example in the docs
public function boot()
{
parent::boot();
Route::model('tag', App\Tag::class);
}
When you bind tag this way then your controller action can use the variable via model resultion:
public function update(Tag $tag) {
// $tag is resolved based on the identifier passed in the url
}
Usually models are automatically bound so doing it manually doesn't really need to be done however you can customise resolution logic if you do it manually
Normal way
Route::get("tags/{id}","TagsController#show");
function($id)
{
$tag = Tag::find($id);
dd($tag); // tag
}
With route model bindings
Route::put("tags/{tag}","TagsController#update");
function(Tag $tag) // Tag model binding
{
dd($tag); // tags
}
ref link https://laravel.com/docs/5.8/routing#implicit-binding
It's just a convention. You can call it all you want. Usually, and {id} refers to the id in your table. A tag, or similarly, a slug, is a string value. A tag could be 'entertainment' for video categories, while 'my-trip-to-spain' is a slug for the description of a video.
You have to chose the words what you are comfortable with. The value will be used to find in your database what record is needed to show the correct request in the view. Likewise you can use video/view/{id}/{slug} or any combination thereof.
Just make sure your URLs don't get too long. Because search engines won't show your website nicely in search results if you do. Find the balance between the unambiguous (for your database) and logic (for your visitors).
Check this out: Route model bindings
Use id, Laravel will get the id from route, and it will be the tag's id, it is integer.
function show($id) {
$tag = Tag::find($id);
}
Use tag, Laravel automatically resolves Eloquent models defined in routes or controller actions whose type-hinted variable names match a route segment name.
In URL, your tag parameter is integer, however in your controller action $tag will be a model object:
function action(Tag $tag) {
$tag->name;
}
So you don't need to get the $tag by eloquent in your controller action. You just need to specify it is From model Tag $tag
It will do it automatically.

Resources