Laravel是一个用于PHP的开源Web MVC框架。 Laravel是一个健壮的框架,可轻松开发PHP Web应用程序,其功能包括具有专用依赖性管理器的模块化打包系统,对关系数据库的访问以及用于应用程序部署和维护的其他实用程序。
Laravel由泰勒·奥特威尔(Taylor Otwell)创建。自2011年6月发布第一版(版本1)以来,它在Web开发行业的PHP框架领域稳步增长。这种受欢迎程度在很大程度上可以归因于库存随附的许多开发人员优先功能。
大约在2000年左右,大多数PHP代码都是程序性的,可以以“脚本”的形式找到,这些脚本可能会缠杂着意大利面条式的代码。即使是最简单的页面也没有关注点分离的问题,因此对于应用程序而言,迅速发展成为维护噩梦非常容易。世界需要更好的东西…进入PHP版本5和各种PHP框架,试图为各种Web应用程序问题带来一些急需的解决方案和更好的解决方案。
从那时起,我们已经看到了许多发布的框架,这些框架将为现存的和正在使用的流行框架铺平道路。今天,我们认为前三名是Zend Framework,Symfony,当然还有Laravel。尽管这些框架中的每个框架都基于相似的原理,并且旨在解决(基本)相同的常见问题,但是它们的主要区别在于它们的实现。他们每个人都对如何解决问题有自己的怪癖。当您查看它们各自产生的代码时,您会发现有一条漂亮的实线将它们彼此分开。以我们的拙见,Laravel框架是最好的。
了解有关Laravel和CodeIgniter之间的区别的更多信息
在此Laravel初学者教程中,您将学习Laravel基础知识,例如:
注意假定您已经在本地系统上安装了PHP的副本。如果没有,您可以在这里阅读如何安装
Composer既是程序包又是依赖项管理器。要安装它,请打开终端并cd进入新目录。运行以下命令:
curl -Ss getcomposer.org/installer | php
该命令的结果将如下所示:
注意有关设置Laravel的更多详细说明,请参阅此处的Laravel文档。
您将看到它下载并编译了composer.phar脚本,这是我们用来安装Laravel的脚本。 尽管可以通过多种方式来设置新的Laravel应用程序,但是我们将通过Laravel作曲家脚本来完成它。 要安装此脚本,请运行:
composer global require laravel/installer
看起来像这样:
这将下载并安装所有框架文件本身以及所需的所有依赖项。 软件包将保存在供应商目录中。 下载并安装后,就像发出以下命令一样简单:
laravel new uploadApp
您将看到类似以下输出的内容:
Composer正在安装Laravel运行所需的所有软件包。可能需要几分钟,所以请耐心等待。完成后,运行ls -al命令查看安装的内容。
以下是常见Laravel应用程序中目录的简要分类:
现在,让我们构建该应用程序的其余部分,并使用特殊的artisan命令运行它(以免安装和配置Web服务器(如Apache或nginx)的麻烦)。 .env文件包含/ config目录中的文件用于配置应用程序的所有配置值。在其中,您会注意到应用程序内部使用的各种参数的配置值。
在此在线Laravel教程中,我们将构建一个非常简单的应用程序,该应用程序只会做两件事:
对于此项目,我们的应用程序将是只写的,这意味着用户只能写文件并查看他们已上传的文件列表。该应用程序是非常基础的,但是应该作为您开始构建Laravel技能和知识的良好实践。请注意,为简洁起见,我已排除了任何数据库建模,迁移和身份验证,但是,在实际应用程序中,这些是您要考虑的其他事项。
这是为了使应用程序按预期工作所需的组件列表:
Laravel中的路由基本上是URI指定的端点,该URI充当应用程序提供的某些功能的“指针”。最常见的是,路由仅指向控制器上的方法,并且还指示哪些HTTP方法能够访问该URI。路由也不总是意味着控制器方法。它也可以将应用程序的执行传递给已定义的Closure或匿名函数。
为什么要使用路线?
路由存储在项目根目录下/ routes文件夹下的文件内。默认情况下,有几个不同的文件对应于应用程序的不同“面”(“面”来自六边形体系结构方法)。他们包括:
此时要关注的关键文件是特定于浏览器的文件,即web.php。默认情况下,已经定义了一种路由,该路由是您导航到应用程序的Web根目录(Web根目录位于公共目录中)时单击的路径。我们需要三种不同的路由来使我们的上传应用程序正常运行:
备注:如果希望将用于显示上传表单和文件列表的所有逻辑放在单个页面上,则可能不需要/ list端点,但是,我们暂时将它们分开以在此主题上添加更多内容。
//inside routes/web.php
Route::get('/upload', 'UploadController@upload')->name('upload');
Route::get('/download, 'UploadController@download)->name(‘download');
Route::post('/process', 'UploadController@process')->name('process');
Route::get('/list', 'UploadController@list')->name('list');
在此Laravel框架教程中,对于每个所需的路由,我们将使用可用的HTTP特定请求方法之一(get(),post(),put(),delete(), patch()或options())。有关每个分类的详细信息,请查看此内容。这些方法的作用是指定允许哪些HTTP动词访问该给定路由。如果您需要一个路由来接受一个以上的HTTP动词(如果您使用单个页面既显示初始数据又发布提交的表单数据,则可能是这种情况),则可以使用Route :: any( ) 方法。
Route :: get()和Route :: post()方法(以及Route外观上与HTTP谓词相关的任何其他方法)的第二个参数是内部包含的特定Controller和方法的名称在使用允许的HTTP请求(GET,POST,PATCH等)到达路由端点时执行的控制器,我们对所有三个路由都使用UploadController,并以以下方式指定了它们:
我们在每条路线上调用的最后一个方法是它的name()函数,该函数接受单个字符串作为参数,并用于或多或少地“标记”一条特定的路线,并易于记住该名称(在我们的示例中,上传,处理和列出)。我意识到,当URL的名称完全相同时,为每个路由指定自己的名称似乎并不是一个很好的功能,但是当您使用/ users / profile / dashboard / config之类的特定路由时,它确实派上了用场,使用profile-admin或user-config会更容易记住。
关于立面的注释:
在此Laravel框架教程中,上面的路由定义是使用Route门面,而不是手动实例化新的Illuminate / Routing / Router对象并在该对象上调用相应的方法。这只是节省键入内容的快捷方式。外墙在Laravel框架中被大量使用-您可以并且应该更加熟悉它们。可以在这里找到Facades的文档。
控制器是“ MVC”(模型-视图-控制器)体系结构中的“ C”,这是Laravel所基于的。控制器的工作可以归结为以下简单定义:它接收来自客户端的请求并将响应返回给客户端。这是最基本的定义,也是任何给定控制器的最低要求。它在这两件事之间所做的工作通常被认为是控制器的“动作”(或“路由的实现”)。它充当客户端应用程序的第二个入口点(第一个是请求),客户端将请求有效负载(我们将转到下一个)发送到应用程序,并期望某种类型的响应(形式为成功页面,重定向,错误页面或任何其他类型的HTTP响应)。
当命中该路由时,控制器会(基本上)执行与路由定义相同的操作,并且将匿名函数设置为“操作”。 区别在于,在将路由内联定义到实际的url定义时,控制器可以很好地保持关注点的分离,这基本上意味着我们正在将路由的分配URI与该路由的实现或该路由被执行时执行的代码耦合在一起。 打。
例如,以下两段代码将实现相同的功能:
例1:在单个方法调用中(在web.php路由文件中)路由的定义和实现
//inside routes/web.php
<?php
Route::get('/hello-world', function(Request $request) {
$name = $request->name;
return response()->make("<h1>Hello World! This is ".$name, 200);
});
范例2:Route的定义位于routes / web.php中,但其实现位于/ app / Http / Controllers / HelloWorldController类中
//inside routes/web.php
<?php
Route::get('/hello-world', 'HelloWorldController@index')->name('hello-world');
------------------------------------------------------------------------------------
//inside app/Http/Controllers/HelloWorldController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class HelloWorldController extends Controller
{
public function index(Request $request)
{
$name = $request->name;
return response()->make("<h1>Hello World! This is ".$name, 200);
}
}
尽管Laravel示例#2似乎需要做很多工作(不是的,只是更多的代码而已),但看看通过将给定的“ hello-world”路由的动作逻辑放入控制器内部所获得的好处而不是将路由的定义作为回调函数:
让我们运行此命令,它将为我们生成一个新的控制器。
// ...inside the project's root directory:
php artisan make:controller UploadController
本质上,此命令的作用是在/app/Http/Controllers/UploadController.php的主控制器目录内为名为“ UploadController”的控制器生成一个存根。可以随意打开该文件并进行查看。 这非常简单,因为它只是控制器的存根版本,具有正确的名称空间路径和从其扩展的必需类。
在继续进行本PHP Laravel教程并对UploadController的生成的存根进行一些更改之前,我认为首先创建请求类会更有意义。 这是因为处理请求的控制器方法必须在其签名中键入提示该请求对象的提示,从而使其能够自动验证传入的表单数据(如rules()方法中所指定。稍后会进一步介绍…) 让我们再次使用artisan命令来生成我们的请求存根:
php artisan make:request UploadFileRequest
此命令将在app / Http / Requests / UploadFileRequest内部生成一个名为UploadFileRequest的文件。 打开存根并进行查看…您会发现它非常简单,仅包含两个方法authorize()和rules。
让我们修改请求存根,以满足我们应用程序的需求。 修改文件,使其看起来像这样:
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class UploadFileRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'fileName' => 'required|string',
'userFile' => 'required|file'
];
}
}
变化不大,但是请注意authorize()方法现在返回true而不是false。 此方法决定是否允许请求进入应用程序。 如果将其设置为false,它将阻止请求进入系统(通常是控制器上的方法)。 这将是一个非常方便的地方,可以对用户进行任何授权检查,或者可以决定请求是否可以前进到控制器的任何其他逻辑。 现在,我们只是在此处返回true,以允许任何事物使用请求。
另一个方法rules()是所有与验证有关的魔术发挥作用的地方。 这个想法很简单:以以下形式返回包含一组规则的数组:
'formFieldName' => 'constraints this field has separated by pipe characters (|)'
Laravel开箱即用地支持许多不同的验证约束。有关它们的完整列表,请在此处查看在线文档。对于我们的上载应用程序,将有两个字段通过前端表单上的POST请求传递。 fileName参数必须包含在表单主体内(即必填),并且用作文件名,我们会将文件存储在存储器中(这是在控制器中完成的,我们稍后会介绍)。通过添加竖线字符(|)和单词’string’,我们还指定文件名必须是字符串。约束始终由管道分隔,允许您在一行中为给定字段指定任何其他条件!什么力量!
第二个参数userFile是用户从网页上的表单上载的实际文件。 UserFile也是必需的,并且必须是文件。注意:如果我们希望上载的文件是图像,那么我们将使用图像约束,这会将接受的文件类型限制为一种流行的图像类型(jpeg,png,bmp,gif或svg)。由于我们希望允许用户上传任何类型的文件,因此我们将坚持使用文件验证约束。
这就是请求对象的全部内容。它的主要工作是简单地保存表单主体参数必须满足的一组可接受的标准(约束),以便深入应用程序。还要注意的另一件事是,这两个字段(userFile和filename)也必须在HTML代码中以输入字段的形式指定(字段名称与请求对象内的名称相对应)。
您可能会问:确保这定义了表单请求应包含的特征,但是对这些约束的实际检查在哪里进行?接下来我们将讨论这一点。
打开app / Http / Controllers / UploadController并对其进行以下更改:
<?php
namespace App\Http\Controllers;
use Illuminate\Contracts\Container\BindingResolutionException;
use Illuminate\Http\Request;
use App\Http\Requests\UploadFileRequest; //our new request class
use Illuminate\Support\Facades\Storage;
class UploadController extends Controller
{
/**
* This is the method that will simply list all the files uploaded by name and provide a
* link to each one so they may be downloaded
*
* @param $request : A standard form request object
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
* @throws BindingResolutionException
*/
public function list(Request $request)
{
$uploads = Storage::allFiles('uploads');
return view('list', ['files' => $uploads]);
}
/**
* @param $file
* @return \Symfony\Component\HttpFoundation\BinaryFileResponse
* @throws BindingResolutionException
*/
public function download($file)
{
return response()->download(storage_path('app/'.$file));
}
/**
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
* @throws BindingResolutionException
*/
public function upload()
{
return view('upload');
}
/**
* This method will handle the file uploads. Notice that the parameter's typehint
* is the exact request class we generated in the last step. There is a reason for this!
*
* @param $request : The special form request for our upload application
* @return array|\Illuminate\Http\UploadedFile|\Illuminate\Http\UploadedFile[]|null
* @throws BindingResolutionException
*/
public function store(UploadFileRequest $request)
{
//At this point, the parameters passed into the $request (from form) are
//valid--they satisfy each of the conditions inside the rules() method
$filename = $request->fileName; //parameters have already been validated
$file = $request->file('userFile'); //that we don't need any additional isset()
$extension = $file->getClientOriginalExtension(); //grab the file extension
$saveAs = $filename . "." . $extension; //filename to save file under
$file->storeAs('uploads', $saveAs, 'local'); //save the file to local folder
return response()->json(['success' => true]); //return a success message
}
}
因此,这是一种将上传的文件保存到磁盘的相当简单的方法。这是上面的upload()方法的分解:
这个难题的最后一个主要部分是刀片模板,它将包含用于我们简单应用程序的所有HTML,CSS和javascript。这是代码-我们将在后面解释。
<body>
<h1>Upload a file</h1>
<form id="uploadForm" name="uploadForm" action="{{route('upload')}}" enctype="multipart/form-data">
@csrf
<label for="fileName">File Name:</label>
<input type="text" name="fileName" id="fileName" required /><br />
<label for="userFile">Select a File</label>
<input type="file" name="userFile" id="userFile" required />
<button type="submit" name="submit">Submit</button>
</form>
<h2 id="success" style="color:green;display:none">Successfully uploaded file</h2>
<h2 id="error" style="color:red;display:none">Error Submitting File</h2>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script>
$('#uploadForm').on('submit', function(e) {
e.preventDefault();
var form = $(this);
var url = form.attr('action');
$.ajax({
url: url,
type: "POST",
data: new FormData(this),
processData: false,
contentType: false,
dataType: "JSON",
success: function(data) {
$("#fileName").val("");
$("#userFile").val("");
}
}).done(function() {
$('#success').css('display', 'block');
window.setTimeout(()=>($("#success").css('display', 'none')), 5000);
}).fail(function() {
$('#error').css('display', 'block');
window.setTimeout(()=>($("#error").css('display', 'none')), 5000);
});
});
</script>
</body>
</html>
这是我们的/ upload页面的样子:
这是刀片文件的一个非常典型的示例,该刀片文件包含HTML表单和javascript / jQuery,用于添加异步功能(因此页面不会刷新)。有一个基本的标记,其中没有方法属性(我将在几秒钟内解释),并且具有一个奇怪的action属性,其值为{{route(’file.upload’)}}。在Blade中,这就是所谓的指令。指令只是功能的花哨名称-它们是特定于刀片模板的功能,这些模板执行构造Web页面和Web应用程序时常见的不同操作。为了更好地了解刀片可以执行的所有操作,请在此处查看文档。在上述情况下,我们使用route指令为表单提交生成URL。
请记住,我们之前在web.php文件中的应用程序中定义了路由,并为每个路由指定了易于记住的名称。 {{route()}}伪指令接受一条路由的名称,在内部缓存的路由列表中查找该名称,并根据web.php文件中该路由的定义生成完整的URL。对于第一种情况,我们指定我们希望表单将其提交的数据发送到应用程序的/ process URL,该URL定义为POST路由。
您可能已经注意到的下一个奇怪的事情是@csrf标签,位于开始表单标签的正下方。在Blade中,此标记在表单上生成_token参数,在允许处理表单数据之前先在应用程序内部对其进行检查。这样可以确保表单内的数据是有效来源,并防止跨站点请求伪造攻击。有关更多信息,请参阅文档。
在此之后,我们将表单定义为普通表单,但是请注意,表单参数的名称userFile和fileName与我们在请求对象中定义的完全相同。如果我们忘记包含在请求对象中定义的给定参数的输入(或拼写错误),则该请求将失败并返回错误,从而防止原始表单请求碰到位于UploadController @处的控制器方法过程 。
继续尝试一下,并使用此表单向应用程序提交一些文件。然后,导航到/ list页面以查看上载文件夹的内容,并在表中列出了您上载的文件:
让我们退后一步,看看我们在本Laravel教程中所做的工作。
此图描述了当前的应用程序(不包括高级细节):
您应该记得,我们在本Laravel教程开始时构建的请求对象应在其rule方法中定义的参数与刀片模板中的表单具有相同的参数(如果不重新阅读“创建验证逻辑”部分) 。用户在通过刀片模板引擎呈现的网页中输入表单(此过程当然是自动驾驶,因此我们甚至不必考虑它)并提交表单。模板底部的jQuery代码停止默认的提交(它将自动重定向到单独的页面),创建ajax请求,使用表单数据加载请求并上传文件,然后将整个内容发送到我们的第一层应用程序:请求。
通过将rules()方法中的参数与提交的表单参数相关联来填充请求对象,然后根据每个指定的规则验证数据。如果满足所有规则,则请求将传递到与路由文件web.php中定义的值相对应的任何控制器方法。在这种情况下,完成工作的是UploadController的process()方法。一旦到达控制器,我们就知道请求已通过验证,因此我们不必重新测试给定的文件名是否实际上是字符串或userFile参数实际上包含某种类型的文件…我们可以照常继续。
然后,控制器方法从请求对象中获取经过验证的参数,通过将传入的fileName参数与userFile的原始扩展名进行连接来生成完整的文件名,将该文件存储在应用程序的目录中,然后返回一个简单的JSON编码响应,以验证请求是否成功。响应由jQuery逻辑接收,它执行一些其他与UI相关的任务,例如显示成功(或错误)消息5秒钟,然后将其隐藏以及清除以前的表单条目…这样用户可以确定请求是否成功,并且可以根据需要上传另一个文件。
另外,请注意上图中的客户机和服务器之间的连线。这个概念对于您理解绝对至关重要,它将帮助您解决将来在杂耍中可能遇到的问题,例如,在任何给定时间可能发生的多个异步请求。分隔线恰好在请求对象的边界处。可以将请求对象本身视为应用程序其余部分的“网关” …它对从Web浏览器传入的表单值进行初始验证和注册。如果它们被认为是有效的,则继续进行到控制器。之前的所有内容都位于前端(“客户端”的字面意思是“位于用户计算机上”)。响应从应用程序返回到客户端,在这里,我们的jQuery代码耐心地等待其到达,并在收到响应后执行一些简单的UI任务。
我们已经为新手和经验丰富的候选人提供了将近90多个重要的Laravel和PHP相关面试问题,以找到合适的工作。