I'm using Laravel (version 4) on a project of mine and I was wondering if it would be possíble in any way to know the verb to my requisition inside a laravel's controller.
Thanks in advance.
I don't know your exact Laravel version.
The current docs say there's a specific method in the Request object. Quoting:
$method = Request::method();
if (Request::isMethod('post'))
{
//
}
but I don't have a 4.1 version to test with, though. In any case you can always access the $_SERVER superglobal - Laravel style, too:
echo Request::server('REQUEST_METHOD');
// will get you "GET", "POST", ecc.
Related
I was asking myself if it was a bad practice to send every ajax request I use on my Laravel 8 project with the HTTP Post method.
What I mean is that, according to Laravel 8 documentation on routing (if I understood everything well), you should use the appropriate HTTP request :
Route::get($uri, $callback);
Route::post($uri, $callback);
Route::put($uri, $callback);
Route::patch($uri, $callback);
Route::delete($uri, $callback);
Route::options($uri, $callback);
A French tutorial on the routes explains this (translated by myself) :
GET : ask for a resource that never changes,
POST : update or create a resource (often wrongly used when PUT is needed),
PUT : create or replace a resource,
PATCH : partialy update a resource,
DELETE : delete a resource.
The "problem", if there is one, is that in my code in almost only use HTTP post requests for AJAX in my routes/web.php file, like this :
Route::post('mails/update/{id}', 'App\Http\Controllers\MailController#update');
Route::post('mails/sendMail/', 'App\Http\Controllers\MailController#sendMailTest')->name('mails.sendMailTest');
Route::post('mails/sendInstantMail/', 'App\Http\Controllers\MailController#sendInstantMail')->name('mails.sendInstantMail');
Route::post('mails/getRouteList/', 'App\Http\Controllers\MailController#getRouteList')->name('mails.getRouteList');
According to what I read, I should probably use PUT or PATCH for my update method. But with POST it works. Is it a bad practice to continue to use POST?
If I guess right, AJAX is only a way to do HTTP request, but in fact it is still the same idea behind the request, so I should change my request methods.
I am really sorry if my question is dumb, and thanks for your help!
Sources :
Laravel 8 - Route documentation about the router methods : https://laravel.com/docs/8.x/routing#available-router-methods
French tutorial on Laravel routing see "Les méthodes" chapter : https://laravel.sillo.org/cours-laravel-8-les-bases-le-routage/
English translated tutorial with Google Translate (See "The methods" chapter) : https://laravel-sillo-org.translate.goog/cours-laravel-8-les-bases-le-routage/?_x_tr_sl=fr&_x_tr_tl=en&_x_tr_hl=fr&_x_tr_pto=wapp
Problem / What I've tried:
Getting the currently used controller and action in Laravel 5 is easy (but not as easy as it should be), however I'm stuck with getting the currently used artisan console command.
To fetch the controller name I do this:
$route = Route::getRoutes()->match(Request::capture());
$listAction = explode('\\', $route->getActionName());
$rawAction = end($listAction);
// controller name and action in a simple array
$controllerAndAction = explode('#', $rawAction);
But when calling from a console action, it always returns the default index controller's name ("IndexController" or so in Laravel). Does anybody know how to make this ?
By the way I've also worked throught Request::capture() but this still gives no info about the command.
The simplest way is to just to look at the arguments specified on the command line:
if (array_get(request()->server(), 'argv.1') === 'cache:clear') {
// do things
}
Yes, you can use $_SERVER directly, but I like to use the helper functions or the Facades, as those will give you the current data.
I go from the assumption that - during unit tests - the superglobals might not always reflect the currently tested request.
By the way: Obviously can also do array_get(request()->server('argv'), '1') or something alike. (request()->server('argv.1') doesnt work at this point). Or use \Request::server(). Depends on what you like most.
As per the Symfony\Component\Console\Command\Command class, the method to return the name of the command (eg. my:command) is:
$this->getName();
You should use it from within an Artisan command extending Illuminate\Console\Command (default on Artisan commands).
Remember that it will return only the command name and not the available parameters (eg. for the command signature my:command {--with-params=} it will only return my:command).
Reflection might be of help? Try this:
$var = new \ReflectionClass($this);
dd($var);
I am always getting the this error.
{"status":false,"error":"Unknown method."}
But all syntax are correct from my side. because everything is working fine on the browser but same URL integration on the devices gives the 'unknown method error'.
I am using this 'get' method. Sample URL
SITEURL/api/login/test?req_type=custom
Am I missing something while integrating? Perhaps a setting? I have just included the library and rest config file.
I think your problem is the name of controller is the same with the name of method try to make a test:
if the name of your controller is:
class Test extends REST_Controller{
//your method name is different from the name of controller class
public function testget_get(){
echo $this->response(array('test'=> 'test'), 200);
}
}
I have experienced this problem on hmvc structure.
You also need to check that from device which method your are getting means they are sending 'POST' or 'GET' so you can update your function name accordingly.
In my case I have done the function name as _get to the methods but from device methods of sending parameter is 'POST' which I am trying to access as 'GET'.
So please cross check this once.
When you create a method with the library, you need to append the type of request you are going to make to it.
So, if your method is test, and you are making a GET request to it, it needs to look like this:
function test_get(){
...
}
Same with POST requests
function test_post(){
...
}
Same with PUT, and DELETE as well.
NB This is only a guess since you didn't include any of your code for some reason.
In my CakePHP app I return JSON and exit for certain requests. An example of this would be trying to access the API for a login as a GET request:
header('Content-Type: application/json');
echo json_encode(array('message'=>'GET request not allowed!'));
exit;
However I am having to prefix the echo with the content type in order for it to be sent as JSON. Otherwise my code at the other end interprets it different.
Any ideas on how to get around this? Or at least improve it.
Update: Cake version 2.3.0
You can leverage the new 2.x response object:
public function youraction() {
// no view to render
$this->autoRender = false;
$this->response->type('json');
$json = json_encode(array('message'=>'GET request not allowed!'));
$this->response->body($json);
}
See http://book.cakephp.org/2.0/en/controllers/request-response.html#cakeresponse
Also you could use the powerful rest features and RequestHandlerComponent to achieve this automatically as documented: http://book.cakephp.org/2.0/en/views/json-and-xml-views.html
You just need to allow the extension json and call your action as /controller/action.json.
Then cake will automatically use the JsonView and you can just pass your array in. It will be made to JSON and a valid response by the view class.
Both ways are cleaner than your "exit" solution - try to unit-test code that contains die()/exit(). This will end miserably. So better never use it in your code in the first place.
I've built a web API using CodeIgniter and am about to roll out an updated version. So, let's say you can make the following calls into it:
mysite.com/api/v1.0/get_customers
mysite.com/api/v2.0/get_customers
(Assume I'm using routes to get to the right controller version).
I have a CI library structure like this:
controllers/
+ 1.0/
+ Api.php
+ 2.0/
+ Api.php
libraries/
+ 1.0/
+ Customer.php
+ 2.0/
+ Customer.php
models/
+ 1.0/
+ Customer_model.php
+ 2.0/
+ Customer_model.php
Now assume a v1.0 call comes in and I load the 1.0 controller, which loads the 1.0 library and model. After that, a v2.0 call comes in and I load all 2.0 versions...
Will CI recognize that the path to the 1.0 classes are different than the 2.0 classes and re-load them (rather than thinking they already loaded because they share the same class name when in fact it's the 1.0 version)?
How do people deal with this? Do I need to use different class names, like this:
class Customer_1_0
class Customer_2_0
class Customer_model_1_0
class Customer_model_2_0
I hope not... Is there a cleaner way to do this? I feel like I am missing something fundamental here.
Thank you,
Steve
When CI looks for a class, it looks on a request-by-request basis (loading <domain>/foo/bar then <domain>/foo/bar again will still reload the class Foo, unless you have caching of some form) and it terminates when it feels that it has the appropriate classes (which is good, because if it were too aggressive, it would cause collisions).
Assuming that your given CI version knows which directory it is supposed to look in, you should not have a problem. Of course, if you have two versions of the same class in the same file, that wouldn't work in PHP in general.
I know the post is very old but, it was left without any solution and there is a solution to that.
(Obs.: i am using Codeigniter 3)
In config/autoload.php codeigniter file you should get the API version requested from URI. Something like this:
$URISegments = explode('/', $_SERVER['REQUEST_URI']);
$version = $URISegments[2]; // get the version from the correct segment
Check if the version requested is a valid API version:
$APIPath = APPPATH . 'controllers' . DIRECTORY_SEPARATOR . $version;
if ( ! file_exists($APIPath)) {
// give some error and exit
}
Now we know we have a valid API version being requested, so, what we should do is generate the correct path to the model version the API will consume:
$unversionedModelClasses = ['OneModel', ...];
$versionedModelClasses = array_map(
function($modelClass) use ($version)
{
return $version . '/' . $modelClass;
}
, $unversionedModelClasses);
The result of that is an array like this:
Array
(
[0] => v1.0/OneModel,
...
After that, you just have to assign this array to $autoload['model']:
$autoload['model'] = $versionedModelClasses;
And that is it. When you call OneModel in your controller version 1.0, the model version 1.0 will be called, when on 2.0 controller, model version 2.0 will be called.
You don't need use namespace to make the models versions diferents because codeigniter will only require() the models you have on $versionedModelClasses array.
You don't need to rename the model class names, since the same i told previously apply here too.
The same logic can be applied to libraries, and so on, you just need to populate the $autoload['libraries'] etc the same way.