如何更新PUT请求中的特定字段?

时间:2015-12-07 16:47:50

标签: laravel eloquent laravel-5.1

我有一个settings表格,用于存储网站标题,社交网络链接和其他内容...我可以通过设置缓存变量来完成所有操作。

现在,我的问题是,如何更新此表?例如......如果我有以下刀片形式:

{!! Form::model(config('settings'), ['class' => 's-form', 'route' => ['setting.update']]) !!}
{{ method_field('PUT') }}
<div class="s-form-item text">
    <div class="item-title required">Nome do site</div>
    {!! Form::text('title', null, ['placeholder' => 'Nome do site']) !!}
</div>
<div class="s-form-item text">
    <div class="item-title required">Descrição do site</div>
    {!! Form::text('desc', null, ['placeholder' => 'Descrição do site']) !!}
</div>
<div class="s-form-item s-btn-group s-btns-right">
    <a href="{{ url('admin') }}" class="s-btn cancel">Voltar</a>
    <input class="s-btn" type="submit" value="Atualizar">
</div>
{!! Form::close() !!}

PUT请求中,如何通过传递的每个名称在表中搜索并更新表?这是另一个文件:

路线

Route::put('/', ['as' => 'setting.update', 'uses' => 'Admin\AdminConfiguracoesController@update']);

控制器

class AdminConfiguracoesController extends AdminBaseController
{
    private $repository;

    public function __construct(SettingRepository $repository){
        $this->repository = $repository;
    }

    public function geral()
    {
        return view('admin.pages.admin.configuracoes.geral.index');
    }

    public function social()
    {
        return view('admin.pages.admin.configuracoes.social.index');
    }

    public function analytics()
    {
        return view('admin.pages.admin.configuracoes.analytics.index');
    }

    public function update($id, Factory $cache, Setting $setting)
    {
        // Update?

        $cache->forget('settings');

        return redirect('admin');
    }
}

存储库

class SettingRepository
{
    private $model;

    public function __construct(Setting $model)
    {
        $this->model = $model;
    }

    public function findByName($name){
        return $this->model->where('name', $name);
    }
}

模型

class Setting extends Model
{
    protected $table = 'settings';

    public $timestamps = false;

    protected $fillable = ['value'];
}

的ServiceProvider

class SettingsServiceProvider extends ServiceProvider
{
    public function boot(Factory $cache, Setting $settings)
    {
        $settings = $cache->remember('settings', 60, function() use ($settings)
        {
            return $settings->lists('value', 'name')->all();
        });

        config()->set('settings', $settings);
    }

    public function register()
    {
        //
    }
}

移植

class CreateSettingsTable extends Migration
{
    public function up()
    {
        Schema::create('settings', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name', 100)->unique();
            $table->text('value');
        });
    }

    public function down()
    {
        Schema::drop('settings');
    }
}

2 个答案:

答案 0 :(得分:2)

好的,一步一步。

首先,让我们考虑一下我们真正想要实现的目标,并在第二步中看看实施情况。

查看代码,我假设您要创建一组未定义的视图,其中包含用于更新某些设置的表单。对于用户来说,设置似乎是按组进行结构化的,例如“常规”,“社交”,“分析”,但您不会像这样在数据库中构建您的设置。您的设置基本上是一个简单的键/值存储,与某些设置组没有任何关系。

更新时,您需要一种处理所有设置的单一更新方法,而不管发送更新请求的形式。

我希望我的假设是正确的,如果我不是,请纠正我。

好的很酷,但是,来吧,我该如何实现呢?

与往常一样,可能有一千种方法可以实现这样的东西。我已经编写了一个示例应用程序,以解释我将如何实现它,我认为它非常 Laravelish (简而言之!)。

<强> 1。我应该如何存储我的数据?

我们已经谈过了。我们想要一个在数据库中持久存在的基本键/值存储。因为我们与Laravel合作,让我们为此创建一个模型和迁移:

php artisan make:model Setting --migration

这将创建一个模型和适当的迁移。让我们编辑迁移以创建键/值列:

<?php

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateSettingsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('settings', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->text('value');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::drop('settings');
    }

}

