如何从具有父子关系的模型中获取下一个和上一个记录

时间:2018-03-23 14:12:25

标签: php laravel laravel-5 orm model

我的模型中有一个父子关系,其中parent可以包含多个子部分。所以在我的模型中,我已将表格加入到自身并使用Section列,我可以确定哪个部分是父/子。

我的问题是如何检索子节的下一个和上一个记录?

我的 class Section extends Model { use BelongsToSortedManyTrait, SortableTrait; public $fillable = [ 'id', 'name', 'description', 'parent', 'position' ]; public function subsections() { return $this->hasMany(self::class, 'parent')->sorted(); } public function next(){ // get next record return self::where('id', '>', $this->id)->orderBy('id','asc')->first(); } public function previous(){ // get previous record return self::where('id', '<', $this->id)->orderBy('id','desc')->first(); } } 型号:

// basic concrete ICommand implementation
abstract class CommandBase : ICommand
{
    public event EventHandler CanExecuteChanged;

    protected void OnCanExecuteChanged ( ) => CanExecuteChanged?.Invoke ( this, EventArgs.Empty );

    public virtual bool CanExecute ( object parameter ) => true;

    public abstract void Execute ( object parameter );
}

// Now, a more specialized command. 
class GenerateReportCommand : CommandBase
{
    // In the GOF version of the Command pattern, you inject the context in the command's constructor
    public GenerateRepportCommand ( MainViewModel context )
    {
        _context = context;

        // The viewmodel will tell us when to refresh our CanExecute
        context.PropertyChanged += ( sender, e ) => OnCanExecuteChanged ( );
    }

    private MainViewModel _context;

    public override bool CanExecute ( object parameter ) =>    !string.IsNullOrWhiteSpace ( _context.Item1 ) 
                                                            && !string.IsNullOrWhiteSpace ( _context.Item2 );

    public override void Execute ( object parameter )
    {

        // someDependency.GenerateReport ( _context.Item1, _context.Item2 );
    }
}

// Now for the viewmodel side of things
class MainViewModel : ViewModelBase
{
    public MainViewModel ( )
    {
        // You could inject your "report generating" dependencies through here
        GenerateReport = new GenerateReportCommand ( this );
    }

    public string Item1 { get { return _item1; }
                          set { _item1 = value; OnPropertyChanged ( ); } }
    private string _item1;

    public string Item2 { get { return _item2; }
                          set { _item2 = value; OnPropertyChanged ( ); } }
    private string _item2;

    public ICommand GenerateReport { get; private set; }
}

注意上一个和下一个方法,目前它们适用于所有部分,但不会考虑父/子关系。

我能以任何方式实现这一目标吗?

2 个答案:

答案 0 :(得分:0)

这尚未经过测试,但请尝试:

self::where('parent', $this->parent)
    ->where('id', '<', $this->id)
    ->orderBy('id','desc')
    ->first();

将父项添加到查询中会将下一个值限制为具有相同父ID的那些值。然后你就可以这样使用:

$subsection = Section::find(2);
$next = $subsection->next();
$prev = $subsection->previous();

此外,最好使下一个和上一个父查询可选:

public function next($parent = false) {
    $query = self::query();

    if ($parent) {
        $query = $query->where('parent', $this->parent);
    }

    $query = $query->where('id', '<', $this->id)
    ->orderBy('id','desc')
    ->first();
}

这将允许您检查下一节和上一节以及小节。

一切顺利。

更新(API解决方案 - 尚未经过测试)

$section = Section::find($id); // Whatever the section id is;

$subsection = Section::where('parent', $section->id)->first();

return [
    'section'         => $section,
    'next_section'    => $section->next()->id,
    'prev_section'    => $section->prev()->id,
    'subsection'      => $subsection,
    'next_subsection' => $subsection->next(true)->id,
    'prev_subsection' => $subsection->prev(true)->id,
];

在下一节调用中,您可以传递子节ID并在返回api之前运行next / prev:

$subsection = Section::find(1)->next();

答案 1 :(得分:0)

试试这个:

public function next(){
    $id = $this->parent ?: $this->id;
    return self::where('id', '>', $id)->orderBy('id','asc')->first();
}

public  function previous(){
    $id = $this->parent ?: $this->id;
    return self::where('id', '<', $id)->orderBy('id','desc')->first();
}