I've set up routes for a resource and added additional routes for the same controller. I've had this route working and don't think I've changed anything but now it's routing to the wrong method in the controller.
I'm aware of the first in and first out principle of the routes and have this set up at the moment:
Route::post('products/addItemToCart', array('uses' => 'ProductsController#addItemToCart'));
Route::post('products/editItemInCart', array('uses' => 'ProductsController#editItemInCart'));
//Product Related Routes
Route::get('products/saletotal/{id}', function ($id) {
return Product::groupedSales($id);
});
Route::get('products/itemValue/{id}', array('uses' => 'ProductsController#itemValue'));
Route::get('products/cartitem/{id}', array('uses' => 'ProductsController#getCartItem'));
Route::resource('products', 'ProductsController');
I have a form which POSTS to products/addItemToCart for some reason this no longer uses the method addItemToCart but is going to the controllers show method and treating the 2nd parameter as an ID of the record to find.
I placed a var_dump at the start of the show method to identify the value being passed to the show method which is addItemToCart
It's as if the routes file is ignoring the previous routes and skipping to the defaults in the resource route.
Any ideas what mistakes I've made?
Thanks
Update: additional code for fuller picture:
The POST is generated by javascript with this method:
if($('#rowId').val() !=="") {
postUrl = "/products/editItemInCart";
} else {
postUrl = "/products/addItemToCart";
}
$.ajax({
type: "POST",
url: postUrl,
data: item,
dataType: 'json',
success: function(result) {
//update the displayed Cart
var data = result;
updateCart();
}
});
item is an array
The method in Products controller are:
<?php
//updated 08-11-2013
class ProductsController extends BaseController {
/**
* Product Repository
*
* #var Product
*/
protected $product;
public function __construct(Product $product)
{
$this->product = $product;
}
public function addItemToCart() {
$product = Product::find( Input::get( 'id' ) );
//method code
}
**
* Display the specified resource.
*
* #param int $id
* #return Response
*/
public function show($id)
{
dd($id);
$product = $this->product->findOrFail($id);
return View::make('products.show', compact('product'));
}
the show method is being used instead of the expected addToCart method as specified in the URL and route
I can see the exected items in the POST from within firebug
You need to add the parameter expectation to the route string.
Route::post('products/addItemToCart/{id}', array('uses' => 'ProductsController#addItemToCart'));
Otherwise the resource controller interprets this as products/{param}/{param} hence why it goes to the default post implementation of the controller.
Related
I made a search method that should allow me to search in a TWIG table, added custom repository method that would allow me to find the entity by specified attribute and called it in the controller function and also the script responsible for the search function with its input label in the twig file but I keep getting the "[Semantical Error] Couldn't find constant name, method App\Controller\InventaireContesController::searchConte() in C:\Users\maiez\Projet\config/routes../../src/Controller/ (which is being imported from "C:\Users\maiez\Projet\config/routes/annotations.yaml"). Make sure annotations are installed and enabled.
" error.
Please find below the script in the twig code containing the search function :
<script>
$(document).ready(function(){
$('#search').keyup(function(){
search_table($(this).val());
});
function search_table(value){
$('#sa tbody').each(function(){
var found = 'false';
$(this).each(function(){
if($(this).text().toLowerCase().indexOf(value.toLowerCase()) >= 0)
{
found = 'true';
}
});
if(found == 'true')
{
$(this).show();
}
else
{
$(this).hide();
}
});
}
});
</script>
This is the search input field :
<input id="search" class="form-control" type="text" name="search" placeholder="Rechercher..." aria-label="Search">
This is the custom method in the entity repository :
public function findContes($cnt){
return $this->createQueryBuilder('contes')
->where('contes.titre LIKE :titre')
->setParameter('titre', '%'.$cnt.'%')
->getQuery()
->getResult();
}
and this is the controller method that seems not to work :
/**
* #Route ("/invContes/search", name"searchInv")
* #param Request $request
* #param NormalizerInterface $Normalizer
* #return Response
* #throws \Symfony\Component\Serializer\Exception\ExceptionInterface
*/
public function searchConte(Request $request, NormalizerInterface $Normalizer)
{
$repository = $this->getDoctrine()->getRepository(Inventairecontes::class);
$requestString=$request->get('searchValue');
$conte=$repository->findContes($requestString);
$jsonContent=$Normalizer->normalize($conte,'json',['groups'=>'contes']);
$retour = json_encode($jsonContent);
return new JsonResponse($jsonContent);
}
Imports and twig IDs are correct.
Thank you in advance.
I have this route declared on laravel:
Route::get('pages/{page}/{slug}', 'Common\Pages\CustomPageController#show')
->middleware(['web', 'prerenderIfCrawler']);
This route works fine and works if you make requests to:
https://example.com/pages/1/test-page
https://example.com/pages/2/other-page
https://example.com/pages/3/url-test
The problem is that I need a more friendly url as well as.
https://example.com/test-page
https://example.com/other-page
https://example.com/url-test
I want remove the suffix called pages, The numbers for the pages will never change and will be static for each one.
I've tried to make static routes for each one but can't get it to work.
Route::get('other-page', array('as' => 'other-page', function() {
return App::make('Common\Pages\CustomPageController')->show(2);
}))->middleware(['web', 'prerenderIfCrawler']);
I would appreciate a little help.
You could always get the URL segment in the Controller and use that to know what page you are on. If you don't want to do that you could pass extra information in the 'action' to specify the page:
Route::middleware(['web', 'prerenderIfCrawler'])->group(function () {
Route::get('test-page', [
'uses' => 'Common\Pages\CustomPageController#show',
'page' => 'test-page',
]);
...
});
Then you can get this extra information in the Controller:
public function show(Request $request)
{
$page = $request->route()->getAction('page');
...
}
If you knew all the pages you can use a route parameter with a regex constraint to restrict it to only those page names:
Route::get('{page:slug}', ...)->where('page', 'test-page|other-page|...');
public function show(Page $page)
{
...
}
You could just make use of a wildcard to catch your routes like this:
Route::get('/{slug}', 'Common\Pages\CustomPageController#show')
->middleware(['web', 'prerenderIfCrawler']);
Then in your controller:
public function show($slug)
{
$page = Page::where('slug', $slug)->first();
// ...
}
Just be careful with where you place the route. It should be at the end of your routes otherwise it will catch all the request of your app.
// ...
// my other routes
// ...
Route::get('/{slug}', ...);
By the way, if you want to bind your page models using the slug attribute do this:
Route::get('/{page:slug}', 'Common\Pages\CustomPageController#show')->//...
^^^^^^^^^
Then in your controller:
public function show(Page $page)
{ ^^^^^^^^^^
// ...
}
Check this section of the docs.
I have a template home.html.twig loaded and an ajax request as the code below shows. That works just fine.
But if I load my website with the route mywebsite.com/search/foo then I only have searchListing.html.twig displayed without any home.html.twig loaded so the site is broken
So is there a way in the controller, before the return, to check if my template home.html.twig is loaded and if not load it and insert searchListing.html.twig inside a block ?
my html:
<li>foo</li>
here is my ajax:
$(document).ready(function() {
$('.trigger').on('click', function(e) {
e.preventDefault();
const $link = $(e.currentTarget);
$.ajax({
url: $link.attr('href'),
type: 'get'
})
.done(function (data) {
$('#main-content').html(data)
})
});
});
my controller:
class Search extends AbstractController {
/**
* #Route("/search/{var}", name="search")
*/
public function search ($var) {
// CHECK HERE
// if home.html.twig is loaded > load searchListing.html.twig inside a given block
// if home.html.twig is not loaded > load home.html.twig then load searchListing.html.twig inside a given block
return $this->render('searchListing.html.twig',[
'var' => $var,
]);
}
}
If I understand correctly you need:
/**
* #Route("/search/{var}", name="search")
*/
public function search (Request $request, $var) {
// render only search results for ajax request
if ($request->isXmlHttpRequest()) {
return $this->render('searchListing.html.twig',[
'var' => $var,
]);
}
return $this->render('home.html.twig',[
'var' => $var,
]);
}
my json post request has a data key named "id", now how im going to pass it from routes to my controller?
my json post request
$.post("/employees", {id:"1"}, function(response){
if(response.success)
{
var branchName = $('#branchname').empty();
$.each(response.employees, function(){
$('<option/>', {
value:$(this).user_no,
text:$(this).firstname
}).appendTo(branchName);
});
}
}, 'json');
as you can see from my json post request i have put a key value name id
my routes
Route::post('employees', [
'as' => 'employees', 'uses' => 'mot#getemployee'
]);
and my controller
public function getemployee($id){
$employees = employees::where("branch_no", $id)->lists('firstname', 'user_no');
return response()->json(['success' => true, 'employees' => $employees]);
}
as you can see, I have an argument $id, it supposedly, its where the key value named id from the json post request will be put and be used from the query stuff.
Since you're using $.post in your jQuery code, the {id: ...} parameter passed as a POST data, which means that instead of having:
public function getemployee($id){
You should have:
public function getemployee() {
$id = (int)$_POST['id']; //notice that int casting
#KhanShahrukh has a good point. Consider using the following instead of the traditional POST variable:
<?php
namespace App\Http\Controllers;
use Request;
....
....
class ... extends ... {
public function ...() {
if(Request::ajax()) { //Prevent direct access
$id = Request::input('id;);
Regarding the second issue (which mentioned in the comment), $(this) won't refer to the object. In order to access the object's properties, you should add parameters to the function() in your $.each function. (Manual)
So instead of:
$.each(response.employees, function(){
$('<option/>', {
value:$(this).user_no,
text:$(this).firstname
You should have:
$.each(response.employees, function(firstname, user_no){
$('<option/>', {
value: user_no,
text: firstname
Is it possible to access route parameters within a filter?
e.g. I want to access the $agencyId parameter:
Route::group(array('prefix' => 'agency'), function()
{
# Agency Dashboard
Route::get('{agencyId}', array('as' => 'agency', 'uses' => 'Controllers\Agency\DashboardController#getIndex'));
});
I want to access this $agencyId parameter within my filter:
Route::filter('agency-auth', function()
{
// Check if the user is logged in
if ( ! Sentry::check())
{
// Store the current uri in the session
Session::put('loginRedirect', Request::url());
// Redirect to the login page
return Redirect::route('signin');
}
// this clearly does not work..? how do i do this?
$agencyId = Input::get('agencyId');
$agency = Sentry::getGroupProvider()->findById($agencyId);
// Check if the user has access to the admin page
if ( ! Sentry::getUser()->inGroup($agency))
{
// Show the insufficient permissions page
return App::abort(403);
}
});
Just for reference i call this filter in my controller as such:
class AgencyController extends AuthorizedController {
/**
* Initializer.
*
* #return void
*/
public function __construct()
{
// Apply the admin auth filter
$this->beforeFilter('agency-auth');
}
...
Input::get can only retrieve GET or POST (and so on) arguments.
To get route parameters, you have to grab Route object in your filter, like this :
Route::filter('agency-auth', function($route) { ... });
And get parameters (in your filter) :
$route->getParameter('agencyId');
(just for fun)
In your route
Route::get('{agencyId}', array('as' => 'agency', 'uses' => 'Controllers\Agency\DashboardController#getIndex'));
you can use in the parameters array 'before' => 'YOUR_FILTER' instead of detailing it in your constructor.
The method name has changed in Laravel 4.1 to parameter. For example, in a RESTful controller:
$this->beforeFilter(function($route, $request) {
$userId = $route->parameter('users');
});
Another option is to retrieve the parameter through the Route facade, which is handy when you are outside of a route:
$id = Route::input('id');