Laravel - First segment to be optional - php

I'm fairly new to Laravel and I want my website to be multilingual. And I store the chosen language slug in Session. But how can I make my urls display which language was chosen:
Route::get('/{lang?}/signup', array(
'as' => 'signup',
'uses' => 'UsersController#getSignup'
));
http://example.com/en/signup - if I get the first segment with URL::segment(1) and pass it to the Session everything is OK. With the Route I posted above I get 4oh4 if I open the second link.
So basically I can't think of a way that will make both http://example.com/en/signup and http://example.com/singup to work.
The first link should change the user language and the second should use the value stored in Session to fetch the results for this language.
Edit:
I'm trying to make something like a CMS, where I have set some keys in a table in the database - languages:
id - (int) AI, name - (varchar) - Language's name, prefix - (varchar) - Language's prefix
And another table that stores the translations of certain parts in the website:
id - (int) AI, key (eg. signup_form_name), value (eg. My sign up form)
And I have this function in my helpers.php:
function _t($key, $language = NULL)
{
if(is_null($language))
$language = Session::get('currLang');
$string = DB::table('translations')
->where('key', $key)
->pluck('value');
return (!is_null($string)) ? $string : $key;
}

How could it differentiate
en
from
signup
?
Those are just two strings. The only way could be to hit
http://example.com//signup
Instead of
http://example.com/signup
Because this way you are explicitly telling Laravel that you are not passing the first route parameter. But that will not work, because Laravel will not understand it too, there's an issue about this in Github.
So this is one of your options:
Route::get('/signup/{lang?}' ...);
So you can hit it as
http://example.com/signup
or
http://example.com/signup/en

Route::get('/{lang?}/signup', array(
'as' => 'signup',
'uses' => 'UsersController#getSignup'
))->where('lang', '(en|br)');
The key problem here is that you need to hard code the langs into your controller, but it should work...

Related

What is the best way for various meaning slug in Laravel Routing?

for perfect SEO, I need the following url structure.
http://127.0.0.1:8000/california-side-hustles
http://127.0.0.1:8000/california-san-francisco-side-hustles
http://127.0.0.1:8000/california-san-francisco-94804-side-hustles
http://127.0.0.1:8000/vacation-home-rentals-side-hustles
for above urls, I can make the Laravel Route like this.
Route::get('{id}side-hustles', function ($id) {
});
but I have a problem on this. I am in finding the best way for working, because the above 4 urls have to get the each other results.
http://127.0.0.1:8000/california-side-hustles
california => state param
by using this param, I need to retrieve the results from the database.
http://127.0.0.1:8000/california-san-francisco-side-hustles
california => state param
san-francisco => city param
by using these 2 params, I need to retrieve the results from the database.
http://127.0.0.1:8000/california-san-francisco-94804-side-hustles
california => state param
san-francisco => city param
94804 => zip code param
by using these 3 params, I need to retrieve the results from the database.
http://127.0.0.1:8000/vacation-home-rentals-side-hustles
vacation-home-rentals => object param title
by using this param, I need to retrieve the object from the database
totally, above 4 url rules will have the same format like this {slug}-side-hustles. their process will not be same.
for this, what is the best way on laravel routing?
I would suggest you to simplify.
Using your URLs as example:
http://127.0.0.1:8000/california-side-hustles
http://127.0.0.1:8000/california-san-francisco-side-hustles
http://127.0.0.1:8000/california-san-francisco-94804-side-hustles
You could use the following
http://127.0.0.1:8000/{state}/{article}
http://127.0.0.1:8000/{state}/{city}/{article}
http://127.0.0.1:8000/{state}/{city}/{zipcode}/{article}
And in the controller(s), you can create dedicated methods for each route.

Using regex to make menu item active in laravel adminlte