在设置模型中,我们必须将name列添加到可填充数组中。我将解释为什么我们需要在下面。基本上,我们想要使用一些不错的Laravel API,因此我们必须使name-attribute可填充。

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Setting extends Model {

    /**
     * @var array
     */
    protected $fillable = ['name'];

}

<强> 2。我如何访问设置数据?

我们讨论了这个in your last question,所以我不会详细介绍这个,我假装这个代码已经存在。我将在此示例中使用存储库,因此我将在开发期间更新SettingsServiceProvider

第3。创建存储库

为了使依赖关系更加松散耦合,我将创建一个接口(Laravel世界中的契约)并将其绑定到具体实现。然后我可以使用带有依赖注入的契约,Laravel将使用Service Container自动解决具体实现。也许这对你的应用程序来说太过分了,但无论我的应用程序有多大,我都喜欢编写可测试的代码。

app/Repositories/SettingRepositoryInterface.php

<?php

namespace App\Repositories;

interface SettingRepositoryInterface {

    /**
     * Update a setting or a given set of settings.
     *
     * @param string|array $key
     * @param string       $value
     *
     * @return void
     */
    public function update($key, $value);

    /**
     * List all available settings (name => value).
     *
     * @return array
     */
    public function lists();

}

如您所见,我们将使用存储库更新设置并在键/值数组中列出我们的设置。

具体实现(在本例中为Eloquent)如下所示:

app/Repositories/EloquentSettingRepository.php

<?php

namespace App\Repositories;

use App\Setting;

class EloquentSettingRepository implements SettingRepositoryInterface {

    /**
     * @var \App\Setting
     */
    private $settings;

    /**
     * EloquentSettingRepository constructor.
     *
     * @param \App\Setting $settings
     */
    public function __construct(Setting $settings)
    {
        $this->settings = $settings;
    }

    /**
     * Update a setting or a given set of settings.
     * If the first parameter is an array, the second parameter will be ignored
     * and the method calls itself recursively over each array item.
     *
     * @param string|array $key
     * @param string       $value
     *
     * @return void
     */
    public function update($key, $value = null)
    {
        if (is_array($key))
        {
            foreach ($key as $name => $value)
            {
                $this->update($name, $value);
            }

            return;
        }

        $setting = $this->settings->firstOrNew(['name' => $key]);
        $setting->value = $value;
        $setting->save();
    }

    /**
     * List all available settings (name => value).
     *
     * @return array
     */
    public function lists()
    {
        return $this->settings->lists('value', 'name')->all();
    }

}

DocBlocks几乎可以解释如何实现存储库。在更新方法中,我们使用firstOrNew方法。这就是为什么我们必须更新模型中的可填充数组。

现在让我们将接口绑定到该实现。在app/Providers/SettingsServiceProvider.php中,将其添加到register-method:

/**
 * Register any application services.
 *
 * @return void
 */
public function register()
{
    $this->app->bind(
        \App\Repositories\SettingRepositoryInterface::class,
        \App\Repositories\EloquentSettingRepository::class
    );
}

我们可以将此添加到AppServiceProvider,但由于我们的设置有专门的服务提供商,因此我们会将其用于绑定。

现在我们已经完成了存储库,我们可以更新SettingsServiceProvider的boot-method中的现有代码,以便它使用存储库而不是硬编码App\Setting

/**
 * Bootstrap the application services.
 *
 * @param \Illuminate\Contracts\Cache\Factory          $cache
 * @param \App\Repositories\SettingRepositoryInterface $settings
 */
public function boot(Factory $cache, SettingRepositoryInterface $settings)
{
    $settings = $cache->remember('settings', 60, function() use ($settings)
    {
        return $settings->lists();
    });

    config()->set('settings', $settings);
}

<强> 4。路线和控制器

在这个简单的示例中,主页将显示一个表单来更新某些设置。在同一路由上发出PUT / PATCH请求将触发更新方法:

<?php

get('/', ['as' => 'settings.index',  'uses' => 'Admin\SettingsController@index']);
put('/', ['as' => 'settings.update', 'uses' => 'Admin\SettingsController@update']);

