I would like to pass the id of an object to a controller in laravel. Basically I've a page that displays the information relating to a book. The user has the option to add themes to that book. The line below is the link they click in order to open the create theme form:
Add Theme
and the ThemeController method:
public function create(){
$books = Book::all();
return View::make('theme.create', compact('books'));
}
Currently this brings up a Form with a list of all of my books in a dropdown. I would rather just pass the id of the book the user was on prior to being brought to this form and use that instead. Is there any way I can do that? I've also included my routes.php file:
Route::model('book', 'Book');
//Show pages
Route::get('/books', 'BookController#index');
Route::get('book/create', 'BookController#create');
Route::get('book/edit/{book}', 'BookController#edit');
Route::get('book/delete/{book}', 'BookController#delete');
Route::get('book/view/{book}', 'BookController#view');
////Handle form submissions
Route::post('book/create', 'BookController#handleCreate');
Route::post('book/edit', 'BookController#handleEdit');
Route::post('book/delete', 'BookController#handleDelete');
//Themes
Route::model('theme', 'Theme');
Route::get('/themes', 'ThemeController#index');
Route::get('theme/create', 'ThemeController#create');
Route::get('theme/edit/{book}', 'ThemeController#edit');
Route::get('theme/delete/{book}', 'ThemeController#delete');
Route::get('theme/view/{book}', 'ThemeController#view');
Route::post('theme/create', 'ThemeController#handleCreate');
Route::post('theme/edit', 'ThemeController#handleEdit');
Route::post('theme/delete', 'ThemeController#handleDelete');
You can still use normal $_GET methodology.
On your route:
book/create
You could simply request.
book/create?book_id=xxyy
Then in your controller create function
public function create(){
$bookId = Input::get('book_id');
$books = Book::all()->where('book_id' => $bookId);
return View::make('theme.create', compact('books'));
}
PLEASE NOTE:
I haven't used Laravel in a while, don't trust that elequont query :P.. I was just putting a theoretical "where" in there.
And here http://laravel.com/docs/requests#basic-input, you will note this:
"You do not need to worry about the HTTP verb used for the request, as
input is accessed in the same way for all verbs."
So whether you're using get, put, post or delete, whatever you wrapped in your header, you will be able to find using Input Class.
EDIT
Just needed to add, that you won't need to modify your routes at all. This is just a Simple GET parameter in a GET request. Just like in any other application.
Related
I have a bit of a complicated issue. I could use some help.
I have a form that is being handled by the following function:
$module = request('module');
$classe = request('classe');
$horaire = request('horaire');
$date = request('date');
$students = DB::select('SELECT * FROM `etudiants` WHERE etudiants.id_classe = '.$classe);
return view('g_absence.absence',['module'=> $module, 'classe'=>$classe,'horaire'=>$horaire,'date'=>$date,'students'=>$students]);
I take the values $module, $class, $horaire, $date and $students and need to use them inside a different view: g_absence.absence. This works fine and when the view is returned I have access to said variables.
The issue is, inside the g_absence.absence view, I have another form that also needs to be handled, and because the url remains the same even tho a different view is returned, I cant make two posts for the same path.
web.php:
Route::get('/testboy', [App\Http\Controllers\g_absence::class,'index'])->name('marquer');
Route::post('/testboy',[App\Http\Controllers\g_absence::class, 'marquer']);
Route::post('/testboy',[App\Http\Controllers\g_absence::class, 'ajoutabsence']);
The first line is the one that send to the form page just a simple
return view
The second one handle the form in that view
The third one, I want it to handle the form inside the
g_absence.absence view, but they share the same path.
Excuse me if I'm being unclear, I'm a bit of a beginner in Laravel
your problem is using the same route for different methods
basically the first route gets executed every time you use the '/testboy' action that is why your second function never get's called.
you can solve this issue by changing your urls for example:
Route::post('/testboy-marquer',[App\Http\Controllers\g_absence::class, 'marquer']);
Route::post('/testboy-ajoutabsence',[App\Http\Controllers\g_absence::class, 'ajoutabsence']);
Or you can use one function that's handle both with one url by pathing additional parameter to your url depending on your function call :
Route::post('/testboy?type=marquer',[App\Http\Controllers\g_absence::class, 'ajoutabsence']);
in your function check the type :
if(request('type') == 'marquer') {
execute marquer logic here...
} else {
execute absence logic here...
}
Using method and path with two functionalities is wrong, but if you want to somehow use both routes my same method and path which I don't recommend you must let the request to pass through like a middleware in your first block of code Instead of return a view.
Recommended way is to have 2 routes with different paths or at least one route with a parameter by which you can determine what code block must be executed.
Imagine you have the following resources for example: Users, Posts and Comments (With typical relationship setup in laravel).
When fetching a single Post, you will have the following endpoint
GET /api/posts/1
// With route model binding
public function show(Post $post)
{
return $post;
}
This is fine if I only want the Post object, but in some pages in my application, I also need to load the User and the Comments associated with the Post.
How do you guys handle that kind of scenario?
1. Should I load everything in that endpoint like:
return $post->load(['user', 'comments.user']);
and call it a day? (nope)
2. Should I accept an additional parameter that will tell my controller to load the relationship based on that value?
// With route model binding
public function show(Request $request, Post $post)
{
// rel for "relationship"
if ($request->has('rel')) {
$post->load($request->input('rel'));
}
return $post;
}
with this approach I could do something like this:
GET /api/posts/1?rel=user
returns Post with User
or I could build an array of parameter with jquery's $.param(['user', 'comments.user'])
GET /api/posts/1?rel%5B%5D=user&rel%5B%5D=comments.user
returns Post with User + Comments.User
but anyone can easily mess with the 'rel' parameter so I also need to check that
¯\(°_o)/¯
3. Just create a new endpoint for every specific requirements. (what should your endpoint look like for the example above?).
I'm building a SPA with Angular + Laravel (just a self-consumed API) for my Internal Project when I encounter this pitfall. The second approach is what I currently using for basic fetching and I use the third approach for more complex requirements.
Any inputs are appreciated.
I have a resource controller for member data. All of the usual resource functions, including edit, are working perfectly. I am trying to add additional edit functions within this controller so that I can create views that only are for specific subsets of the Member model data, since the data set is rather large. So, I've set up the extra routes and functions. But when I attempt to link to the edit2 resource, Laravel will not create the proper link. I don't know what I'm doing wrong. Code:
Route:
Route::get('members.edit2', array('as'=>'edit2', 'uses'=> 'MembersController#edit2'));
Route::resource('members','MembersController');
MembersController:
// Regular edit function -- works just fine:
public function edit($id)
{
$member = $this->member->find($id);
return View::make('members.edit', array(
'member'=>$member, ...
));
}
// Extra edit2 function -- should work if I could successfully route to it:
public function edit2($id)
{
$member = $this->member->find($id);
return View::make('members.edit2', array(
'member'=>$member, ...
));
}
show.blade.php:
// normal edit link (works fine, see source code below):
edit
// additional edit2 link (creates a bad link, see source code below):
edit
source code:
// normal link that uses edit for member id=27:
edit
// link that attempts to use edit2 for same member:
edit
I'm sure there is a way of doing this. It doesn't matter whether I use the named route 'edit2' rather than 'members.edit2', the exact same bad link is created. I've tried every combination I can think of. Laravel docs are not at all helpful for this. Thanks!
Your don't declare your edit2 route as you should do. Your first mistake is that the member's id you want to edit is not passed as a parameter and the second one that by calling this {{route('edit2')}} Laravel expects a url like /members.edit2 which is never going to appear. You should better use sth like /members/{id}/edit2.
Try using this:
Route::get('members/{id}/edit2', array('as'=>'edit2', 'uses'=> 'MembersController#edit2'));
and call it like:
{{ route('edit2', [$id]) }}
Also be careful, whenever you call Url::route() or simply route() you should pass their parameters in an array like:
{{route('myRoute', ['par1', 'par2', 'par3', ...]}}
Here is the flow:
User creates a text based post.
User edits a text based post (an edit page with the post info is displayed)
User submits the changes to the post (a request sent to the post controller)
Now, if I have MULTIPLE types of posts, I have to check in steps 2 and 3 that the user is indeed updating the RIGHT type of post because someone could very well alter the URL to edit a post of type A when it's really of type B. This leads to a lot of redundant code, such as ...
if(user is indeed the editor && the post type is correct) show the edit page
I think it would make a lot of sense to have an EDIT controller that does all the verification needed in the constructor (or maybe a base class?), and then calls the method. Have you encountered similar issues like this - and if not, does this make any design sense?
CodeIgniter is an MVC. That means that your controllers serve as an intermediate between your models (your data), and your view (front-end). "Edit" is an action that you do to objects, like data. Data objects should be organized within a controller, which calls the actual edit functions from the model.
I'm assuming you have a Post controller. At its core, it should have basic CRUD functions, like adding and editing posts. It should look something like this:
class Post extends CI_Controller
{
function __construct()
{
parent::__construct();
}
function index()
{
// List all posts, perhaps?
}
function add()
{
// Add a post
}
function edit($post_id)
{
// Edit a post
}
function view($post_id)
{
// View a post
}
}
That will give you the following pages:
http://example.com/post
http://example.com/post/add
http://example.com/post/view/1
http://example.com/post/edit/1
Checking for user permissions is its own chapter. If you are using a library like Tank Auth, you can check permissions like so:
if ($this->tank_auth->is_logged_in()) {
// Do stuff
}
That should go at the beginning of each function - or in the __construct(), if you want to DRY it up completely.
Good luck.
Lets say for example I am creating a an online shop. I have a controller called products and within that controller I have a function called create_product. Create_product calls a view that displays a form where users get to enter new products into the database.
When the user fills in the form to create a product, should I send the action back to the create_product controller and handle it with an IF statement? or offload to another function?
Example
<form method="post" action="www.example.dev/products/create_product/add">
//the above form would post back to the original controller
function create_product()
{
if(uri->segment(3) == "add")
{
//call a model to do all the database stuff
}
load->view->create_product_form;
}
Is this the best way to handle this or should I be passing it off to another function?
Don't cram a ton of stuff in one function using the URI segment to filter it. createProduct() can list the products available for creation (in a CRUD format, I assume), and the submission of the form should ping another controller with the POSTed data. Perhaps insertProduct(), where the data is sanitized and sent to the model for insertion to the database.
Separation of concerns! Keep the functions as separate as possible with good descriptors for the names of the functions.
I (personally) would have a function that set the form parameters and "launch" the view with that form, and another function used to validate and call the model to put the values of that form into the database. I believe that is really up to you, but the code would be cleaner if you divide the controller with several functions depending on what they actually do.
I like the way symfony deals with forms & form submission. It is in one function (action)
simplified code:
executeCreate() {
$this->form = new Form()
if($r->isMethod('POST')) {
//handle submission
bind();
save();
}