JB Online开发笔记0:重要模块介绍

工欲善其事,必先找框架。

工程结构

+---app
|   +---Console
|   +---Exceptions
|   +---Http
|   |   +---Controllers
|   |   +---Middleware
|   |   \---Requests
|   +---Models
|   \---Providers
+---bootstrap
+---config
+---database
|   +---factories
|   +---migrations
|   \---seeds
+---public
+---resources
|   +---js
|   +---lang
|   +---sass
|   \---views
+---routes
+---storage
|   +---app
|   +---debugbar
|   +---framework
|   \---logs
\---tests

重要部分介绍

/app/Http

这个文件夹里的内容定义控制器、中间件和请求。

/app/Model/app/Repositories

这个部分定义网站中使用到的模型。

/database

定义数据库表类型与元素,处理建立数据库的操作。

/resources

这个文件夹包括脚本、样式表等文件、文本翻译以及页面的内容。

/routes

这个文件夹里定义路由。

模块之间的相互关系

事由

【堆排序】愿天堂没有大物 22:36:21

基本够了吧

【aunt】JB网开发指南还没写 22:36:25

介绍一下这几个部分是如何连起来的吧!

【aunt】JB网开发指南还没写 22:36:30

然后再举个例子

【aunt】JB网开发指南还没写 22:36:31

YEAH

大概意思

以下内容是我的瞎几把理解,可能有误,请务必指出。

  1. 当服务器收到一个请求,首先会通过复杂的PHP调用、引入来跳转到路由(route)环节,这一步可以近似看作是C的#include。(其实这不是第一步,但是那并不重要,就跟PA里你学会了程序不从main开始执行一样,以后再了解好了。)

  2. PHP将当前访问的地址与路由中定义的每一条路由进行顺序匹配,如果匹配成功,进行下一步处理,否则404。路由器同时需要(顺序?)对请求进行动词(HTTP verb)中间件(middleware)检查,例如auth中间件只允许登录了的用户通过,其他的包括admin(仅限管理员)、throttle(单位时间内只允许多少次)、role(用户组检验)等中间件以及较为特殊的Gate函数,此处不进行介绍。如果动词错误,则405,如果中间件检验失败,则403。

  3. 检验通过后,跳转至对应的控制器(controller)函数进行执行。控制器函数会根据对应的请求(request)进行预处理,比如对输入的内容进行检查,如果发现输入不合法则返回并提示错误,或者进行净化(sanitize)然后放行。控制器会进行一系列的函数处理,最后返回一个view(中文名不知道)或者JSON数据,或者直接报错终止。

  4. 在控制器处理中,可能会对模型(model)进行操作,模型进一步调用库函数(repository)中定义的函数与数据库进行交互。控制器返回view时,还可能会调用模型的特征(trait),这就相当于在C++中调用class的成员函数/对象了。特称包括属性(attritube)(例如名称等)、方法(method)(如何修改)、关系(relationship)(和别的模型之间的关系)、能力(scope)等。

  5. 浏览器收到了服务器返回的view或者数据之后,就可以把数据渲染出来,用户就看到了精美的JB网画面了。

举个例子

服务器收到了对/的访问,也就是要访问一下主页。

  1. (首先跳过很长的对程序员透明的内容)

  2. 路由器命中了位于/routes/frontend/home.php中的Route::get('/', '[email protected]')->name('index');这一行,这行使用全局的web中间件组,然后进行中间件检查。

  3. /app/Http/Middleware/CheckClientIP.php中定义了如何对客户端的IP进行检查。

    /**
    * Handle an incoming request.
    *
    * @param  \Illuminate\Http\Request  $request
    * @param  \Closure  $next
    * @return mixed
    */
    public function handle($request, Closure $next)
    {
       if (\Auth::hasUser() || $request->url() == route('frontend.auth.login')
           || $request->url() == route('frontend.auth.login.post')) {
           return $next($request);
       }
    
       if (!app()->isLocal() && env('APP_BLOCK_IP', true)) {
           $ip = geoip()->getClientIP();
           $location = geoip()->getLocation($ip);
           if ($location['country'] != 'China') {
               return abort(233, "GeoIP check failed: " . $ip . " from " . $location['country']);
           }
       }
       return $next($request);
    }

    如果发现用户并非来自大陆地区,就会报233错误,跳转到“爱慕拆腻斯”页面。

  4. 通过所有的中间件检查后,跳转到控制器[email protected]执行。函数的定义如下

    /**
    * @return \Illuminate\View\View
    */
    public function index()
    {
       $feeds = array();
       if(app_blogonhome()) {
           $originFeed = \Feeds::make(app_blogrss(), 0, false);
           $items = $originFeed->get_items();
           foreach ($items as $item) {
               //$description = $item->get_description();
               //$regex = '/(<[^>]+>)/is';
               //$content = preg_replace($regex, '', $description);
    
               $date = \Carbon\Carbon::parse($item->get_date());
               $feeds[] = array(
                   'permalink'   => $item->get_permalink(),
                   'title'       => $item->get_title(),
                   'date'        => $date,
               );
           }
       }
    
       return view('frontend.index')
           ->withNotice($this->noticeRepository->getNotice())
           ->withOngoingCourses($this->courseRepository->getOngoingCourses())
           ->withAssignments($this->assignmentRepository->getOngoingAssignments())
           ->withFeeds(collect($feeds));
    }

    这段函数首先获取$feeds,也就是首页上你能看到的“班级博客”的内容,然后把公告、作业、课程、博客的内容统统塞给view('frontend.index')处理,把处理好的内容返回。

  5. /resources/views/frontend/index.blade.php的内容如下:

    @extends('frontend.layouts.app')
    
    @section('title', app_name() . ' | ' . __('navs.general.home'))
    
    @section('content')
       <div class="page-header text-center">
           <div class="card">
               <img class="card-img" src="/storage/posts/jb-online-devlog-0-modules/{{ app_coverart() }}" id="coverart" style="width: 100%">
               <div class="card-img-overlay text-right">
                   <h4 class="card-title flipInX animated">
                       {{ app_name() }}
                   </h4>
               </div>
           </div>
       </div>
       <div class="row">
           <div class="col col-lg-7 col-12" id="leftCol">
               @include('frontend.includes.index.assignments', [$assignments])
           </div>
    
           <div class="col col-lg-5 col-12" id="rightCol">
               @include('frontend.includes.index.heatmap')
               @include('frontend.includes.index.notice', [$notice])
               @include('frontend.includes.index.courses', [$ongoingCourses])
               @include('frontend.includes.index.blogonhome')
           </div>
       </div>
    @endsection

    第一行是表示,这个页面继承前端的布局,然后第三行设置标题,第五行开始是页面的内容。这已经很容易看懂了,不介绍了。

  6. 最后服务器把所有诸如@xxx(条件语句)和{{ xxx }}(显示文本)以及{!! xxx !!}(显示HTML)的代码全部处理(其实都是PHP的语法糖),然后把HTML内容发给客户端。客户端就渲染出了漂亮的页面。

发布于2019-01-13 23:06

笔记 / Laravel