Custom Query Parameters without Appending Them to URL - mod-rewrite

I have 'urlFormat'=>'path' and 'showScriptName'=>false in the urlManager.
I have proxies/read as controller/action and article=>some_name as parameters.
Whenever I create a link such as:
$this->createUrl('proxies/read', array('article'=>$name));
The result is an URL of the type:
proxies/read?article=socks5_proxy_list
I would like to dump the query parameter and reformat the URL to look like this:
controller/action/param_name/param_value
In this case that would be:
proxies/read/article/socks5_proxy_list
My current 'rules' look like this:
'rules'=>array(
'<controller:\w+>/<id:\d+>'=>'<controller>/view',
'<controller:\w+>/<action:\w+>/<id:\d+>'=>'<controller>/<action>',
'<controller:\w+>/<action:\w+>/article/<article:\w+>'=>'<controller>/<action>/article/<article>',
'<controller:\w+>/<action:\w+>'=>'<controller>/<action>',
),
But they don't seem to be working.

Shortcut to make this work:
$this->createUrl('proxies/read/article/'.$name);
And leave the urlManager rules without your custom rule.
Another way:
// urlManager
'rules'=>array(// order of rules is also important
'<controller:\w+>/<action:\w+>/article/<article:\w+>'=>'<controller>/<action>',
'<controller:\w+>/<id:\d+>'=>'<controller>/view',
'<controller:\w+>/<action:\w+>/<id:\d+>'=>'<controller>/<action>',
'<controller:\w+>/<action:\w+>'=>'<controller>/<action>',
),
In the above array, i just put the new rule in the beginning, to make sure that, that rule is applied whenever such a pattern is encountered. If you have other rules, then just make sure that this rule appears before a more general rule, that can match the pattern. Rule of thumb: more specific rule should appear before general rule.
create url in view:
$this->createUrl('proxies/read', array('article'=>$name));
Incase you don't need any of the default "user-friendly url" rules, but only need path format urls, then you only need to specify 'urlFormat'=>'path' and leave the 'rules' array empty or omitted all together.
Read the URL Management guide in the definitive guide, if you haven't already.

no need for rules..
http://yourhost.com/mycontroller/dosomething/param1/value/param2/value
class MyController extends Controller {
public function actionDosomething($param1, $param2) {
}
}
as for createUrl(). hand it a key=>value array of parameters as a second parameter
http://www.yiiframework.com/doc/api/1.1/CController#createUrl-detail

try these set of rules
'rules'=>array(
'<controller:\w+>/<id:\d+>'=>'<controller>/view',
'<controller:\w+>/<action:\w+>/<id:\d+>'=>'<controller>/<action>',
'<controller:\w+>/<action:\w+>/*'=>'<controller>/<action>',
),

Related

Construct routes(urls) with slugs separated by dash in laravel

I am about to make more SEO-friendly URLs on my page and want a pattern looking like this for my products:
www.example.com/product-category/a-pretty-long-seo-friendly-product-name-12
So what are we looking at here?
www.example.com/{slug1}/{slug2}-{id}
The only thing I will care about from the URL in my controller is the {id}. The rest two slugs are just of SEO purpose. So to my question. How can I get the 12 from a-pretty-long-seo-friendly-product-name-12?
I have tried www.mydomain.com/{slug}/{slug}-{id} and in my controller to try and get $id. Id does not work. I am not able to able to separate it from from a-pretty-long-seo-friendly-product-name. So in my controller no matter how I do I get {slug2} and {id} concatenated.
Coming from rails it is a piece of cake there but can't seem to figure out how to do that here in laravel.
EDIT:
I am sorry I formulated my question very unclear. I am looking for a way to do this in the routes file. Like in rails.
You're on the right track, but you can't really logically separate /{slug}-{id} if you're using dash-separated strings. To handle this, you can simply explode the chunks and select the last one:
// routes/web.php
Route::get('/{primarySlug}/{secondarySlugAndId}', [ExampleController::class, 'example']);
// ExampleController.php
public function example($primarySlug, $secondarySlugAndId){
$parts = collect(explode('-', $secondarySlugAndId));
$id = $parts->last();
$secondarySlug = $parts->slice(0, -1)->implode('-');
... // Do anything else you need to do
}
Given the URL example.com/primary-slug/secondary-slug-99, you would have the following variables:
dd($primarySlug, $secondarySlug, $id);
// "primary-slug"
// "secondary-slug"
// "99"
The only case this wouldn't work for is if your id had a dash in it, but that's another layer of complexity that I hope you don't have to handle.
Route::get('/test/{slug1}/{slug2}','IndexController#index');
public function index($slug1, $slug2)
{
$id_slug = last(explode('-',$slug2));
$second_slug = str_replace('-'.$id_slug,'',$slug2);
dd($slug1, $second_slug,$id_slug);
}

Wildcard Prefix Laravel 5

is there a way in Laravel 5 to have a recognized list of prefixes, such as ['gbr','en','eu'], so that
/gbr/bar/baz/shoelace // or
/eu/bar/baz/shoelace
is handled by the same controller#method as
/bar/baz/shoelace
Except that the additional parameter foo=gbr is passed in the first condition?
Note the Route::group prefix won't work because there may or may not be a prefix in this case. Also, this strategy should take precedence over all else, i.e. the Route would check for the (optional) prefix first.
Yes there is a way.
When declaring your routes, you can declare them as
Route::get('{prefix}/bar/baz/shoelace', 'controller#method')->where('prefix', 'gbr|en|eu');
gbr|en|eu is a simple regular expression that will match either the string gbr, en or eu. Check out Regular expression constraints for more details
And in your controller you can have
public function method($prefix) {
//code here
}

