【问题标题】:Laravel Many To Many Relationship issueLaravel 多对多关系问题
【发布时间】:2014-11-11 01:46:51
【问题描述】:

我是 Laravel 的新手。我从 github 代码修改了启动应用程序,以将给定的帖子详细信息保存到数据库中。 但面临以下2个问题

  1. 在逗号之前输入的第一个值仅插入到数据库中。我认为因为在关系表中只插入一条记录。
  2. 在编辑帖子中,类别显示为 json 结构

我已经为多对多关系建立了一个数据库。

帖子、类别和categories_post

创建了一个表单来添加/编辑帖子

<form class="form-horizontal" method="post" action="@if (isset($post)){{ URL::to('admin/blogs/' . $post->id . '/edit') }}@endif" autocomplete="off">
        <!-- CSRF Token -->
        <input type="hidden" name="_token" value="{{{ csrf_token() }}}" />
        <!-- ./ csrf token -->

        <!-- Tabs Content -->
        <div class="tab-content">
            <!-- General tab -->
            <div class="tab-pane active" id="tab-general">
                <!-- Post Title -->
                <div class="form-group {{{ $errors->has('title') ? 'error' : '' }}}">
                    <div class="col-md-12">
                        <label class="control-label" for="title">Post Title</label>
                        <input class="form-control" type="text" name="title" id="title" value="{{{ Input::old('title', isset($post) ? $post->title : null) }}}" />
                        {{{ $errors->first('title', '<span class="help-block">:message</span>') }}}
                    </div>
                </div>
                <div class="form-group {{{ $errors->has('categories') ? 'error' : '' }}}">
                    <div class="col-md-12">
                        <label class="control-label" for="categories">Categories</label>
                        <input class="form-control" type="text" name="categories" id="categories" value="{{{ Input::old('categories', isset($post) ? $post->categories : null) }}}" />
                        {{{ $errors->first('categories', '<span class="help-block">:message</span>') }}}
                    </div>
                </div>
                <!-- ./ post title -->

                <!-- Content -->
                <div class="form-group {{{ $errors->has('content') ? 'has-error' : '' }}}">
                    <div class="col-md-12">
                        <label class="control-label" for="content">Content</label>
                        <textarea class="ckeditor" name="content" value="content" rows="10">{{{ Input::old('content', isset($post) ? $post->content : null) }}}</textarea>
                        {{{ $errors->first('content', '<span class="help-block">:message</span>') }}}
                    </div>
                </div>
                <!-- ./ content -->
            </div>
            <!-- ./ general tab -->
        </div>
        <!-- ./ tabs content -->

        <!-- Form Actions -->
        <div class="form-group">
            <div class="col-md-12">
                <element class="btn-cancel close_popup">Cancel</element>
                <button type="reset" class="btn btn-default">Reset</button>
                <button type="submit" class="btn btn-success">Update</button>
            </div>
        </div>
        <!-- ./ form actions -->
    </form>

这是控制器代码

// Start transaction!
        DB::beginTransaction();

        $title = Input::get('title');
        $categoriesString = Input::get('categories');
        $categories = explode(',', $categoriesString);
        $postDetails = $this->post->findByTitle($title);
        if($postDetails)
        {
            return Redirect::to('blog/create')->withInput()->withErrors(array('title' => 'Title already exists'));
        } else {
            // Update the blog post data
            $this->post->title            = $title;
            $this->post->slug             = Str::slug(Input::get('title'));
            $this->post->content          = Input::get('content');
        }

        try 
        { // Validate, then create if valid
            $newPost = $this->post->save();
        } catch(ValidationException $e)
        {
            // Rollback and then redirect
            // back to form with errors
            DB::rollback();
            return Redirect::to('admin/blogs/create')->with('error', Lang::get('admin/blogs/messages.create.error'));
        } catch(\Exception $e)
        {
            DB::rollback();
            throw $e;
        }

以逗号分隔的类别与表格

        $categoriesString = Input::get('categories');
        $categories = explode(',', $categoriesString);

然后检查该类别是否已存在于数据库中。如果存在,则获取它的 id 并附加到新数组。

        $categoryClass = new Categories();
        $categoryIds = array();
        foreach($categories as $category)
        {
            try {
                // Validate, then create if valid
                $categoryName = strtolower($category);
                $categoryDetails = $categoryClass->findByName($categoryName);
                if($categoryDetails)
                {
                    $categoryId = $categoryDetails->id;
                } else {    
                    $categoryClass->name = $category;
                    $categoryClass->save();
                    $categoryId = $categoryClass->id;
                } 
            } catch(ValidationException $e)
            {
                // Rollback and then redirect
                // back to form with errors
                DB::rollback();
                return Redirect::to('blog/create')->with('error', Lang::get('blog/messages.create.error'));
            } catch(\Exception $e)
            {
                DB::rollback();
                throw $e;
            }

            // Push category id into category id's array
            $categoryIds[] = $categoryId;
        }

        //Then sync the categories with new categories  
        $this->post->categories()->sync($categoryIds);

        // Commit
        DB::commit();

        return Redirect::to('blog/' . $this->post->id . '/edit')->with('success', Lang::get('blog/messages.create.success'));

