I'm sort of new to Silex and learning. I'm trying to return the base url inside one of my route controllers to return the new path after inserting a row into a database. No matter what I try it's returning an empty string though. Here's part of that function:
$app->match('/item', function(Request $request) use ($app) {
$method = $request->getMethod();
switch ($method) {
//POST
case 'POST': //insert
$data = array(
'item' => $request->get('item'),
'description' => $request->get('description'),
'quantityOnHand' => $request->get('quantityOnHand'),
'reorderPoint' => $request->get('reorderPoint'),
'supplier_id' => $request->get('supplier_id')
); //before to get supplier_id???? Or do it in ios
$app['db']->insert('inventory', $data);
$newId = (int) $app['db']->lastInsertId(); //cast int
$location = $request->getBaseUrl().'/inventory/id/'.$newId;
return $app->json(array('status' => 201, 'id'=>$newId, 'location' =>$location), 201);
break;
}
}
Everything in the $location variable is working except the base path. Am I missing something? I'm injecting the $request into the controller. When I run this it returns /inventory/item/101 for the location, without my base url.
Based on comments, it seems that what the OP is looking for is the hostname, not the base url, so the getHost method should be used.
Remember, though, that to generate URLs easily you should use the UrlGenerator instead of crafting it manually. Silex has a default provider for this service.
Related
How do I tell my API to display a particular result based on another column?
e.g. localhost:8000/api/gadgets/{{id}}
Normally it returns the particular information of the specific gadget with that ID and localhost:8000/api/gadgets/{{imei_code}} does not return any value or an error whereas imei_code is a column that I needed to pass as a GET request...
I'm using the normal resource controller
public function show(Gadgets $gadget)
{
$response = ['data' => new GadgetResource($gadget), 'message' => 'specific gadget'];
return response($response, 200);
}
Also I need help on how I can create like a search function in the controller.
You can`t do two similar URLs. I think your route for URL
localhost:8000/api/gadgets/{{imei_code}}
isn`t work. Also the order of the routes is important and route that defined firstly will be have higer priority then route that defined secondly.
Because your routes /api/gadgets/{{id}} and /api/gadgets/{{imei_code}} is similar in this case only the one described earlier will be processed.
You can define another router and handler, for example:
localhost:8000/api/gadgets
That will return a list of gadgets by default and you can add filters for imei_code. For example:
localhost:8000/api/gadgets?imei_code=123
And your handler for the new route may be writed something like that:
public function showList(Request $request): GadgetResource
{
if ($imeiCode = $request->query('imei_code')) {
$list = Gadget::query()->where('imei_code', $imeiCode)->get();
} else {
$list = Gadget::query()->take(10)->get();
}
return GadgetResource::collection($list);
}
Or like alternative solution you can create diferent route for searching of gadgets exactly by imei_code to get rid of any route conflicts
localhost:8000/api/gadgets/by_imei/123
public function findByImei(Request $request): GadgetResource
{
$imeiCode = $request->route('imei_code');
$item = Gadget::query()->where('imei_code', $imeiCode)->first();
return new GadgetResource($item);
}
You can specify the model key by scoping - check docs
Route::resource('gadgets', GadgetController::class)->scoped([
'gadget' => 'imei_code'
]);
Than, when Laravel try to bind Gadget model in Controller - model will will be searched by key imei_code.
This code equvalent of
Route::get('/gadget/{gadget:imei_code}');
Try to change response
public function show(Gadgets $gadget)
{
$response = ['data' => new GadgetResource($gadget), 'message' => 'specific gadget'];
return response()->json($response);
}
I'm using Laravel 8 to generate a temporary signed route and pass some params, but I'd like my URL to take me to some URL of my choosing rather than a page in my project.
For context, my Laravel 8 project is an API, so there are no views, my API is then consumed by a front-end project written in Nuxt.
I've tried adding my URL to the first arg of temporarySignedRoute but it says that my route isn't found.
$verifyURL = URL::temporarySignedRoute(
'https://example.com/account/verify', Carbon::now()->addHours(24), ['contact' => 5, 'team' => 'john']
);
What am I missing or what workaround is there here?
UPDATE
So it turns out that I don't need to take the user to an external URL, but it seems that the wrong URL is being generated by URL::temporarySignedRoute.
The start of my generated URL is (for example) https://example.com/api/contact/verify and I need the URL to be https://api.example.com/api/contact/verify
So the same domain, except a sub-domain.
It looks like the APP_URL isn't being read because I changed it and it has no impact, and besides, this is used elsewhere, so I tried updating the URL with:
$verifyURL = URL::temporarySignedRoute(
'contact.verify', Carbon::now()->addHours(24), ['contact' => 5, 'team' => 'john]
);
// fix for wrong URL
$verifyURL = str_replace('example.com', 'api.example.com', $verifyURL);
However, this appears to have an invalid signature when the link provided by $verifyURL is clicked? How can I get the api part at the beginning?
URL::temporarySignedRoute() has a fourth parameter called $absolute which is a boolean. So if you want to prepend a custom url rather than the default url used by Laravel, this is the variable to change.
The default value for $absolute is true. Therefore in order to prepend your own custom url, be sure to change it to false first as below:
$verifyURL = URL::temporarySignedRoute(
'contact.verify', Carbon::now()->addHours(24), ['contact' => 5, 'team' => 'john], false // The $absolute value
);
Then concatenate your custom url:
$your_custom_url . $verifyURL;
First step, in the AppServiceProvider boot method, you need to register custom URL signing:
public function boot()
{
// This allows us to generate a temporary url for report downloading
Storage::disk('reports')->buildTemporaryUrlsUsing(function ($path, $expiration, $options) {
return URL::temporarySignedRoute(
'report.download',
$expiration,
array_merge($options, ['path' => $path])
);
});
}
To create the URL:
Storage::disk('reports')->temporaryUrl($pathname, Carbon::now()->addSeconds(10))
To download the file, this is my controller:
<?php
declare(strict_types=1);
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Storage;
use URL;
class ReportDownloadController extends Controller
{
public function download(Request $request)
{
if (!URL::signatureHasNotExpired($request)) {
return response('The URL has expired.');
}
if (!URL::hasCorrectSignature($request)) {
return response('Invalid URL provided');
}
return Storage::disk('reports')->download($request->get('path'));
}
}
I am new to laravel. I am coming form cakephp, so routing is creating a bit of difficulty for me.
I have tried the Question but getting error in that.
I also tried for Route::controller(); and Route::resource(); but not getting the the result i want.
I simply want the rounting to be
http://example.com/controller/action/param1/param2/param3
also, if i can get answer for the backend management like
http://example.com/backend/controller/action/param1/param2/param3
In Laravel 5.2 the use of Route::controller('Controller') has been deprecated due to annoying race conditions.
To get your desired result. Let's say you have a controller App\Http\Controllers\MyController.
In your routes.php file you would have the following:
Route::group(['middleware' => ['web']], function(Router $router) {
// Note the question marks after the parameters
// this makes them optional.
$router->get('uri/{action?}/{param1?}/{param2?}', [
'uses' => 'MyController#getIndex'
]);
});
You would now have a controller method getIndex
// As the parameters were optional, make sure to give them
// default values.
public function getIndex($action = null, $param1 = null, $param2 = null)
{
// Your route logic
}
im coming from cakephp too, and i write this route for emulate cakephp routing.
Route::any('{anyRoute}', function($anyRoute){
$call = "";
$parts = explode("/", $anyRoute);
$size = sizeof($parts);
if($size > 0){
$controller = ucfirst(strtolower(trim($parts[0])));
$action = trim(array_get($parts, 1));
$params = [];
if(empty($controller)){
return view("welcome");
}
else{
if(empty($action)){
$action = "index";
}
}
if($size > 2){
unset($parts[0], $parts[1]);
$params = array_merge($params, $parts);
}
$object = app('App\\Http\\Controllers\\'.$controller.'Controller');
call_user_func_array([$object, $action], $params);
}
})->where('anyRoute', '(.*)');
Easiest way to get params i thinks this way maybe helps you:
i assume you want to get params
//App/routes.php
Route::get( '/controller/action/{param1}/{param2}/{param3}' , 'ActionController#getParams' );
//App/Http/Controllers/ActionController.php
public function getParams($param1, $param2, $param3 )
{
return $param1.$param2.$param3;
}
for second part it's same.
for more information: laravel controller
Laravel doesn’t have implicit routing like CakePHP (like you, I moved from CakePHP to Laravel). You’re better off defining resource routes, i.e.
$router->resources([
'users' => 'UserController',
'articles' => 'ArticleController',
'events' => 'EventController',
// And so on...
]);
This has the benefit of people being able to see what routes your application responds to by looking over your app/Http/routes.php file, rather than having to delve into your controller classes and seeing what actions you’ve defined in them.
I would like use a method of controller from another bundle, in my controller.
The method this->forward need a Response object, and i don't know how to use it.
public function indexAction($name)
{
$response = $this->forward('AcmeHelloBundle:Hello:fancy', array(
'name' => $name,
'color' => 'green',
));
// ... further modify the response or return it directly
return $response;
}
And i saw that i can use service but i want to know if its the best solution or they are another.
$this->forward takes arguments in this order:
Logical Name of controller action in string format i.e. 'AcmeHelloBundle:Hello:fancy'
Parameters to be passed as request variables in array format i.e. array(
'name' => $name,
'color' => 'green',
)
These parameters can be accessed in the controller using request access functions.
Sometimes you want to bypass security completely and run a command in another controller despite a user's permissions level. Luckily you can do that fairly easily.
First, run a use Command for your controller at the top of the controller you want to use the data from:
use AppBundle\Controller\MySourceDataController;
Then call that function from within your destination controller:
$response = MySourceDataController::getTheData( $option1, $option2 );
If you need to pass a Request object, you can do it this way:
$response = MySourceDataController::getTheData( new Request( array(
'server' => 'USAServer1',
) ), $option2 );
This returns a Request with the set parameter of server. I also defined a $option2, this would be a variable often defined in the URL such as:
* #Route("/mydata/{server}/", name="api-source-data")
* #param Request $request
* #param $server
Lastly, if you're passing JSON in that controller and want to convert it back to an object, you can run this bit of code on the $response:
if ( 0 === strpos( $response->headers->get( 'Content-Type' ), 'application/json' ) ) {
$response = json_decode( $response->getContent(), true );
}
Voila. Access any controller form any other controller and bypass security notation for the source controller. :)
So the title describes my problem pretty well I think, but let me explain why I want to do this as theremight be an other solution to my problem that I haven't thought about.
Let's say that I have a route specifying the class of the object it will patch:
Route::patch('{class}/{id}', array(
'as' => 'object.update',
function ($class, $id) {
$response = ...;
// here I want to call the update action of the right controller which will
// be named for instance CarController if $class is set to "car")
return $response;
}
));
This is something pretty easy to do with $app->make($controllerClass)->callAction($action, $parameters); but doing it this way won't call the filters set on the controller.
I was able to do it with laravel 4.0 with the callAction method, passing the app and its router, but the method has changed now and the filters are called in the ControllerDispatcher class instead of the Controller class.
If you have routes declared for your classes then you may use something like this:
$request = Request::create('car/update', 'POST', array('id' => 10));
return Route::dispatch($request)->getContent();
In this case you have to declare this in routes.php file:
Route::post('car/update/{id}', 'CarController#update');
If you Use this approach then filters will be executed automatically.
Also you may call any filter like this (not tested but should work IMO):
$response = Route::callRouteFilter('filtername', 'filter parameter array', Route::current(), Request::instance());
If your filter returns any response then $response will contain that, here filter parameter array is the parameter for the filter (if there is any used) for example:
Route::filter('aFilter', function($route, $request, $param){
// ...
});
If you have a route like this:
Route::get('someurl', array('before' => 'aFilter:a_parameter', 'uses' => 'someClass'));
Then the a_parameter will be available in the $param variable in your aFilter filter's action.
So I might have found a solution to my problem, it might not be the best solution but it works. Don't hesitate to propose a better solution!
Route::patch('{class}/{id}', array(
'as' => 'object.update',
function ($class, $id) {
$router = app()['router']; // get router
$route = $router->current(); // get current route
$request = Request::instance(); // get http request
$controller = camel_case($class) . 'Controller'; // generate controller name
$action = 'update'; // action is update
$dispatcher = $router->getControllerDispatcher(); // get the dispatcher
// now we can call the dispatch method from the dispatcher which returns the
// controller action's response executing the filters
return $dispatcher->dispatch($route, $request, $controller, $action);
}
));