在Laravel中,数据库逻辑应该放在哪里?

3

我目前对Laravel还很陌生,正在努力理解Laravel的代码结构。学习Laravel的原因是为了增加创建良好代码和易于管理应用程序的知识。因此,对我来说,将应用程序构建到一个被接受的标准非常重要。

我已经阅读了几篇文章,但仍不确定如何组织代码。

目前,我的应用程序结构如下:

app/
    Console
    Exceptions
    Http
       Controllers
           Auth
           Message
           Settings
       Middleware
    Providers
    Traits
        Message
        Settings

我的一个控制器看起来像这样:

<?php

namespace App\Http\Controllers\Message;

use DB;
use Auth;
use Request;
use App\Http\Controllers\Controller;

class TypeController extends Controller
{
    public function __construct () {
        $this->middleware('auth');
        $this->middleware('access');
    }

    public function type () {
        $this->adjustTypingStatus(1);
    }

    public function untype () {
        $this->adjustTypingStatus(0);
    }

    protected function adjustTypingStatus ($level) {
        DB::table('user_lobby_info')
            ->where('userid', Auth::User()->id)
            ->where('lobby', Request::get('lobbyid'))
            ->update([ 'typing' => $level ]);
    }
}

?>

问题

如何更好地将控制器分成更小、更易管理的部分?我应该将数据库逻辑放入模型中,并仅调用模型的方法吗?


我注意到你的控制器方法中引用了DB类而不是模型。你能分享一下你的模型吗? - Dom DaFonte
@DomDaFonte 我没有设置大部分的模型。我想这是 Laravel 的一部分,我认为它不太有用,因为我使用了查询构建器而不是引用模型,现在看来更有意义。 - Shawn31313
好的,我相信我现在理解了这个问题,我会回答一个答案,应该能够澄清如何使用Laravel创建一个简单的CRUD MVC应用程序。 - Dom DaFonte
user_lobby_info 是一个数据透视表吗? - Rwd
@DomDaFonte 谢谢 - Shawn31313
@RossWilson 先生,不是这样的! - Shawn31313
2个回答

2
这是我如何分解控制器逻辑并在小到中等规模的项目中使用模型的方法。
1. 创建你的表和模型
这个命令将创建你的模型,而 --migration 参数将创建一个迁移文件,引用了 BluePrint 类,你可以使用它来创建你的模型表。
php artisan make:model UserLobbyInfo --migration

你似乎已经创建了一个数据库,所以你可能想要移除 --migration,除非你想使用它来使用 BluePrint 创建模式。我个人喜欢使用迁移。在 Laravel 5 中,你的模型将直接创建在 App 文件夹下。
2. 修改你的模型文件
你可以在 App 文件夹中找到你的模型文件。在你的模型中,你应该添加你将插入或更新的字段(批量填充项)和你的表名,如果它不遵循 Laravel 的约定(Laravel 假设驼峰表示不同的单词,并且你的表以 's' 结尾,所以它认为你的表将是 user_lobby_infos,在你的情况下,你的表名是 user_lobby_info)。这是我根据你上面查询的数据更新它的方式:
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class UserLobbyInfo extends Model
{
// Define mass fillable items
    protected $fillable = array('userid','lobby','typing');

//Define table
    protected $table = 'user_lobby_info';

}

如何使用您的模型

该模型现在具有从其扩展的Illuminate\Database\Eloquent\Model类提供的所有方法,因此您可以执行以下操作和更多操作:

//To query all content:
$index = UserLobbyInfo::all();

//To query specific content:
$userLobby = UserLobbyInfo::where('id', '=', 1)->first();

//Save things:
$userLobbyInfo = UserLobbyInfo::where('id', '=', 1)->first();
$userLobbyInfo->lobby = Request::get('lobbyid')
$userLobbyInfo->save();

//Using the model for your query above this is how you can send an update:
UserLobbyInfo::where('userid', '=', Auth::User()->id)
        ->where('lobby', '=', Request::get('lobbyid'))
        ->update([ 'typing' => $level ]);

3. 创建预先包含CRUD相关方法的控制器 这个命令将创建一个控制器,其中包含您在CRUD应用程序中通常使用的所有方法(Index,show,create,save,edit,update,delete)。

php artisan make:controller UserLobbyController --resource

在这些函数中,您需要添加相应的模型和所需方法。 4. 添加所有传统CRUD应用程序中使用的路由,并链接到--resource方法 如果您使用--resource,您将能够使用资源函数,该函数将为您提供所有所需资源的路由。
Route::resource('userlobby', 'UserLobbyController');