2021: This was in fact an issue with the package. Regex link matching has since been implemented with the solution I created to solve it for myself. You can read about it in the documentation here.
I'm using Laravel 5.8 with AdminLTE for Laravel.
There's several options to create a menu, one of which is to create it in the provided config file, which I use.
You can specify an active key in the menu that allows you to make the menu have the class that makes the menu item active and activates the dropdown.
I have a menu item, which I would like to make active on these pages:
/posts (works with active => ['/posts'])
/posts/{post_id} (id are only numbers)
These URL's shouldn't match:
/posts/create
/posts/anyotherlink
/posts/1text
I can not use /posts/* because that would make the create page and some others active.
The readme suggest that you can also use regex to do this. I don't use regex at all, but I came to this, which, according tot regex101 seems to match what I need it to:
^\/posts\/[0-9]+$
I've tried to implement it like so:
[
'text' => 'Posts overview',
'url' => '/posts',
'icon' => 'list',
'active' => ['/posts', '^\/posts\/[0-9]+$'],
'active' => ['/posts', '/posts/[^0-9]'] // also tried this
],
Unfortunately, this does not seem to work as it doesn't make the menu item active on the pages listed above.
Edit: I've also created an issue in the GitHub repository as I suspect that this might be an issue with the package.
Am I missing something, or doing something wrong?
In the ActiveChecker.php class of the project you can find this piece of code
protected function checkPattern($pattern)
{
$fullUrlPattern = $this->url->to($pattern);
$fullUrl = $this->request->fullUrl();
return Str::is($fullUrlPattern, $fullUrl);
}
Based on laravel documentation, Str::is does not run regexp matching, but justs supports asterisks for wildcards.
In your case you could post a PR that will use regexo if the given pattern is a regular expression, otherwise, run Str::is
You can try using the below pattern in your code:
/^\/posts(\/[0-9]+)?$/
This will work for the below test scenarios:
/posts
/posts/3829
/posts/921
/posts/1
You can check the requirement with the provided solution on REGEX_Solution
Hope it works!
This is where route naming is really helpful. So, in my code this route would named something like admin:post.index. Then to check if it was active I could use the request helper and a method called routeIs().
Using the name I'd use, here's an example:
request()->routeIs('admin:post.index')
Now, if I wanted this link to be active for the create, edit, delete etc routes I'd do the following:
request()->routeIs('admin:post.*')
This would work since I apply route names following a dot notation hierarchy.
You can optionally provide multiple patterns to that method if there were specific routes you wanted to match.
I have created a solution for my problem, it's by no means the prettiest solution, but it'll work, for now.
I have edited the ActiveChecker.php file and edited the checkPattern() function, so it evaluates regex if the pattern in the config file starts with regex:.
protected function checkPattern($pattern)
{
$fullUrlPattern = $this->url->to($pattern);
$fullUrl = $this->request->fullUrl();
if(mb_substr($pattern, 0, 6) === "regex:") {
$regex = mb_substr($pattern, 6);
if(preg_match($regex, request()->path()) == 1) {
return true;
}
return false;
}
return Str::is($fullUrlPattern, $fullUrl);
}
In my config file, I can now just do this, to use a regex pattern, simply by using the regex: prefix.
'active' => ['/suppliers', 'regex:#^posts/[0-9]+$#'],
The path of the request which is posts/1 for example, will get compared with the regex, not the full URL.

Symfony 1.4 linkToDeleteMenu Confirm not making JavaScript

I had to make an entity called ProfileSchema with some fields, which one is Project_id. I needed to make a List, Edit, New, etc., for which I used the admin generator. The problem was as follows.
I have a list of projects, which they link to the list of the ProfileSchemas that have the same project_id, so I needed a route like: /backend/project/:project_id/ListProfileSchema
I couldn't find a way to do this with the admin generator (getting the project_id into the route), so I coded by hand all the routes (around 12, the new, edit, delete, batch actions, etc.), and change all the code generated by the admin generator to use the project_id passed as a parameter and the code generated by the adming generator as a guide.
==Questions==
Is there a way more simple to do something like this?
Now I need to add the confirmation JavaScript on the delete action on the actions of the list, which is generated by the method linkToDeleteMenu
public function linkToDeleteMenu($object, $params){
$url = url_for('project_delete_profile_schema', array('project_id' => $this->project_id, 'profile_schema_id' => $object->getId() ));
// $url = '/backend/project/1/DeleteProfileSchema/16'
return link_to(__($params['label'], array(), 'sf_admin'), $url, $object, array('confirm' => !empty($params['confirm']) ? __($params['confirm'], array(), 'sf_admin') : $params['confirm'], 'project_id' => $this->project_id, 'profile_schema_id' => $object->getId()));
}
The above code doesn't get the JavaScript. This code below generates the link well and it works, but I can't make the confirmation for the JavaScript appear.
return link_to(__($params['label'], array(), 'sf_admin'), $url, $object);
And the confirmation data is set, as replacing $url with $this->getUrlForAction('delete') does the trick but with the incorrect URL (the one generated by the admin generator).
By the way, I searched a lot trying to find something similar. The only similar question was this:
Routing exception in symfony ("The "/league/:id_league/members/new" route has some missing mandatory parameters (:id_league)")
But the answer didn't help me (as the default value is not dynamic and can't get to override it)
I forgot to close this question. After some time i found that the solution was this:
return link_to('Delete', 'project_delete_profile_schema', array('project_id' => $object->getProjectId(), 'profile_schema_id' => $object->getId()), array( 'confirm' => !empty($params['confirm']) ? __($params['confirm'], array(), 'sf_admin') : $params['confirm']));
You pass the name displayed for the link as the 1st argument , the route name as the 2nd arguments, and the needed variables in the array in the 3rd parameter to generate the route. Finally, you pass the array to generate the confirmation code. My route is
project_delete_profile_schema:
url: /project/:project_id/DeleteProfileSchema/:profile_schema_id

How do I pass a parameter from URL to an admin generated form?

I have two models namely 'Client' and 'Pet' which have admin generated modules for each. There is a one-to-many relationship involved so I want to be able to create a new Pet using a cid (client id) specified in the URL (i.e. /pet/new/cid/6)
I already disabled the cid field in the Client form so that the parameter from the URL will be passed as the default value.
I tried overriding the actions.class.php of the admin generated module with this code:
public function executeCreate(sfWebRequest $request)
{
$this->form = $this->configuration->getForm();
$params = $request->getParameter($this->form->getName());
$params["cid"] = $request->getParameter('cid');
$request->setParameter($this->form->getName(), $params);
parent::executeCreate($request);
}
It works if i replaced
$request->getParameter('cid');
with a hard-coded int value so I think the problem is that I'm not able to get the parameter from the URL.
I think I might be missing on some routing configurations but I'm fairly new to this framework so I'm not really sure what to do.
You can simply pass the parameter cid in the url like this :
/pet/new?cid=6
and get the result in your action with :
$request->getParameter('cid');
The first part of the routing (/pet/new) is a specific doctrineRouteCollection

Passing parameters through form to Controller (CakePHP)

Okay, so I'm fairly new to CakePHP. This is the setup:
I've got a Model (Reservation), and a controller, (ReservationController).
I'm trying to provide a simple add() functionality.
The request url is: www.example.com/reservations/add/3
Where 3 is the ID of the event this reservation is for.
So far, so good. The problem is, the form is constructed like this:
<h2>Add reservation</h2>
<?php echo $form->create('Reservation');
echo $form->input('first_name');
echo $form->input('last_name');
echo $form->input('email');
echo $form->input('tickets_student'); echo $form->input('tickets_nstudent');
echo $form->end('Add');?>
When I hit the send button, the request URL becomes simply www.example.com/reservations/add/, and the event id is lost.
I've solved it now by grabbing the id in the controller, and make it available to the form:
// make it available for the form
$this->set('event_id', $eventid);
And then, in the form:
$form->create('Reservation',array('url' => array($event_id)));
It works, but it strikes me as a bit ugly. Isn't there an easier way to make sure the form POST action gets made to the current url, instead of the url without the id?
Nik's answer will fail if the website isn't in the server public_html root.
This answer is more solid:
<?php echo $form->create('Reservation',array('url'=>'/reservation/add/'.$data['id']));?>
Following the strictest convention for just a moment, reading a URL like /reservations/add/3 would be, well, confusing. You're calling on the ReservationsController to act on the Reservation model, but passing it an event ID. Calling /reservations/edit/3 is far less confusing, but just as wrong for your situation since the id value, "3", would be assumed to be a reservation identifier.
Essentially, you're making an ambiguous request at best. This is a simple form to create a reservation and that reservation has to be associated with an event. In a "traditional" scenario, the form would allow the user to select an event from some kind of list. After all, the foreign key, probably event_id in this case, is really just another property of a reservation. The list would have to be populated in the controller; this is usually done via a find( 'list' ) call.
If you already know the event that you want to create the reservation against (which you apparently do), then I'd probably select the analogous method of using a hidden field in the form. You still have to set the value in the controller just as you're doing, but the end result is a bit more Cake-y. The hidden field would be named data[Reservation][event_id] (again, I'm assuming the name of your foreign key field).
$form->create('Reservation',array('action' => 'add',$eventId);
and in the controller:
function add($eventId = null)
{
if($eventId == null)
{
// error state
throw new NotFoundException('Invalid id');
}
...
}
I do it all the time.
You can do following:
$form->create('Reservation',array('url' => $this->Html->url()));
this way all your variables from the url will be added in the form action :)
As Rob Wilkerson suggests, the issue is your URL route doesn't accurately describe the operation being performed. It becomes further confusing when you want to edit the reservation: /reservations/edit/6. Now the number in the URL means something different.
The URL convention I use for situations like these (adapted to your particular case) is /events/3/reservations/add. It takes a bit more up-front to configure your routes, but I've found it's superior for clarity down the road.
Sample routes.php:
Router::connect(
'/events/:event_id/reservations/:action',
array('controller'=>'reservations','action'=>'index'),
array(
'pass' => array('event_id'), // pass the event_id as a param to the action
'event_id' => '[0-9]+',
'actions'=>'add|index' // only reverse-routes with 'action'=>'add' or
// 'action'=>'index' will match this route
)
)
// Usage: array('controller'=>'reservations','action'=>'add','event_id'=>3)
Router::connect(
'/events/:event_id/reservations/:id/:action',
array('controller'=>'reservations'),
array(
'pass' => array('id'), // pass the reservation id as a param to the action
'id' => '[0-9]+',
'event_id' => '[0-9]+',
'actions'=>'edit|delete' // only reverse-routes with 'action'=>'edit' or
// 'action'=>'delete' will match this route
)
)
// Usage: array('controller'=>'reservations','action'=>'edit','event_id'=>3,'id'=>6)
In your FormHelper::create call, you'd have to specify most of the reverse-route you want to follow, but again, the up-front cost will pay dividends in the future. It's usually better to be explicit with Cake than to hope its automagic always works correctly, especially as the complexity of your application increases.

Categories