Laravel Ajax controller with single route - ajax

Just wondering if this is a good way to write ajax code to interact with Laravel routes?
Example my application's require to list all customer data and also list all country through ajax. I have 3 controller ApiController, CustomerController, CountryController.
So in my routes.php I have this routes
Route::get('api/v1/ajax/json/{class}/{function}', 'Api\v1\ApiController#ajaxreturnjson');
In the ApiController.php, I have below function to call other controller function to return the data I need.
class ApiController extends Controller
{
public function ajaxreturnjson(Request $request, $controller, $function){
$input = $request->input();
if($request->input('namespace') != ''){
$namespace = $request->input('namespace');
unset($input['namespace']);
}else{
$namespace = 'App\Http\Controllers';
}
$data = array();
try {
$app = app();
$controller = $app->make($namespace.'\\'.$controller);
$data = $controller->callAction($function, array($request)+$input);
} catch(\ReflectionException $e){
$data['error'] = $e->getMessage();
}
return response()->json($data);
}
}
So example to use the ajax, I just need to pass the class name, namespace and also the function name to the ajax url.
Example to retrieve all customer info.
$.ajax({
dataType:"json",
url:"api/v1/ajax/json/CustomerController/getList",
data:"namespace=\\App\\Http\\Controllers\\",
success:function(data){
}
})
So in this way, I don't have to create so many routes for different ajax request.
But I am not sure if this will cause any security issue or is this a bad design?

Personally, I would not do it this way. Sure, you could do it this way, but it's not very semantic and debugging it could be a pain.
Also, if someone else begins working on the project, when they look at your routes file, they won't have any idea how your app is structured or where to go to find things.
I think it's better to have a controller for each Thing.

Related

How to use parameter from function to create an URL? Laravel Routing

I'm sending an URL hashed and when i get it i have to show a view on Laravel, so i have those functions on the controller and also some routes:
This are my routes:
Route::post('/sendLink', 'Payment\PaymentController#getPaymentLink');
Route::get('/payment?hash={link}', 'Payment\PaymentController#show');
And this are the functions i have on my controller:
public function getPaymentLink (Request $request){
$budgetId = $request['url.com/payment/payment?hash'];
$link = Crypt::decryptString($budgetId);
Log::debug($link);
//here to the show view i wanna send the link with the id hashed, thats why i dont call show($link)
$view = $this->show($budgetId);
}
public function show($link) {
$config = [
'base_uri' => config('payment.base_uri'), ];
$client = new Client($config);
$banking_entity = $client->get('url')->getBody()->getContents();
$array = json_decode($banking_entity, true);
return view('payment.payment-data')->with('banking_entity', $array);
}
And this is getting a "Page not found" message error.
What i want to to is that when i the client clicks on the link i send him that has this format "url.com/payment/payment?hash=fjadshkfjahsdkfhasdkjha", trigger the getPaymentLink function so i can get de decrypt from that hash and also show him the view .
there is no need to ?hash={link} in get route
it's query params and it will received with $request
like:
$request->hash
// or
$request->get('hash')
You need to define route like this:
Route::get('/payment/{hash}', 'Payment\PaymentController#show');
You can now simply use it in your Controller method like below:
<?php
public function getPaymentLink (Request $request,$hash){
$budgetId = $hash;
// further code goes here
}

Obtain CodeIgniter links that consider routes.php