你路由文件中的这一行代码将为CRUD应用程序创建以下常见路由。运行 "php artisan route:list |grep userlobby" 命令,即可看到这些路由:

|        | GET|HEAD  | userlobby                                | userlobby.index      | App\Http\Controllers\UserLobbyController@index                          | web                |
|        | POST      | userlobby                                | userlobby.store      | App\Http\Controllers\UserLobbyController@store                          | web                |
|        | GET|HEAD  | userlobby/create                         | userlobby.create     | App\Http\Controllers\UserLobbyController@create                         | web                |
|        | GET|HEAD  | userlobby/{userlobby}                    | userlobby.show       | App\Http\Controllers\UserLobbyController@show                           | web                |
|        | PUT|PATCH | userlobby/{userlobby}                    | userlobby.update     | App\Http\Controllers\UserLobbyController@update                         | web                |
|        | DELETE    | userlobby/{userlobby}                    | userlobby.destroy    | App\Http\Controllers\UserLobbyController@destroy                        | web                |
|        | GET|HEAD  | userlobby/{userlobby}/edit               | userlobby.edit       | App\Http\Controllers\UserLobbyController@edit                           | web                |

5. 将您的控制器压缩为CRUD方法 由于这可能会变得很冗长,因此我将仅提供以下编辑和更新方法。希望这能让您了解如何分解控制器:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\UserLobbyInfo;  // Add this to access your new model
use App\Http\Requests;

class UserLobbyController extends Controller
{

    /**
     * Show the form for editing the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function edit($id)
    {
        $updateLobby = UserLobbyInfo::where('id', '=', $id)->first(); //This queries the table specifically for the id, just for demo purposes.

        return view('lobbies.edit', compact('updateLobby')); //This will send the above defined array to your view to pre-populate.
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, $id)
    {
        $userLobby = UserLobbyInfo::where('userid', '=', Auth::User()->id)
            ->where('lobby', '=', $request->lobbyid)->first();

         //Grab the UserLobby row you want to update.
        $updateLobby->typing = $level; //update the typing value
        $updateLobby->save(); // save it.
    }

对于更复杂的应用程序,我通常会将较重的控制器逻辑迁移到一个类中,并在控制器中使用该类引用。仅当我编写具有多个表连接的复杂查询(尤其是需要在该连接中使用多个where子句的连接)时,才使用DB::类。希望这可以帮助您了解如何在Laravel中正确使用模型。许多信息都可以在Laravel文档中找到。我还喜欢这个速查表:laravel cheatsheet。如果您有更多问题或者我没有完全回答您的问题,只需让我知道即可。

那么在控制器中留下逻辑和查询是可以的吗?因为我得到了不同的想法。 - Shawn31313
在某个阶段,您将不得不将逻辑传递到控制器中。我通常尝试保持控制器中的方法少于10行代码。如果您只是更新表中的一行并具有用于查询该数据的简单方法,则我会将其保留在控制器中。如果您需要复杂的逻辑来从多个行检索数据,或者需要使用大型多表查询在视图中使用,则建议将其移动到自己的类中,然后在控制器中使用该类。特别是如果您要在多个控制器中重复使用函数,则更是如此。 - Dom DaFonte
明白了。那么操作结果怎么样呢?例如,在我的一个控制器中,我拉取数据,然后对其进行一些条件判断和修改。 - Shawn31313
我在一些控制器中操作结果。例如,我必须创建相册的控制器,如果用户的记录不存在,则创建一个文件夹并将记录添加到相册表中。代码位于我的AlbumsController的upload()方法中。我可以将其放入名为Albums的类中,然后通过调用use App/Classes/Album将该类添加到控制器中,但这是唯一一个我调用以执行此功能的控制器,而且代码不多。如果我想在许多控制器中创建相册,那么我就必须考虑将其移动到一个类中。希望这个例子有所帮助。 - Dom DaFonte

1

使用Eloquent代替原始的SQL查询或者Query Builder查询。将所有与数据相关的逻辑放到Model类中:

public function getApprovedUsersWithPosts()
{
    return $this->where('approved', true)->with('posts')->get();
}

你的控制器应该尽量精简。不要在控制器中放置查询或其他逻辑。另外,使用依赖注入而不是门面模式:

protected $user;

public function __construct(User $user)
{
    $this->user = $user;
}

public function index()
{
    return view('users.approved', [
        'users' => $this->user->getApprovedUsers()
    ]);
}

那么模型应该严格专注于从数据库获取数据,而不是操纵数据?我认为操纵数据的工作应该由控制器来完成。 - Shawn31313

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接