教程:PHP项目开发全程实录#PHP项目实战#EWShop商城系统


P11

安装Macaw路由组件
进入项目目录,然后:

composer require noahbuscher/macaw:dev-master

说明文档:
点击这里查看

使用方法:
安装好之后,进入index.php,使用以下代码就可以使用Macaw:

<?php
    //包含所有composer组件库
    require('vendor/autoload.php');

    use NoahBuscher\Macaw\Macaw;

    Macaw::get("/", function(){
        echo "11111111111111";
    });

    Macaw::get("/hello/world", function(){
        echo "22222222222222";
    });

    Macaw::get("/hello/(:num)", function($num){
        echo "22222222222222".$num;
    });

    Macaw:get("/hello/(:num)", "admin\Admin@index");
    //控制器

    Macaw::dispatch();

调用控制器里的类和方法

如果需要使用Macaw调用类里面的方法,需要这样做。

首先,在index.php里面定义好路径和调用类方法名称,如:

Macaw::get("/admin", "admin\Demo@index");
Macaw::get("/admin/add", "admin\Demo@add");
//疑问:Macaw怎么知道admin\Demo是app\controllers里面的admin\Demo,而不是别的路径下的admin\Demo呢?
//答案:后面会使用composer.json文件里的autoload里来定义访问路径应该去找哪个路径

然后,进入adminDemo类文件,声明命名空间并创建路径里面的类和方法:

namespace admin;

class Demo {
  function index(){
  }
  function add(){
  }
}

第三,回到index.php文件,引入demo.php文件

require("app/controllers/admin/demo.php");

然后就可以通过domain.com/admin或者domain.com/admin/add访问自己定义的方法了。

统一调用类

如果一个模块就一行require的话,太多了就歇不过来,这时候可以使用psr4规范来引用类。
进入composer.json,添加以下配置:

"autoload":{
  "psr-4": {
    "admin\\":"app/controllers/admin"
    //这个说的是,如果访问admin这个路径,就使用app/controllers/admin下面的类
  }
}

这个配置后,删除index.php的require行,这时候如果访问domain.com/admin会报错找不到类,是因为虽然composer.json已经改了,但是没有更新到vendor/composer/autoload_psr4.php里面,因此还不能生效。需要再执行以下命令:

composer dump-autoload

之后会发现autoload_psr4.php的return array里面多了一行针对"admin\"的配置,这时候就可以访问了。
每添加一个目录,都需要这么执行一次。

用同样的方法为home添加访问:

  1. composers.json里面,添加一行

    "home\\":"app/controllers/home"
    
  2. 在home文件夹里创建test类test.php
  3. 在index里面创建Macaw访问路径

    Macaw::get("/home","home\Test@index");
    
  4. composer dump-autoload就可以了

总结访问执行路径:

  1. 访问index.php,里面有use NoahBuscherMacawMacaw,可以使用Macaw组件
  2. 同时index.php里面有Macaw::get("/admin", "adminDemo@index"); Macaw根据/admin这个路径,去找admin下的Demo类的index方法
  3. admin类在什么位置呢,通过composer.json里面的autoload里的psr-4里的"admin\":"app/controllers/admin"来定义
  4. 同时vendor的composer的autoload_psr4.php里也必须要有这个记录,通过composer dump-autoload来添加
  5. 找到类和方法后,调用方法

P12

建立基础控制器

第一,在controllers下面建立BaseControllers.php文件,这个是基础控制器,里面包含基础方法,比如成功跳转和失败跳转的方法

namespace controllers;
class BaseControllers {
  protected function success($url, $mess){
  }
  protected function error($url, $mess){
  }
}

第二,为了能够在别的文件里直接使用,需要在composer.json里面添加以下命令并执行composer dump-autoload

"controllers\\":"app/controllers"

第三,然后在test或者demo类文件里面

use controllers/BaseControllers;
class Demo extends BaseControllers {
  function index(){
    $this->success("/home", "成功");
    $this->error("/home/add", "失败");
  }
}

第四,这个父类的方法可以用来执行各种成功或者失败的提示,比如登录成功,提交成功等等。

建立视图模块

安装twig/twig组件

composer require twig/twig

使用Twig调取模板文件

首先在views下面建立html模板文件,比如index.html

之后在controllers下面的类文件比如admin.php的方法里,使用如下代码来调用模板:

namespace admin;
use controllers\BaseControllers;

class Admin extends BaseControllers {
  function index () {
    $loader = new \Twig\Loader\FilesystemLoader('C:/wamp64/www/ewshop/app/views'); //此处是绝对路径
    $twig = new \Twig\Environment($loader, [
      
    ]);
    echo $twig->render('admin/index/index.html', ['name' => 'Alex']);
  }
}

在index.html里面,可以使用{{name}}来显示数据。

我的理解,首先这是一个控制器的方法,方法里面的这些代码是用来调取html模板文件的,一手调取模板文件,另一手在echo的时候,将[]里的数据放入到html里。

优化代码

为了不需要每次都写一遍这几行代码,我们把代码放入到BaseControllers中,同时将调用的处理和数据的处理分开。

在BaseControllers类里面,新增以下代码:

class BaseControllers {
  protected $twig;
  protected $data = [];

  //创建twig对象
  public function __construct(){
    $loader = new \Twig\Loader\FilesystemLoader('C:/wamp64/www/ewshop/app/views'); //此处是绝对路径
    $this->twig = new \Twig\Environment($loader, [
      
    ]);
  }

  //处理数据
  protected function assign($var, $value=null){
    if(is_array($var){
      $this->data = array_merge($var, $this->data);
      //如果assign的是一个数组,就merge到data数组里
    }else{
      $this->data[$var] = $value;
      //如果assign的不是一个数组,就添加到data数组里
    }
  }

  //渲染输出
  protected function display($template){
    echo $this->twig->render($template.'.html', $this->data);
  }
}

在admin.php的Admin类里,可以如此使用:

class Admin extends BaseControllers {
  //assign数据
  $this->assign('name', 'Alex'); //不是数组,因此有$var和$value,添加到$this->data数组里
  $this->assign('title', 'This is a test'); 
  $this->assign(['aaa', 'bbb', 'ccc']); //是数组,只有$var,$value是空,merge到$this->data数组里