Laravel pass parameters to route/action

If I want to construct this url: /categories/5/update/?hidden=1 how could I pass both {id} param and hidden param (as GET) ?
My route is:
Route::get('categories/{id}/update', 'CategoryController#update');
I don't want to make a form and put it as POST because I have a number of buttons which simply hides/shows/removes a category and dont want to make a lot of forms for simple actions, although it has nothing to do with the question
I'm just a little bit confused, because it seems like action('CategoryController#update', [$id, 'hidden' => 1]) constructs the right URL but I got no idea how it's distinguished that the first one ($id) must be in URL and the second is a GET param
You may also try this to generate the URL:
$action = action('CategoryController#update', [id => $id]) . '?hidden=1';
Also, query string could be passed with any route even without mentioning about that in Route declaration.

How do I combine CatchAll and EndsWith in an MVC route?

The following route will match any folder structure below BasePath:
http://BasePath/{*SomeFolders}/
How do I create another route which will match any zip file below the same BasePath structure?
I tried this...
http://BasePath/{*SomeFolders}/{ZipFile}
... but it errors with
A path segment that contains more than one section, such as a literal section or a parameter, cannot contain a catch-all parameter.
Parameter name: routeUrl
How should I approach this?
*Update*
The original requirements are in fact flawed.
{ZipFile} will match the final section regardless of what it contains. (File or Folder)
In reality I believe the route pattern I'm looking to match should be:
http://BasePath/{*SomeFolders}/{ZipFile}.zip
It seems that constraints are the answer here.
routes.MapRoute( _
"ViewFile", "BasePath/{*RestOfPath}", _
New With {.controller = "File", .action = "DownloadFile"}, _
New With {.RestOfPath = ".*\.zip"}
)
routes.MapRoute( _
"ViewFolder", "BasePath/{*RestOfPath}", _
New With {.controller = "Folder", .action = "ViewFolder"} _
)
or for those of you who prefer C#...
routes.MapRoute(
"ViewFile", "BasePath/{*RestOfPath}",
new {controller = "File", action = "DownloadFile"},
new {RestOfPath = #".*\.zip"}
);
routes.MapRoute(
"ViewFolder", "BasePath/{*RestOfPath}",
new {controller = "Folder", action = "ViewFolder"}
);
(Erm I think that's right)
The same route is registered twice, with the first variation being given the additional constraint that the RestOfPath parameter should end with ".zip"
I am given to understand that Custom Constraints are also possible using derivatives of IRouteConstraint.
Catch all anywhere in the URL - exactly what you need
I've written such Route class that allows you to do exactly what you describe. It allows you to put catch-all segment as the first one in the route definition (or anywhere else actually). It will allow you to define your route as:
"BasePath/{*SomeFolders}/{ZipFile}"
The whole thing is described into great detail on my blog post where you will find the code to this Route class.
Additional info
Based on added info I would still rather use the first route definition that doesn't exclude file extension out of the route segment parameter but rather add constraint for the last segment to be
"[a-zA-Z0-9_]+\.zip"
So routing should still be defined as stated above in my answer, but contraint for the ZipFile should be defined as previously written. This would make my special route work out of the box as it is now.
To also make it work for other route delimiters (like dot in your example) code should be changed considerably, but if you know routing very well how it works, you can change it to work that way.
But I'd rather suggest you keep it simple and add a constraint.
As the error says, your catchall has to be the last param in your route.
To get the ZipFile part out, you will have to parse it from the SomeFolders catchall:
public ActionResult MyAction(string SomeFolders)
{
// parse the ZipFile out from the SomeFolders argument
}
So if you have /folder1/folder2/folder3/file.zip, you can do this:
var zipFile = SomeFolders.SubString(SomeFolders.LastIndexOf("/") + 1);

Mutliple URL Segments to Index Function With CodeIgniter

Please excuse me if this is an incredibly stupid question, as I'm new to CodeIgniter.
I have a controller for my verification system called Verify. I'd like to be able to use it something like site.com/verify/123/abcd, but I only want to use the index function, so both URL segments need to go to it.
I'm sure this can be done with URL routing somehow, but I can't figure out how to pass both URL segments into Verify's index function..
Something like this in routes.php should do the job:
$route['verify/(:any)/(:any)'] = "verify/index/$1/$2";
I'm pretty sure you can just pass any controller method in CodeIgniter multiple arguments without modifying routes or .htaccess unless I misunderstood the problem.
function index($arg_one, $arg_two)
{
}
$arg_one representing the 123 and $arg_two representing the abcd in your example URI.
You will either need to edit the routes or write an htaccess rule, however i didn't understand why you want to limit to just the index function.
If you didnt wanna use routes for some reason, then you could add this function to the controller in question.
public function _remap($method_in, $params = array()) {
$method = 'process_'.$method_in;
if (method_exists($this, $method)) {
return call_user_func_array(array($this, $method), $params);
}
array_unshift($params, $method_in);
$this->index($params);
}
Basically it does the same as default behavior in CI, except instead of sending a 404 on 'cant find method', it sends unfound method calls to the index.
You would need to alter your index function to take an array as the first argument.
OR if you know that you only ever want 2 arguments, you could change the last 2 lines to
$this->index($method_in, $params[0]);
Of course both solutions fail in someone uses an argument which is the same as a method in your controller.

Resources