yii2 强制路由路由
Almost all modern web apps have 3 major concerns: Retrieving data from a database easily and effectively, caching the web content and URL rewriting to create user friendly URLs. Yii, like any other good framework, offers simple and easy solutions to all of the above. In my previous article I covered the basics of building a simple CRUD app with Yii. In this tutorial we will look at how Yii greatly simplifies the development of database driven websites with its Active Record support. Additonally, Yii lets you further improve your websites by implementing user friendly URLs and powerful caching techniques. Let's dive in!
几乎所有现代Web应用程序都具有3个主要问题:轻松有效地从数据库检索数据,缓存Web内容和URL重写以创建用户友好的URL。 与其他任何好的框架一样,Yii为上述所有问题提供了简单的解决方案。 在上一篇文章中,我介绍了使用Yii构建简单的CRUD应用程序的基础知识。 在本教程中,我们将了解Yii如何通过Active Record支持大大简化数据库驱动网站的开发。 此外,Yii允许您通过实现用户友好的URL和强大的缓存技术来进一步改善网站。 让我们潜入吧!
We will be creating a very simple web app for storing and retrieving details about different smartphones using Yii.
我们将创建一个非常简单的Web应用程序,用于使用Yii存储和检索有关不同智能手机的详细信息。
To create a skeleton Yii application we will use the command line tool yiic
that ships with Yii framework. You can find it under YiiRoot/framework
directory. As I am on windows it's under C:\yii\framework
. I recommend adding this directory to your system path so that you can run yiic
from any folder. If you are on Windows you also need to add the path to php.exe
to your system path.
为了创建一个框架Yii应用程序,我们将使用Yii框架附带的命令行工具yiic
。 您可以在YiiRoot/framework
目录下找到它。 当我在Windows上时,它位于C:\yii\framework
。 我建议将此目录添加到系统路径,以便您可以从任何文件夹运行yiic
。 如果您使用的是Windows,则还需要将php.exe
的路径添加到系统路径。
Just go to the folder where you keep all your PHP projects (I'm on Windows, so it's C:\wamp\www in my case), then run the command: yiic webapp project_name_here
. I am naming the project as gadgetstore. That should create a new Yii project with the necessary folder hierarchy.
只需转到保存所有PHP项目的文件夹(我在Windows上,在我的情况下为C:\ wamp \ www),然后运行命令: yiic webapp project_name_here
。 我将项目命名为gadgetstore 。 这将创建一个具有必要文件夹层次结构的新Yii项目。
By default, the Yii actions defined inside the controllers are accessed in the following way:
默认情况下,通过以下方式访问控制器内部定义的Yii操作:
http://localhost/gadgetstore/index.php?r=controller/action
http://localhost/gadgetstore/index.php?r=controller/action
Since we want to be user friendly, we don't want this type of URL. To change this, open the config file i.e. main.php
and uncomment the following lines:
由于我们希望对用户友好,所以我们不需要这种类型的URL。 要更改此设置,请打开配置文件即main.php
并取消注释以下几行:
'urlManager'=>array(
'urlFormat'=>'path',
'rules'=>array(
'/'=>'/view',
'//'=>'/', '/'=>'/',
),
),
Add 'showScriptName'=>false
after line 2 to suppress the annoying index.php
from the URL. Also don't forget to add a .htaccess
file with the following content to the root of your project:
在第2行之后添加'showScriptName'=>false
,以从URL中'showScriptName'=>false
烦人的index.php
。 同样不要忘记将具有以下内容的.htaccess
文件添加到项目的根目录:
Options +FollowSymLinks
IndexIgnore */*
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index.php
Now, the URLs can be accessed in a much simpler way:
现在,可以以更简单的方式访问URL:
http://localhost/gadgetstore/controller/action
http://localhost/gadgetstore/controller/action
Configuring your app to use a database is a matter of adding a couple of lines to your configuration. Just open up your /protected/config/main.php
file and uncomment the following lines:
配置您的应用程序以使用数据库是在配置中添加几行的问题。 只需打开/protected/config/main.php
文件,然后取消注释以下几行:
'db'=>array(
'connectionString' =>'mysql:host=localhost;dbname=testdb',
'emulatePrepare' => true,
'username' => 'root',
'password' => '',
'charset' => 'utf8',
),
Here we are essentially configuring our app to use a particular MySQL or MariaDB database. In my case, the database name is testdb
. Change the dbname in the above snippet accordingly. The rest of the details are self explanatory.
在这里,我们实际上是在配置我们的应用程序以使用特定MySQL或MariaDB数据库。 在我的情况下,数据库名称为testdb
。 相应地更改上述片段中的dbname。 其余细节不言自明。
Now let's quickly set up a database table that will contain information about our amazing gadgets.
现在,让我们快速设置一个数据库表,其中将包含有关我们惊人的小工具的信息。
The table structure is as follows:
表结构如下:
Table Name: phone
Column Type
id int(10)
name varchar(65)
price int(6)
memory varchar(65)
camera varchar(65)
screen_size varchar(65)
os varchar(65)
For the time being we will just keep 5 simple attributes that are common to all smartphones i.e. price, memory, camera, screen_size and os.
目前,我们将仅保留所有智能手机共有的5个简单属性,即价格,内存,相机,screen_size和os。
Now, the next step is to create the Active Record class that will hold the attributes of a smartphone. Each AR class corresponds to a database table and each AR instance represents a single row in that table. Now let's create an AR class called Phone. To generate this class we will use gii, the automatic code generation tool that ships with Yii. Open up: http://localhost/gadgetstore/gii
in your browser and go to the model generator. Provide the table name (in my case phone
) and type Phone in the model class field. Have a look at the following screenshot.
现在,下一步是创建Active Record类,该类将保存智能手机的属性。 每个AR类对应一个数据库表,每个AR实例代表该表中的一行。 现在让我们创建一个名为Phone的AR类。 为了生成此类,我们将使用Yii随附的自动代码生成工具gii。 在浏览器中打开: http://localhost/gadgetstore/gii
并转到模型生成器。 提供表名(在我的情况下为phone
),然后在模型类字段中输入Phone。 看下面的截图。
Now hit preview and click on generate to create the model class. You can find it inside the protected/models
directory.
现在点击预览,然后单击生成以创建模型类。 您可以在protected/models
目录中找到它。
As the AR class is generated you can instantiate it anywhere and access the database table attributes as the properties of the AR instance. This is achieved through the __get()
magic method. For example, it's perfectly legal to do the following:
生成AR类后,您可以在任何地方实例化它,并访问数据库表属性作为AR实例的属性。 这是通过__get()
魔术方法实现的。 例如,执行以下操作是完全合法的:
$model=new Phone; //creates new model instance
$model->name="Samsung Galaxy Note 3"; //sets name property
$model->price=299; //sets price property
$model->os="Android 4.3"; //sets os property
Now to save the model all you need to do is call save() on it.
现在要保存模型,您只需在其上调用save()即可。
$model->save(); //saves the phone to the database.
Updating an existing row is also very simple.
更新现有行也非常简单。
$model=Phone::model()->findByPK(10); //phone with id 10
$model->price=300;
$model->save(); //save the updates in DB.
To Delete a row:
删除行:
$model=Phone::model()->findByPK(10);
$model->delete(); //gone from the table
Active Record basically offers an easy way to perform CRUD operations that often involve simple SQL commands. For complex queries you might want to switch to Yii DAO.
Active Record基本上提供了一种执行CRUD操作的简便方法,该操作通常涉及简单SQL命令。 对于复杂的查询,您可能需要切换到Yii DAO 。
Just a small change is needed in the generated model. Open up model class Phone and find the following line in the rules()
function:
生成的模型只需要进行很小的更改。 打开模型类Phone,然后在rules()
函数中找到以下行:
array('id, name, price, memory, camera, screen_size, os', 'safe', 'on'=>'search')
Now replace search
with insert
in the above line. Why we did this will become clear in the subsequent sections.
现在,在上面的行中用insert
替换search
。 我们为什么这样做,将在随后的部分中明确说明。
Now that you have the AR ready we need to create a controller that will actually do the insertion/update (also called upsert) in the database using the AR class. Just create a file PhoneController.php
inside protected/controllers. Inside the file create an empty class PhoneController.
现在您已经准备好AR,我们需要创建一个控制器,该控制器实际上将使用AR类在数据库中进行插入/更新(也称为upsert)。 只需在protected / controllers中创建一个文件PhoneController.php
。 在文件内部创建一个空类PhoneController。
class PhoneController extends Controller{
}
Now let's add a function actionAdd()
to the class which looks like following:
现在,向类添加一个函数actionAdd()
,如下所示:
public function actionAdd(){
$model=new Phone;
if(isset($_POST['Phone'])) //line 3
{
$model->attributes=$_POST['Phone']; //line 5
if($model->validate()){
$model->save();
$this->redirect("view/$model->id"); //line 6
}
}
$this->render('add',array('model'=>$model));
}
In this function we are adding a new row to the table. But prior to this we need to create a view file that shows a form through which one can enter various attribute values of the phone. The form can be generated very easily through gii's form generator. You can open up gii in your browser and go to the form generator. Just enter the name of the model (Phone) and name of the view (in this case phone/add) and click generate. It will create a view file add.php
inside protected/views/phone
.
在此函数中,我们向表添加了新行。 但是在此之前,我们需要创建一个显示文件的视图文件,通过该文件可以输入电话的各种属性值。 通过gii的表单生成器可以很容易地生成表单。 您可以在浏览器中打开gii,然后转到表单生成器。 只需输入模型名称(电话)和视图名称(在本例中为电话/添加),然后单击生成。 它将在protected/views/phone
创建一个视图文件add.php
。
In the above snippet first we check if the request is POST. If not then we simply show the form where the user can enter values. But if it's a post back we need to store the data in table. To capture the incoming data we do the following:
在上面的代码段中,我们首先检查请求是否为POST。 如果不是,那么我们仅显示表单,用户可以在其中输入值。 但是,如果要回发,则需要将数据存储在表中。 为了捕获传入的数据,我们执行以下操作:
$model->attributes=$_POST['Phone'];
The above operation is known as massive assignment. Here all the properties of model are given values that are received in the request. Remember how we changed the scenario from search to insert inside the Phone
class earlier? It's because of this massive assignment. Whenever we are instantiating new model the scenario is insert. So, if we declare the attributes safe only for the search scenario, this massive assignment will fail. That's the reason we declared the attributes of Phone
as safe for insertion.
以上操作称为大规模分配。 在这里,模型的所有属性都被赋予在请求中接收的值。 还记得我们是如何将方案从搜索更改为之前插入Phone
类的吗? 这是因为这项艰巨的任务。 每当我们实例化新模型时,场景就是插入。 因此,如果我们声明属性仅对于搜索方案而言是安全的,那么这种大量分配将失败。 这就是我们将Phone
的属性声明为可安全插入的原因。
Next, we check if there are validation errors, and if there are none, we proceed to save the model. The user is then redirected to a URL where he can see the added smartphone. The update and view functionality are implemented in a similar fashion.
接下来,我们检查是否存在验证错误,如果没有,则继续保存模型。 然后,用户被重定向到一个URL,在此他可以看到添加的智能手机。 更新和查看功能以类似的方式实现。
Just a quick note: you can download the demo app and check out the source code. There you can see how the additional functions and views for PhoneController are implemented.
简要说明:您可以下载演示应用程序并签出源代码。 在那里,您可以看到如何实现PhoneController的附加功能和视图。
Currently our URL for viewing a newly added smartphone uses this format:
目前,我们用于查看新添加的智能手机的URL使用以下格式:
http://localhost/gadgetstore/phone/view/[id]
But how about making it a bit more attractive? Maybe we can impress our users by showing them the name of the smartphone in the URL? Something like http://localhost/gadgetstore/phones/samsung-galaxy-s4
perhaps?
但是如何使其更具吸引力呢? 也许我们可以通过在URL中向用户显示智能手机的名称来打动我们的用户? 像http://localhost/gadgetstore/phones/samsung-galaxy-s4
?
To implement this type of URL just add the following line to the urlManager rules in protected/config/main.php
.
要实现这种类型的URL,只需将以下行添加到protected/config/main.php
的urlManager规则中。
'phones/'=>'phone/show'
Together, all the rules are as follows:
在一起,所有规则如下:
'urlManager'=>array(
'urlFormat'=>'path',
'showScriptName'=>false,
'rules'=>array(
'phones/'=>'phone/show', //rule 1
'/'=>'/view',
'//'=>'/',
'/'=>'/',
),
),
What rule 1 means is any url that starts with 'phones/' should be handled by the actionShow() function of PhoneController class. Additionally, the part after 'phones/' will be passed as a GET request parameter called 'name' to the actionShow()
function. By doing this we can capture the request param and utilize it to find the required smartphone by name!
规则1的意思是任何以“ phones /”开头的网址都应由PhoneController类的actionShow()函数处理。 此外,“ phones /”之后的部分将作为名为“ name”的GET请求参数传递给actionShow()
函数。 通过这样做,我们可以捕获请求参数并利用它来按名称查找所需的智能手机!
The actionShow()
function is implemented as follows:
actionShow()
函数的实现如下:
public function actionShow(){
if(isset($_GET['name'])){
$name=$_GET['name'];
$name=implode(' ',explode('-',$name));
$phone=Phone::model()- >find('name=:name',array(':name'=>$name));
if($phone==null)
throw new CHttpException(404,'Page Not Found');
$this->render('view',array('phone'=>$phone));
}
else
throw new CHttpException(404,'Page Not Found');
}
Remember Yii's URL management is pretty vast and you can create really impressive URL patterns with it. This was just a basic tutorial showing a subset of what the URL management module is capable of.
请记住,Yii的URL管理非常广泛,您可以使用它创建令人印象深刻的URL模式。 这只是基础教程,显示了URL管理模块功能的一部分。
Also, please note that while selecting entries by name is perfectly legit, you should always select them by unique slugs (URL-optimized strings), just in case some entries have the same name. This is done by generating a unique name-based slug on every insertion. For example, if Samsung Galaxy S4 was inserted, the slug might be samsung-galaxy-s4
. However, if another Samsung Galaxy S4 model appears, the new slug should be something like samsung-galaxy-s4-01
, just to be different from the first one.
另外,请注意,虽然按名称选择条目是完全合法的,但应始终使用唯一的段(URL优化的字符串)选择它们,以防万一某些条目具有相同的名称。 这是通过在每次插入时生成唯一的基于名称的段来完成的。 例如,如果插入了Samsung Galaxy S4,则该子弹可能是samsung-galaxy-s4
。 但是,如果出现另一款三星Galaxy S4机型,则新弹头应类似于samsung-galaxy-s4-01
,与第一款samsung-galaxy-s4-01
有所不同。
Yii's caching implementation has many types. In the most simple scenarios we might get our task done through query caching.
Yii的缓存实现有很多类型。 在最简单的情况下,我们可以通过查询缓存来完成我们的任务。
While using Active Record we can specify to put the retrieved data into cache and subsequently use the cache instead of hitting the database. In our app, query caching can be achieved through the following snippet:
在使用Active Record时,我们可以指定将检索到的数据放入缓存中,然后使用缓存而不是访问数据库。 在我们的应用中,查询缓存可以通过以下代码段实现:
$phones=Phone::model()->cache(2000,null,2)->findAll();
The above code retrieves the data from the DB and adds it to the cache. The first parameter specifies how many seconds the cache will live. The second parameter is the dependency which is null in our case. The third parameter denotes the number of subsequent queries to cache. As we have specified 2 as 3rd argument the next 2 queries will be cached. So, the next two times a request comes, the cache will be searched for the content instead hitting the database. This clearly improves the performance if you are getting too many requests per second.
上面的代码从数据库中检索数据并将其添加到缓存中。 第一个参数指定缓存将生存多少秒。 第二个参数是依赖关系,在我们的例子中为空。 第三个参数表示要缓存的后续查询数。 由于我们将2指定为第3个参数,因此接下来的2个查询将被缓存。 因此,在接下来的两次请求到来时,将在缓存中搜索内容,而不是访问数据库。 如果您每秒收到太多请求,这显然会提高性能。
There are other, advanced, types of caching, but outside the scope of this article. If you'd like them covered in more detail, let us know in the comments below.
还有其他高级缓存类型,但不在本文讨论范围之内。 如果您想更详细地介绍它们,请在下面的评论中告诉我们。
The abilities of the above discussed modules are really vast. As it was not possible to cover all the aspects in a single tutorial, some points were left out. So, aside from letting us know what you'd like to read more about, here are the top 3 things you should start reading after this tutorial.
上面讨论的模块的功能确实非常广泛。 由于不可能在一个教程中涵盖所有方面,因此省略了一些要点。 因此,除了让我们知道您想了解的更多信息之外,还有本教程之后您应该开始阅读的三件事。
Yii's AR offers a very nice API to select data from the database in different ways. You can find data by attributes, primary keys and your own search conditions. Just head over to the above link to know more about it.
Yii的AR提供了一个非常不错的API,可以以不同的方式从数据库中选择数据。 您可以按属性,主键和您自己的搜索条件查找数据。 只需转到上面的链接即可了解更多信息。
You should start reading about how to use different patterns in your URL rules inside the config file. This gives you the power to create impressive URLs in your apps. Apart from that it's also useful to create your own URL rule class.
您应该开始阅读如何在配置文件中的URL规则中使用不同的模式 。 这使您能够在应用程序中创建令人印象深刻的URL。 除此之外,创建自己的URL规则类也很有用。
Query caching is not the only caching mechanism available in Yii. There are several other implementations too. The Yii documentation has an excellent tutorial regarding caching with Yii.
查询缓存不是Yii中唯一可用的缓存机制。 也有其他几种实现。 Yii文档提供了有关使用Yii进行缓存的出色教程。
Thank you for reading, and don't forget to check out the source code for more info!
感谢您的阅读,不要忘记查看源代码以获取更多信息!
翻译自: https://www.sitepoint.com/yii-routing-active-record-caching/
yii2 强制路由路由