POST 模型

    /**
     * Get the post's categories.
     *
     * @return array
     */
    public function categories()
    {
        return $this->belongsToMany('Categories');
    }

类别模型

    /**
     * Get the Categories's posts.
     *
     * @return array
     */
    public function posts()
    {
        return $this->belongsToMany('Post');
    }

请有人帮我解决这个问题。

【问题讨论】:

    标签: php mysql laravel laravel-4


    【解决方案1】:

    这样做会轻松得多。这就是我存储文章的方式,标签可以用逗号分隔。

    文章控制器存储功能: 首先创建文章对象,将 user_id 设置为当前用户会话 id 并填写表单中的所有字段。如果文章在标签模型中使用静态方法保存附加标签。

    public function store()
    {
        $article = new Article();
        $article->user_id = Auth::id();
        $article->fill(Input::all());
    
        if ($article->save())
        {
            Tag::attach($article, Input::get('tags'));
    
            return Redirect::route('articles.index')
                ->with(['flashMessage' => 'Article created.', 'flashType' => 'success']);
        } else {
            return Redirect::back()->withErrors($article->errors())->withInput();
        }
    }
    

    文章模型,设置可填充属性和标签关系:

    protected $fillable = ['category_id', 'title', 'description', 'content', 'published'];
    
    public function tags()
    {
        return $this->belongsToMany('Tag', 'article_tag', 'article_id', 'tag_id');
    }
    

    标签模型文章关系:

    public function articles()
    {
        return $this->belongsToMany('Article', 'article_tag', 'tag_id', 'article_id');
    }
    

    标签模型attach shope: 首先创建一个空数组来保存标签,分解逗号分隔的标签并枚举它们。修剪分解的标签以消除空格。从标签表中获取TagID,如果为空(表示标签不存在)创建它。将每个 TagID 添加到 tags 数组中,最后将文章模型与 tags 数组同步。

    public function scopeAttach($query, $model, $tags)
    {
        $returnTags = array();
    
        foreach (explode(',', $tags) as $tag)
        {
            $tag = trim(Str::slug($tag));
    
            if ($tag != '')
            {
                $tagID = Tag::where('name', '=', $tag)->pluck('id');
    
                if (empty($tagID))
                {
                    $tagNew = new Tag;
                    $tagNew->name = $tag;
                    $tagNew->save();
    
                    $tagID = $tagNew->id;
                }
    
                $returnTags[] = $tagID;
            }
        }
    
        $model->tags()->sync($returnTags);
    }
    

    View presenter implode tags 函数: 枚举所有标签并 implode 为逗号分隔的字符串。

    public function implodeTags()
    {
        $returnString = null;
    
        foreach ($this->tags as $tag)
        {
            if (!empty($returnString)) $returnString .= ", ";
            $returnString .= $tag->name;
        }
    
        return $returnString;
    }
    

    创建/编辑刀片视图:首先打开新表单以创建或与模型绑定以进行编辑。如果创建;显示没有值的输入字段。如果编辑;使用 View Presenter 中的 implodeTags 函数用逗号分隔的标签列表填充文本字段。

    @if (!isset($edit))
      @section('title', 'Create article')
      {{ Form::open(array('route' => 'articles.store', 'role' => 'form')) }}
    @else
      @section('title', 'Edit article')
      {{ Form::model($article, array('method' => 'PUT', 'route' => ['articles.update', $article->id], 'role' => 'form')) }}
    @endif
    
    ...
    
    <div class="form-group @if ($errors->has('tags')) has-error @endif">
        {{ Form::label('tags', 'Tags') }}
        @if(!isset($article))
            {{ Form::text('tags', null, array('class' => 'form-control')) }}
        @else
            {{ Form::text('tags', $article->present()->implodeTags, array('class' => 'form-control')) }}
        @endif
        @if ($errors->has('tags')) <p class="help-block">{{ $errors->first('tags') }}</p> @endif
    </div>
    
    ...
    

    显然创建/编辑视图包含的不止这些,但这些都是与标签实现相关的部分。

    【讨论】:

    • 但是编辑画面有问题。你能建议你在编辑屏幕上的表现吗
    • 我已更新我的答案以包括我的视图演示者和与标签实现相关的创建/编辑视图的部分。如果您要使用视图演示器,请阅读它的安装和配置文档。
    猜你喜欢
    • 2015-09-14
    • 2019-05-06
    • 2014-05-24
    • 2019-11-25
    • 1970-01-01
    • 2015-04-28
    • 2017-07-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多