How can I link pages in my site considering routes.php?
Example:
$route['login'] = 'user/login';
The code above allows me to see "user/login" visiting just "login". But how can I link to that page using the internal route (user/login) and get as a result the "external route" "login".
I think it's important because I could change my URLs just modifiying "routes.php" and linking everything with internal routes.
From a Drupal perspective I can have my internal route "node/1" and the external url could be "about-us". So if I use "l('node/1')" this will return "about-us". Is there a function like "drupal_get_path_alias"?
Right now I can't find anything in the CI docs that point me to the right direction.
Thanks for your help.
You could have a look at using something like
http://osvaldas.info/smart-database-driven-routing-in-codeigniter
This would allow you to have the routes configured in the database. Then if you want to dynamically create you links through a model like this:
class AppRoutesModel extends CI_Model
{
public function getUrl($controller)
{
$this->db->select('slug');
$this->db->from('app_routes');
$this->db->where('controller', $controller);
$query = $this->db->result();
$data = $query->row();
$this->load->library('url');
return base_url($data->slug);
}
public function getController($slug)
{
$this->db->select('controller');
$this->db->from('app_routes');
$this->db->where('slug', $slug);
$query = $this->db->result();
$data = $query->row();
return $data->controller;
}
}
These have not been fully tested but will hopefully give you the general idea.
I hope this helps you :)
Edit------------------------------
You can create a routes_helper.php and add a function like
//application/helpers/routes_helper.php
function get_route($path)
{
require __DIR__ . '/../config/routes.php';
foreach ($route as $key => $controller) {
if ($path == $controller) {
return $key;
}
}
return false;
}
$this->load->helper('routes');
echo get_route('controller/method');
This does roughly what you want although this method does not support the $1 $2 etc vars that can be added to reflect the :num or :any wildcard that exist. You can edit the function to add that functionality but this will point you in the right direction :D
You can do that with .htaccess file:
Redirect 301 /user/login http://www.example.com/login

Laravel 4 : Route to localhost/controller/action

I'm more or less new to Laravel 4. I've never used routes before but normally what I'm used to is url/controller/action and then the backend routing for me. I've read the documentation for routes and controllers a few times as well as read through some tutorials and so, I'm trying to figure out how to get this to work without writing a route for every controller and action.
I tried something like
Route::get('{controller}/{action}', function($controller, $action = 'index'){
return $controller."#".$action;
});
Now then, I know this is wrong since it doesn't work, but what am I missing? On most tutorials and stuff I'm seeing an route for more or less every controller and action like:
Route::get('/controller/action' , 'ControllerName#Action');
Which seems silly and like a waste of time to me.
Is there anyway to achieve what I want?
If you are looking for a more automated routing, this would be the Laravel 4 way:
Route:
Route::controller('users', 'UsersController');
Controller (in this case UsersController.php):
public function getIndex()
{
// routed from GET request to /users
}
public function getProfile()
{
// routed from GET request to /users/profile
}
public function postProfile()
{
// routed from POST request to /users/profile
}
public function getPosts($id)
{
// routed from GET request to: /users/posts/42
}
As The Shift Exchange mentioned, there are some benefits to doing it the verbose way. In addition to the excellent article he linked, you can create a name for each route, for example:
Route::get("users", array(
"as"=>"dashboard",
"uses"=>"UsersController#getIndex"
));
Then when creating urls in your application, use a helper to generate a link to a named route:
$url = URL::route('dashboard');
Links are then future proofed from changes to controllers/actions.
You can also generate links directly to actions which would still work with automatic routing.
$url = URL::action('UsersController#getIndex');
app\
controllers\
Admin\
AdminController.php
IndexController.php
Route::get('/admin/{controller?}/{action?}', function($controller='Index', $action='index'){
$controller = ucfirst($controller);
$action = $action . 'Action';
return App::make("Admin\\{$controller}Controller")->$action();
});
Route::get('/{controller?}/{action?}', function($controller='Index', $action='index'){
$controller = ucfirst($controller);
$action = $action . 'Action';
return App::make("{$controller}Controller")->$action();
});
I come from .Net world and routing is typically done:
/{Controller}/{action}/{id}
Which looks like:
/Products/Show/1 OR /Products/Show/Beverages
In Laravel I accomplish this routing like so:
Route::get('/{controller?}/{action?}/{id?}', function ($controller='Home', $action='index', $id = null) {
$controller = ucfirst($controller);
return APP::make("{$controller}Controller")->$action($id);
});
The controller would look roughly like so:
class ProductsController extends BaseController {
public function Show($id) {
$products = array( 1 => array("Price" => "$600","Item" => "iPhone 6"),
2 => array("Price" => "$700", "Item" => "iPhone 6 Plus") );
if ($id == null) {
echo $products[1]["Item"];
} else {
echo $products[$id]["Item"];
}
}
}