  //输出
  $this->display('admin/index/index'); //只需要写模板文件路径即可
}

在index.html里,可以使用{{name}}, {{title}}来输出数据,也可以使用遍历方法,还没学到。

一个小坑

在此期间出现一个问题,写入到构造函数的时候,我忘了把$twig改成$this->twig了,导致出现了下面的错误提示,折腾了好一会才找到问题:

Error: call to a member function render on null

我的理解,如果没有这改的话,构造函数里面虽然创建了一个$twig,但是并不是class里面定义的那个@twig,因此这个变量仍然是空的,并不是一个对象,所以这个空的变量下面就不会有一个叫render的function,这也就是call to a member function render on null里面的null的意思,就是你想无中生有是不行的。

另一个小坑

在写display()的时候,忘了写echo,导致什么也没有输出,又花了点时间对比找问题……

P12学习心得:对于一些方法,如果是通用型的,可以把它们“升级”到父类里面,以便大家都可以使用,在父类里面,记得要用$this->来指定变量,这样大家才能用到同样的变量。


建立helper

在app下建立helpers.php全局类,建立帮助的类

if(!function_exist('dd')){
  function dd(...$args){
    http_response_code(500);
    foreach($args as $x){
      var_dump($x);
    }
    die(1);
  }
}

然后在composer.json里添加如下配置:

"files":[
"app/helpers.php",
"config.inc.php"
]

再执行composer dump-autoload,就可以在任何地方都可以调用这个方法,然后输出任何想要的内容,方便开发的时候用来调试。

设置固定目录

在config.inc.php里定义一个路径常量:
define("TEMPDIR", __DIR__);

然后在BaseControllers里的路径,就可以使用TEMPDIR来替换:
$loader = new TwigLoaderFilesystemLoader(TEMPDIR.'/app/views'); //此处是相对路径

设置多套模板

如果需要设置多套模板,可以在admin类文件旁边再建一个temp1.php的文件,然后继承Admin类。

把构造函数$loader和$this->twig这一段放入到admin文件的Admin类里(10.21补充:注意是复制,不是剪切),然后在config.inc.php里定义一个常量
define("TEMPNAME", "home");
$loader里把路径拼接这个常量,通过修改常量就可以实现切换模板。

这个常量,其实是要放到路径里的,如果模板都放到home这个路径下,就define成home,如果别的模板名称,比如template1,把这个修改了就可以实现切换模板的目的。

有一个基础的类Admin,以后每套模板都都继承这个类。
然后改变常量,使得Admin类里面的$loader的路径发生变化。
针对每套模板,都有一个controller类和views下面的一个文件夹路径。

老师的总结:有一个BaseControllers类,下面分别有Admin和Home两个类,分别作为前端和后端的基类,所有的后端的类和前端的类都要分别集成Admin和Home两个类。


P14

前端展示

展示参数,使用{{varname}}
注释,使用{ },不会像<!-- -->这样展示在源码里
包含文件,使用{% include "public/header.html" %}
在控制器里可以assign一个数组$this->assign("data", $array),在模板文件里就需要使用{{data.one}}来显示。

循环输出:
{% for v in data %}
{{v}}

{% endfor %}
即可循环输出

循环输出key和value:
{% for k,v in data %}
{{k}} == {{v}}

{% endfor %}

使用if语句:
{% if title == "lalala" and flag == 2 %}
1111111
{% elseif flag == 2 %}
3333333
{% else %}
2222222
{% endif %}

使用模板里的方法:
{{atime|time('Y-m-d')}}


P15

操作数据库的模型

使用catfan/medoo组件,已经封装好增删改查了,文档链接
安装使用 composer require catfan/medoo
添加到psr-4里面,"models\":"app/models",然后执行composer dump-autoload

使用medoo
在models文件下下面,建立一个basedao.php文件,代码如下:

namespace models;
use MedooMedoo;

class BaseDao extends Medoo {
function __construct(){

$options = [
  'database_type' => 'mysql',
  'database_name' => '',
  'server' => '',
  'username' => '',
  'password' => '',
  'prefix' => '',
  'port' => ''
];
parent::__construct($options);

}
}

之后,就可以在控制器下,比如test.php下,使用如下代码操作数据库:

use modelsBaseDao;

class Test extends BaseControllers {
function index(){

$db = new BaseDao();
$data = $db->select('product', '*');
//分配到模板
$this->assign('data', $data);
$this->display('index/index');

}
}

之后,就可以在模板文件,比如index.html里,使用如下代码循环输出:

{% for v in data %}
{{v.name}}
{{v.money}}
{% endfor %}

就可以完成从数据库里查询数据并从页面上循环展示。

关闭notice提示

在入口文件index.php里,(P15,13:33),第一行,写如下命令:
error_reporting(E_ALL & ~E_NOTICE);
Notice不显示,但是error还显示。

将数据库配置文件写到配置文件里

在config.inc.php里,添加如下:

define("DBNAME", 'ewshop');
...
...

使用medoo语句

$this->debug()->select(‘product', ['name', 'money']);
debug()->可以看sql语句原型,不会执行,只会显示
多个字段使用['name', 'money']
别名使用['name(linkename)', 'money']
加条件
$this->select('link', ['name', 'ord'], ['id'=>1]); //id等于1
$this->select('link', ['name', 'ord'], ['id[>]'=>1]); //id大于1
$this->select('link', ['name', 'ord'], ['id[>]'=>1, 'name[~]'=>'abc']); //id大于1,且name模糊等于abc
$this->select('link', ['name', 'ord'], ['id[>]'=>1, 'ORDER'=>['ord'=>'DESC', 'id'=>'ASC']]); //按照ord DESC排序,id ASC排序
$this->select('link', ['name', 'ord'], ['LIMIT'=>[2,3]'id[>]'=>1, 'ORDER'=>['ord'=>'DESC', 'id'=>'ASC']]); //limit 3 从第3行开始
$data = $this->debug()->get('tablename', 'fieldname'); //等于select 'fieldname' from tablename
$data = $this->count('tablename', '*'); //count有多少行

$data = $this->delete('tablename', 'id[>]'=>1) //第一个是表名,第二个是条件

$data = ['name'=>'Alex', 'ord'=>1];
$data = $this->insert('tablename', $data); //插入数据

$data = $db->debug()->update('link', ['name'=>'aa', 'ord'=>5], ['id'=>1]); //更新数据,第一个参数表名,第二个参数是修改的值,第三个参数是条件

官网语句参考

最后编辑:2021年01月05日 ©著作权归作者所有

发表评论