Php 验证输入和查询优化的问题

Php 验证输入和查询优化的问题,php,mysql,database,laravel,Php,Mysql,Database,Laravel,我正在创建一个管理系统,教师可以在其中管理学生的期末项目,形成者可以看到其他学生创建的项目 我是一个新手,在优化查询和验证URL时遇到问题 以下是我的表格模式: 库索斯 +-------+------------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+------------------

我正在创建一个管理系统,教师可以在其中管理学生的期末项目,形成者可以看到其他学生创建的项目

我是一个新手,在优化查询和验证URL时遇到问题

以下是我的表格模式:

库索斯

+-------+------------------+------+-----+---------+----------------+
| Field | Type             | Null | Key | Default | Extra          |
+-------+------------------+------+-----+---------+----------------+
| id    | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| curso | varchar(255)     | NO   |     | NULL    |                |
+-------+------------------+------+-----+---------+----------------+
三年期

+--------------+------------------+------+-----+---------+----------------+
| Field        | Type             | Null | Key | Default | Extra          |
+--------------+------------------+------+-----+---------+----------------+
| id           | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| data_trienio | varchar(255)     | NO   |     | NULL    |                |
| curso_id     | int(11)          | NO   |     | NULL    |                |
| oe_id        | int(11)          | NO   |     | NULL    |                |
+--------------+------------------+------+-----+---------+----------------+
阿鲁诺斯

+------------+------------------+------+-----+---------+----------------+
| Field      | Type             | Null | Key | Default | Extra          |
+------------+------------------+------+-----+---------+----------------+
| id         | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| id_cartao  | int(10) unsigned | NO   | UNI | NULL    |                |
| nome       | varchar(255)     | NO   |     | NULL    |                |
| email      | varchar(255)     | NO   | UNI | NULL    |                |
| trienio_id | int(11)          | NO   |     | NULL    |                |
+------------+------------------+------+-----+---------+----------------+
爸爸

到目前为止,我已经根据cursos和trienios表上定义的记录设置了动态URL,如下所示:
http://localhost:8000/TGEI/2014-2017年

(TGEI是curso表中的一条记录,用于获取相关的trienios记录;2014-2017年是trienios表中的一条记录,与一对多关系中的curso记录相关,用于获取相关的pap记录)

这一切都很顺利,但我在优化效率极低的查询时遇到了麻烦,而当数据库增长时,这将成为一个非常重要的问题

以下是我的人际关系:

Curso.php

public function trienio()
{
    return $this->hasMany('App\Trienio');
}
Trienio.php

public function curso()
{
    return $this->belongsTo('App\Curso');
}

public function oe()
{
    return $this->belongsTo('App\OE');
}

public function aluno()
{
    return $this->hasMany('App\Aluno');
}
Aluno.php

public function trienio()
{
    return $this->belongsTo('App\Trienio');
}

public function pap()
{
    return $this->hasOne('App\PAP');
}
PAP.php

protected $table = 'pap';

public function aluno()
{
    return $this->belongsTo('App\Aluno');
}
这些是负责为用户可访问页面提供服务的控制器:

CursoController.php

public function index(Curso $curso)
{
    $cursos = $curso->all();

    return view('curso')->withCursos($cursos);
}
public function index(Trienio $trienio, $curso)
{   
    $trienios = $trienio->whereHas('curso', function ($query) use ($curso) {
        $query->where('curso', '=', $curso);
    })->get();

    return view('trienio')->withTrienios($trienios);
}
public function index(Pap $pap, $curso, $trienio)
{
    $pap = $pap->whereHas('aluno.trienio', function ($query) use ($curso, $trienio) {
        $query->where('data_trienio', '=', $trienio)->whereHas('curso', function ($query) use ($curso) {
            $query->where('curso', '=', $curso);
        });
    })->toSql();

    dd($pap);

    return view('pap')->withPap($pap);

}

public function show(Pap $pap, $curso, $trienio, $id)
{   
    $pap = $pap->find($id);

    dd($pap);

    return view('show')->withPap($pap);
}
trineiocontroller.php

public function index(Curso $curso)
{
    $cursos = $curso->all();

    return view('curso')->withCursos($cursos);
}
public function index(Trienio $trienio, $curso)
{   
    $trienios = $trienio->whereHas('curso', function ($query) use ($curso) {
        $query->where('curso', '=', $curso);
    })->get();

    return view('trienio')->withTrienios($trienios);
}
public function index(Pap $pap, $curso, $trienio)
{
    $pap = $pap->whereHas('aluno.trienio', function ($query) use ($curso, $trienio) {
        $query->where('data_trienio', '=', $trienio)->whereHas('curso', function ($query) use ($curso) {
            $query->where('curso', '=', $curso);
        });
    })->toSql();

    dd($pap);

    return view('pap')->withPap($pap);

}

public function show(Pap $pap, $curso, $trienio, $id)
{   
    $pap = $pap->find($id);

    dd($pap);

    return view('show')->withPap($pap);
}
PapController.php

public function index(Curso $curso)
{
    $cursos = $curso->all();

    return view('curso')->withCursos($cursos);
}
public function index(Trienio $trienio, $curso)
{   
    $trienios = $trienio->whereHas('curso', function ($query) use ($curso) {
        $query->where('curso', '=', $curso);
    })->get();

    return view('trienio')->withTrienios($trienios);
}
public function index(Pap $pap, $curso, $trienio)
{
    $pap = $pap->whereHas('aluno.trienio', function ($query) use ($curso, $trienio) {
        $query->where('data_trienio', '=', $trienio)->whereHas('curso', function ($query) use ($curso) {
            $query->where('curso', '=', $curso);
        });
    })->toSql();

    dd($pap);

    return view('pap')->withPap($pap);

}