CI Basic Routing

I have a route in my route.php :
$route['admin/(:any)'] = 'ix/$1';
It routes URI such as localhost/somename/admin/home to localhost/somename/ix/home.php controller.
The problem is if the URI is like this : localhost/somename/admin/blog/updates (nonexistant function), rather than returning 404, it will just run the blog controller construct code.
How do I avoid this? One option is to add the routing to accept only necessary parameters, but is there any other way?
Thanks
You can add a remap function to route the controller internally:
http://ellislab.com/codeigniter/user_guide/general/controllers.html#remapping
public function _remap($method, $params = array())
{
if (method_exists($this, $method))
{
return call_user_func_array(array($this, $method), $params);
}
show_404();
}

issues with backbone.js DELETE request and codeigniter restserver (phils)

I'm sure this is something I'm doing wrong, but I can't seem to figure it out. I'm using backbone.js to talk to my rest server (Philip Sturgeon's codeigniter restserver). I am running a normal model.destroy() on one of my backbone collections model.
//a basic example
tagCollection.at(5).destroy();
This creates a proper call to a url like:
DELETE http://mydomain.com/index.php/tags/tag/id/12
When I get inside my "tag_delete" php function, and do:
$this->delete('id');
This always returns nothing. I assume this has something to do with the way backbone.js sends it's requests, but nothing is jumping out at me. Details below.
Backbone is issuing a "DELETE" request.
Relevant code from my REST_Controller method:
function tag_delete () {
//delete the tag
$id = $this->delete('id'); //always empty
$result = $this->tag_model->delete($id);
if (! $result) {
$this->response(array('status' => 'failed'), 400);
}
$this->response(array('status' => 'success'), 200);
}
Any ideas? Any backbone.js experts run into this when using codeigniter and Philip Sturgeon's restserver?
This should be a cheap quick way to fix your delete request...
function tag_delete () {
$id = $this->uri->segment(4);
$result = $this->tag_model->delete($id);
if (! $result) {
$this->response(array('status' => 'failed'), 400);
}
$this->response(array('status' => 'success'), 200);
}
However, this is how I am structuring my requests using a combo of backbone and REST_Controller...
DELETE http://example.com/index.php/tags/12
(get rid of the /tag/id/ segment of the url... it's implied that you are deleting a 'tag' row from the 'tags' collection by id, appending /tag/id is unnecessary)
function tag_delete ($id) {
$result = $this->tag_model->delete($id);
if (! $result) {
$this->response(array('status' => 'failed'), 400);
}
$this->response(array('status' => 'success'), 200);
}
for the collection:
Backbone.Collection.extend({
url : '/tags'
});
tagCollection.at(5).destroy();
Then add something like this to your routes:
$route['tags/(:num)'] = 'tags/tag/$1';
which will set up the structure necessary for the restserver controller... it is just much more manageable that way if you are doing a lot of Backbone work.
As per tgriesser's suggestion, the best way to do this is to use the url property on the collection. I have used the following before and it works like charm (the following controller implemented using silex framework + paris library for data access):
// DELETE /{resource}/{id} Destroy
$app->delete('/api/todos/{id}', function ($id) use ($app) {
$todo = $app['paris']->getModel('Todo')->find_one($id);
$todo->delete();
return new Response('Todo deleted', 200);
});
In your backbone collection, add the following:
window.TodoList = Backbone.Collection.extend({
model: Todo,
url: "api/todos",
...
});
Recently, I have written a tutorial on how to do GET/POST/PUT/DELETE with Backbone.js and PHP http://cambridgesoftware.co.uk/blog/item/59-backbonejs-%20-php-with-silex-microframework-%20-mysql, might be helpful.

Resources