我们控制器的索引方法将返回包含表单的视图。我已经对整个更新方法进行了评论,以解释每一行的作用:

app/Http/Controllers/Admin/SettingsController.php

<?php

namespace App\Http\Controllers\Admin;

use Illuminate\Contracts\Cache\Factory;
use Illuminate\Http\Request;
use App\Repositories\SettingRepositoryInterface;

class SettingsController extends AdminBaseController {

    /**
     * @var \App\Repositories\SettingRepositoryInterface
     */
    private $settings;

    /**
     * SettingsController constructor.
     *
     * @param \App\Repositories\SettingRepositoryInterface $settings
     */
    public function __construct(SettingRepositoryInterface $settings)
    {
        $this->settings = $settings;
    }

    /**
     * Shows the setting edit form.
     *
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
     */
    public function index()
    {
        return view('settings.index');
    }

    /**
     * Update the settings passed in the request.
     *
     * @param \Illuminate\Http\Request            $request
     * @param \Illuminate\Contracts\Cache\Factory $cache
     *
     * @return \Illuminate\Http\RedirectResponse
     */
    public function update(Request $request, Factory $cache)
    {
        // This will get all settings as a key/value array from the request.
        $settings = $request->except('_method', '_token');

        // Call the update method on the repository.
        $this->settings->update($settings);

        // Clear the cache.
        $cache->forget('settings');

        // Redirect to some page.
        return redirect()->route('settings.index')
            ->with('updated', true);
    }

}

请注意update方法中的第一个语句。除了方法和CSRF令牌之外,它将从请求中获取所有POST数据。 $settings现在是一个关联数组,其中包含您在表单中发送的设置。

<强> 5。最后,观点

对不起Bootstrap课程,但我想快速设置我的示例应用程序样式: - )

我认为HTML非常明显:

resources/views/settings/index.blade.php

@extends('layout')

@section('content')

    <h1>Settings example</h1>

    @if(Session::has('updated'))
        <div class="alert alert-success">
            Your settings have been updated!
        </div>
    @endif

    <form action="{!! route('settings.update') !!}" method="post">

        {!! method_field('put') !!}
        {!! csrf_field() !!}

        <div class="form-group">
            <label for="title">Title</label>
            <input type="text" class="form-control" id="title" name="title" placeholder="Title" value="{{ config('settings.title', 'Application Title') }}">
        </div>

        <div class="form-group">
            <label for="Facebook">Facebook</label>
            <input type="text" class="form-control" id="facebook" name="facebook" placeholder="Facebook URL" value="{{ config('settings.facebook', 'Facebook URL') }}">
        </div>

        <div class="form-group">
            <label for="twitter">Twitter</label>
            <input type="text" class="form-control" id="twitter" name="twitter" placeholder="Twitter URL" value="{{ config('settings.twitter', 'Twitter URL') }}">
        </div>

        <input type="submit" class="btn btn-primary" value="Update settings">

    </form>

@stop

正如您所看到的,当我尝试从配置中获取值时,我也会给它一个默认值,以防它尚未设置。

您现在可以为不同的设置组创建不同的表单。表单操作应始终为settings.update路径。

当我运行应用程序时,我可以看到具有默认值的表单:

No settings stored in the database.

当我输入一些值时,点击更新按钮,Laravel再次将我重定向到表单,我可以看到成功消息和我的设置现在仍然存在于数据库中。

Settings stored

答案 1 :(得分:0)

您可以注入Request课程。让我们更新title

// Injecting Illuminate\Http\Request object

public function update(Request $request, $id, Factory $cache, Setting $setting)
{
    $newTitle = $request->get('title');
    $cache->forget('settings');

    return redirect('admin');
}

要更改db中的值,可以执行以下操作:

$titleSetting = App\Setting::where('name', 'title')->first();
$titleSetting->value = $newTitle;
$titleSetting->save();

整个代码如下:

public function update(Request $request, $id)
{
    $newTitle = $request->get('title');
    \Cache::forget('settings');

    $titleSetting = App\Setting::where('name', 'title')->first();
    $titleSetting->value = $newTitle;
    $titleSetting->save();

    return redirect('admin');
}