public function show(Pap $pap, $curso, $trienio, $id)
{   
    $pap = $pap->find($id);

    dd($pap);

    return view('show')->withPap($pap);
}
如您所见,在PAP控制器的索引方法的情况下,请求数据的查询是一个巨大的混乱,这是n+1问题的缩影:

"select * from `pap` where exists (select * from `alunos` where `pap`.`aluno_id` = `alunos`.`id` and exists (select * from `trienios` where `alunos`.`trienio_id` = `trienios`.`id` and `data_trienio` = ? and exists (select * from `cursos` where `trienios`.`curso_id` = `cursos`.`id` and `curso` = ?)))"
这个查询的目的是获取与trienio记录相关的PAP记录,而trienio记录又与curso记录相关,基于用户在url中输入的输入(我在上面展示了一个示例),问题是,一般来说,我是这方面的新手,我无法将急切加载概念应用于我要运行的查询

此外,我在验证用户可以输入以下内容的URL时遇到问题:

http://localhost:8000/qwfkjnfwq/qjqtikjn/1
控制器方法show将获取pap记录,而不考虑用户输入的2级以上的参数,这显然会带来“安全”问题

我想做的是:

http://localhost:8000/TGEI/2014-2017/1
控制器方法show将加载aluno.trienio嵌套关系,然后根据
2014-2017
参数获取与aluno模型相关的trienio id,然后根据
TGEI
参数获取与trienio模型相关的游标id

所以,像这样的东西

http://localhost:8000/qwfkjnfwq/qjqtikjn/1
将被作废,而不是通过

这可能是一个棘手的问题,但无论谁能帮助我,我都会非常感谢。我知道我的问题的某些部分可能不清楚(甚至更不清楚,因为英语不是我的第一语言),在这种情况下,我可以按照你的意愿澄清它们

为了获得更好的信息,这里是我的web.php文件

Route::get('/', 'CursoController@index');
Route::get('/{curso}', 'TrienioController@index');
Route::get('/{curso}/{trienio}', 'PapController@index');
Route::get('/{curso}/{trienio}/{id}', 'PapController@show');

好的,我来详细谈谈我的评论

使用Laravel 5.2,您可以将模型注入控制器方法(如下所示:
public function show(Pap$Pap)
),Laravel将自动获取url中id为的
Pap
模型(主要是执行
Pap::find($id)
,并将返回值保存到
$Pap
变量中)。这并不总是您想要的,因为您通常希望执行更复杂的查询

我建议您在您的情况下不要使用路由模型绑定,只需自己进行查询。类似这样的内容(请参见我如何从控制器功能中删除模型)

还要注意,在
show()
方法中,我几乎复制了
index()
查询,这是验证

关于查询的优化,您拥有的查询是绝对好的。目前没有n+1问题

如果要对其中一个索引结果执行
foreach
,并调用child的属性,则会出现n+1问题。例如,如果要在
pap
视图中执行类似操作:

@foreach($pap as $p)
<div>{{ $p->aluno->id }}</div>
@endforeach
这不是完全直观的,但是
->whereHas(relationship)
不会立即加载关系。你经常会发现自己在写这样的陈述:

// Pap controller
public function index($curso, $trienio)
{
    $pap = Pap::whereHas('aluno.trienio', function ($query) use ($curso, $trienio) {
        $query->where('data_trienio', '=', $trienio)->whereHas('curso', function ($query) use ($curso) {
            $query->where('curso', '=', $curso);
        });
    })
    ->with('aluno.trienio') // You might need some additional checks here, depending on you needs
    ->get();

    return view('pap')->withPap($pap);
}
// Pap controller
public function index($curso, $trienio)
{
    $pap = Pap::whereHas('aluno.trienio', function ($query) use ($curso, $trienio) {
        $query->where('data_trienio', '=', $trienio)->whereHas('curso', function ($query) use ($curso) {
            $query->where('curso', '=', $curso);
        });
    })
    ->with(['aluno.trienio' => function ($q) use ($curso, $trienio) {
        $query->where('data_trienio', '=', $trienio)->whereHas('curso', function ($query) use ($curso) {
            $query->where('curso', '=', $curso);
        }]); // These are the additional checks
    ->get();

    return view('pap')->withPap($pap);
}

很好的用户名!;)你一定花了很长时间才把问题安排妥当。好+1欢迎来到SO.thx dude,如果我在你的url
http://localhost:8000/qwfkjnfwq/qjqtikjn/1
您需要在执行参数之前验证参数,如
qwfkjnfwq
。是的,我知道,但如何验证?这是问题的要点之一。我认为您最好不要在您的案例中使用。另外,顺便问一下,您如何通过名称(例如:PAP Repository)找到模型并将其作为参数传递到url中(比如:localhost:8000/TGEI/2014-2017/pap repository而不是通过id查找它?您只需在查询中链接一个where方法,并以first结尾。比如
pap::whereHas(..)->where('name',$name)->first()
。然后将方法
$id
重命名为
$name
公共函数show($curso,$trienio,$name)
。对,但是,如何消除名称(PAP(空白)存储库)中的空白?laravel是否会自动为您这样做(例如:重命名为PAP存储库)?(如果这个问题看起来太“新手”,那么很抱歉)。常见的做法是在sql表中增加一个字段(通常称为
slug
),这是名称的名称。没问题,很乐意帮助:)