I'm new in Yii2 so I have Brands table with their types ('brand', 'author', 'company') and their slug name so I need the URL like that www.site.com/{brand_type}/{brand_slug} without controller name so how to do that ?
This is commonly called pretty URLs. To do achieve that in Yii2 put this in your app config file under 'components' key
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'rules' => [
// ...
'<type:\w+>/slug:\w+>' => 'yourcontroller/youraction',
// ...
],
],
The result is that when you passed a URL in the format you specified, your controller will $type and $slug as parameters you can use in your controller which is expected to take the form:
class YourcontrollerController extends YourBaseController
{
...
public function actionYouraction($type, $slug)
{
// Do whatever you want with these variables
}
...
}
Notice that you will need your web server to configure executing your app's index.php even if it is not in the URL. For Apache this can be done, for example, using .httaccess (More details here) :
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index.php
The Definitive Guide to Yii 2.0 has an excellent section about this topic
Related
I need to do an url address that looks like website/user/username where username is coming from database. I've tried to reach it by placing a $user variable in my action function as a parameter and result looks like this website/action?user=username. But it looks kind of hinty and ugly. How can I get a desirable result?
First you need to configure url rules in config/web.php.
[
'components' => [
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'enableStrictParsing' => false,
'rules' => [
"user/<username:\w+>"=> "controller/action"
],
],
],
]
And add url match condition in rules array like
"user/<username:\w+>"=> "controller/action"
Create. htaccess file with below url condition in web folder
RewriteEngine on
# If a directory or a file exists, use it directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# Otherwise forward it to index.php
RewriteRule . index.php
And generate urls with Url helper class or Html class like below
echo Url::to(['controller/action', 'username' => 'jack']);
Or
echo Html::a('Profile', ['controller/action', 'username' => 'jack'], ['class' => 'profile-link'])
Note:- controller name, action name and username should match with Url condition. Which we define in rules array.
I've created a module named catalogue with, for the moment, two actions in the default controller:
actionIndex
actionLineProducts
in the index view I have some link which run the line-product's action, the url was the result of:
Url::to(['line-products', 'line' => $line->name])
my goal is to obtain a link like
catalogue/{line-name}
where line-name is the parameter I send to action LineProducts.
My urlManager configurations are:
'enablePrettyUrl' => true,
'showScriptName' => false,
'rules' => [
'<moduls:catalogue>/<controller:default>/<action:line-products>/<line:*>' => '<module>/<line>',
'<controller:\w+>/<id:\d+>' => '<controller>/view/',
'<controller:\w+>/<action:\w+>/<id:\d+>' => '<controller>/<action>',
'<controller:\w+>/<action:\w+>' => '<controller>/<action>',
],
.htaccess configurations:
RewriteEngine on
# If a directory or a file exists, use it directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# Otherwise forward it to index.php
RewriteRule . index.php
Can anyone explain me why my URL is always like:
http://my-site.dev/catalogue/default/line-products?line={line-name}
You swapped the configuration. The key is the pattern of the url as passed from the browser. The value is the route. Since you are using a specific module, controller and action you can pass those in directly:
'rules' => [
'catalogue/<line>' => 'catalogue/default/line-products'
...
]
You can read the Routing and Url Creation page in the Yii2 guide for more information.
I need a little help(I am not a pro),
My .htaccess file looks like this:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/]+)$ url.php?p1=$1 [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/]+)/([^/]+)$ url.php?p1=$1&p2=$2 [L]
and I would like to display the content on the basis of number of parameters (on the basis of type(in future))
What I wish to know is
$p1 = $_GET['p1'];
$p2 = $_GET['p2'];
if p2 = ""
{
echo "something";
}
else
{
echo "something";
}
Will the above code work without any issue?
What all errors can occur?
Is there a better way to handle this?
How wordpress handles this?
Note: I wish to display the contents on the basis of more than 3 params and type of params as well.
Generally speaking this isn't the greatest way to go about it. It's better to use a router which basically uses a single htaccess rule to catch all requests where a file/folder doesn't exist and then send them to a single php file. That file then initializes the router which figures out what the parameters are based on patterns matched against the request URI.
For example using the symfony/routing component in index.php:
// this is our index.php
// assuming we installed with composer
// and that the vendor dir is one level up from the document root
require_once __DIR__.'/../vendor/autoload.php';
use Symfony\Component\Routing\Matcher\UrlMatcher;
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Route;
// Create a Route Collection
$routes = new RouteCollection();
// lets use an array to define our routes
$routeDefinitions = array(
'foo_archive' => array(
// note the {} wraped parts are params
'path' => '/foo/{p1}/{p2}',
'defaults' => array('controller' => 'foo/archive.php'),
'requirements' => array(
// not a very specific match but lets pretend this matches a
// category or something
'p1'=> '[a-z0-9-_]+',
// matches a date
'p2'=> '[0-9]{4}-[0-9]{2}-[0-9]{2}',
)
// there are other things we can add like options, a requrired host,
// or a specific HTTP mehtod (PUT, GET, POST, etc.)
),
'foo_index' => array(
'path' => '/foo',
'defaults' => array('controller' => 'foo/index.php')
);
);
// let's add our routes
$routeReflector = new \ReflectionClass('Symfony\Component\Routing\Route');
foreach ($routeDefinitions as $name => $def) {
$routes->add($name, $routeReflector->newInstanceArgs($def));
}
$context = new RequestContext($_SERVER['REQUEST_URI']);
$matcher = new UrlMatcher($routes, $context);
$parameters = $matcher->match($_SERVER['PATH_INFO']);
/* so assuming PATH_INFO matched one of our patterns and its
requirements parameters will be an array -
lets pretend PATH_INFO had: /foo/bar/2014-04-20
so we would have an array like:
array(
'controller' => 'archive.php',
'_route' => 'foo_archive',
'p1' => 'bar',
'p2' => '2014-04-20'
)
*/
$controllersDir = realpath(__DIR__ . '/controllers');
$controller = $controllersDir . '/' . $parameters['controller'];
if (file_exists($controller) {
// include our controller and let it do its work
// note that normally you would be instantiating a controller object
// here and invoking some method on it, but for ease of example lets
// just assume it a normal php file with all the logic for the page
include($controller);
} else {
// generate a 500 or 404 error depending on how you want to handle
// it
}
And then your .htaccess would be something like:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php [QSA,L]
Alternatively, if you are open to it you could use a Microframework like Silex which would wire all this up for you and give an out of the box way to do things.
Silex Example (index.php):
// assuming we installed with Composer
// and that the vendor dir is one level up from the document root
require_once __DIR__.'/../vendor/autoload.php';
$app = new Silex\Application();
// you can define routes as closures like this but normally
// I prefer to use classes... You can look at the docs for
// how to do that: http://silex.sensiolabs.org/doc/usage.html#controllers-in-classes
$app->get('/foo/{p1}/{p2}', function($p1, $p2) use($app) {
// do whatever logic you need to do to render the page
});
$app->get('/foo}', function() use($app) {
// do whatever logic you need to do to render the page
});
$app->run();
I have the following url structures in my Yii2 application
http://127.0.0.1/frontend/web/index.php?r=site%2Flogin
http://127.0.0.1/frontend/web/index.php?r=site%2Fpage2
http://127.0.0.1/frontend/web/index.php?r=site%2Fsample
http://127.0.0.1/frontend/web/index.php?r=site%2Fsignup
How can I convert that URL to something like
http://127.0.0.1/login.php
http://127.0.0.1/page2.php
http://127.0.0.1/sample.php
http://127.0.0.1/signup.php
I should remove frontend/web/index.php?r=site%2F
I tried like and it didn't work
Options -Multiviews
RewriteEngine On
RewriteBase /
# Force search engines to use http://127.0.0.1/frontend/web/
RewriteCond %{HTTP_HOST} !^http://127\.0\.0\.1/frontend/web/$
RewriteRule ^(.*) http://127.0.0.1/frontend/web/$1 [R=301,L]
# Specify search friendly URLs
RewriteRule ^login\.php$ /index.php?r=site%2Flogin [L]
I also tried like and it didn't work too.
RewriteEngine on
RewriteRule ^frontend/web/index.php?r=site%2F([^\./]+) /$1.php [L]
No need to change .htaccess to achieve this. Adjust urlManager component.
Add this to your application config:
'components' => [
'urlManager' => [
'enablePrettyUrl' => true, // Cancel passing route in get 'r' paramater
'showScriptName' => false, // Remove index.php from url
'suffix' => '.php', // Add suffix to all routes (globally)
],
// Compare requested urls to routes
'rules' => [
'login' => 'site/login',
'page2' => 'site/page2',
'sample' => 'site/sample',
'signup' => 'site/signup',
],
],
As for removing controller part from all other routes - it violates key MVC concepts.
How you define to which controller requested action belongs in that case?
And what in case of actions with the same name?
For example: http://127.0.0.1/create.php - should it load site/create or users/create?
Also I don't sure if it's good practice, but you can write comparisons to all routes the same way with rules, but all action names should be unique.
Conclusion: you can modify urls to desired view as I mentioned above, but omitting controller names is only recommended for default controller (SiteController).
Official documentation:
UrlManager
$enablePrettyUrl
$showScriptName
$suffix
$rules
Routing and URL Creation
I have an yii advanced app with frontend and backend.
What I try to achieve is that I can access the frontend with the name of a customer.
Example (local): http://localhost/myproject/frontend/web/customer1 should become http://localhost/myproject/frontend/web/customer1/site/login at first visit
And after login the name of the customer should stay in the URL. At the moment the URL changes after login to http://localhost/myproject/frontend/web/
Info:
customer is a GET parameter. It should always be the first argument after http://localhost/myproject/frontend/web/ but I don't want to specify the argument in each redirect or custom link. I hope there's a way to keep this argument and pass it to each of the following site changes.
What I have tried so far:
'urlManager' => [
'class' => 'yii\web\UrlManager',
'enablePrettyUrl' => true,
'showScriptName' => false,
'enableStrictParsing' => true,
'rules' => [
'<controller>/<action>' => '<controller>/<action>',
'<customer:\w+>' => '/site/login',
]
],
But this is not working. I can only access the login page and afterwards the customer name is not showing anymore in the URL.
My .htaccess file looks like this:
RewriteEngine on
# If a directory or a file exists, use it directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# Otherwise forward it to index.php
RewriteRule . index.php
I'm really appreciate any hints on this topic.
To prepend customer name to all urls modify your url rule:
<customer:\w+>/<controller>/<action>' => '<controller>/<action>,
If you now call yii\helpers\Url::to(['site/index', 'customer' => 'customer'])the output will be as you want - /customer/site/index.
Howewer calling it like that in entire project is not flexible approach.
Most of the times Url::to() method is used for generating internal urls.
If you pass array in $route, it will call Url::toRoute(). So you can simply override that method in your custom component.
namespace frontend\components;
use yii\helpers\Url as BaseUrl;
class Url extends BaseUrl
{
public static function toRoute($route, $scheme = false)
{
$customer = ... // Get saved after login customer name (for example from the session)
$route['customer'] = $customer;
return parent::toRoute($route, $scheme);
}
}
Then you can simply call frontend\components\Url::to(['site/index']) to achieve the same result.
Alternative way of customizing helper classes described in official documentation here.
Update:
Also this url rule '<customer:\w+>' => '/site/login', is redundant and the url should be just site/login, because any user before signing in is guest.