วิธีที่ดีที่สุดสำหรับประสิทธิภาพเมื่อกรองการอนุญาตใน Laravel


9

ฉันกำลังทำงานกับแอปพลิเคชันที่ผู้ใช้สามารถเข้าถึงหลายรูปแบบผ่านสถานการณ์ที่แตกต่างกัน ฉันกำลังพยายามสร้างวิธีการด้วยประสิทธิภาพที่ดีที่สุดเมื่อส่งคืนดัชนีของฟอร์มให้กับผู้ใช้

ผู้ใช้สามารถเข้าถึงแบบฟอร์มผ่านสถานการณ์ต่อไปนี้:

  • แบบฟอร์มเป็นเจ้าของ
  • ทีมเป็นเจ้าของแบบฟอร์ม
  • มีสิทธิ์ให้กับกลุ่มที่เป็นเจ้าของแบบฟอร์ม
  • มีสิทธิ์ให้กับทีมที่เป็นเจ้าของฟอร์ม
  • ได้รับอนุญาตให้ใช้แบบฟอร์ม

อย่างที่คุณเห็นมี 5 วิธีที่เป็นไปได้ที่ผู้ใช้สามารถเข้าถึงแบบฟอร์ม ปัญหาของฉันคือฉันจะส่งคืนแบบฟอร์มที่สามารถเข้าถึงได้ให้กับผู้ใช้อย่างมีประสิทธิภาพมากที่สุดอย่างไร

นโยบายแบบฟอร์ม:

ฉันพยายามรับแบบฟอร์มทั้งหมดจากแบบจำลองแล้วกรองแบบฟอร์มตามนโยบายแบบฟอร์ม ดูเหมือนว่าจะเป็นปัญหาด้านประสิทธิภาพเนื่องจากการทำซ้ำในตัวกรองแต่ละครั้งแบบฟอร์มจะถูกส่งผ่านเมธอดที่ประกอบด้วย () eloquent 5 ครั้งดังแสดงด้านล่าง แบบฟอร์มเพิ่มเติมในฐานข้อมูลหมายความว่าสิ่งนี้ช้าลง

FormController@index

public function index(Request $request)
{
   $forms = Form::all()
      ->filter(function($form) use ($request) {
         return $request->user()->can('view',$form);
   });
}
FormPolicy@view

public function view(User $user, Form $form)
{
   return $user->forms->contains($form) ||
      $user->team->forms->contains($form) ||
      $user->permissible->groups->forms($contains);
}

ถึงแม้ว่าวิธีการข้างต้นจะเป็นคอขวดประสิทธิภาพ

จากสิ่งที่ฉันเห็นตัวเลือกต่อไปนี้คือ:

  • ตัวกรอง FormPolicy (วิธีการปัจจุบัน)
  • สอบถามสิทธิ์ทั้งหมด (5) และรวมเข้าในคอลเล็กชันเดี่ยว
  • สอบถามตัวระบุทั้งหมดสำหรับการอนุญาตทั้งหมด (5) จากนั้นสอบถามรูปแบบฟอร์มโดยใช้ตัวระบุในคำสั่งIN ()

คำถามของฉัน:

วิธีใดที่จะให้ประสิทธิภาพที่ดีที่สุดและมีตัวเลือกอื่นใดที่จะให้ประสิทธิภาพที่ดีกว่า


คุณยังสามารถใช้วิธีการเชื่อมต่อแบบหลายต่อหลายคนเพื่อเชื่อมโยงหากผู้ใช้สามารถเข้าถึงแบบฟอร์ม
รหัสสำหรับเงิน

สิ่งที่เกี่ยวกับการสร้างตารางโดยเฉพาะสำหรับการสอบถามสิทธิ์แบบฟอร์มผู้ใช้? user_form_permissionตารางที่มีเพียงและuser_id form_idสิ่งนี้จะทำให้สิทธิ์การอ่านเป็นเรื่องง่าย แต่การอัปเดตสิทธิ์จะยากขึ้น
PtrTon

ปัญหาเกี่ยวกับตาราง user_form_permissions คือเราต้องการขยายการอนุญาตไปยังเอนทิตีอื่นซึ่งจะต้องใช้ตารางแยกต่างหากสำหรับแต่ละเอนทิตี
ทิม

1
@Tim แต่ก็ยังมี 5 ข้อความค้นหา หากนี่เป็นเพียงภายในพื้นที่ของสมาชิกที่ได้รับการป้องกันอาจไม่เป็นปัญหา แต่ถ้านี่เป็น URL สาธารณะที่สามารถได้รับการร้องขอจำนวนมากต่อวินาทีผมก็จำได้ว่าคุณต้องการเพิ่มประสิทธิภาพสักหน่อย ด้วยเหตุผลด้านประสิทธิภาพฉันจะรักษาตารางแยกต่างหาก (ที่ฉันสามารถแคช) ทุกครั้งที่มีการเพิ่มหรือลบสมาชิกในทีมหรือแบบฟอร์มผ่านผู้สังเกตการณ์โมเดล จากนั้นทุกคำขอฉันจะได้รับจากแคช ฉันพบว่าคำถามและปัญหานี้น่าสนใจมากและอยากรู้ว่าคนอื่นคิดอย่างไร คำถามนี้สมควรได้รับการโหวตมากขึ้นและคำตอบเริ่มโปรดปราน :)
ราอูล

1
คุณสามารถพิจารณาให้มีมุมมองที่เป็นรูปธรรมซึ่งคุณสามารถรีเฟรชเป็นงานตามกำหนดเวลาได้ วิธีนี้คุณสามารถรับผลลัพธ์ที่รวดเร็วได้อย่างรวดเร็ว
apokryfos

คำตอบ:


2

ฉันจะดูทำแบบสอบถาม SQL เป็นที่จะทำงานได้ดีกว่า php

บางสิ่งเช่นนี้

User::where('id', $request->user()->id)
    ->join('group_users', 'user.id', 'group_users.user_id')
    ->join('team_users', 'user.id', 'team_users.user_id',)
    ->join('form_owners as user_form_owners', function ($join) {
        $join->on('users.id', 'form_owners.owner_id')
            ->where('form_owners.owner_type', User::class);
    })
    ->join('form_owners as group_form_owners', function ($join) {
        $join->on('group_users.group_id', 'form_owners.owner_id')
            ->where('form_owners.owner_type', Group::class);
    })
    ->join('form_owners as team_form_owners', function ($join) {
        $join->on('team_users.team_id', 'form_owners.owner_id')
           ->where('form_owners.owner_type', Team::class);
    })
    ->join('forms', function($join) {
        $join->on('forms.id', 'user_form_owners.form_id')
            ->orOn('forms.id', 'group_form_owners.form_id')
            ->orOn('forms.id', 'team_form_owners.form_id');
    })
    ->selectRaw('forms.*')
    ->get();

จากด้านบนของหัวของฉันและยังไม่ทดลองสิ่งนี้ควรให้คุณทุกรูปแบบที่เป็นของผู้ใช้กลุ่มของเขาและทีมนี้

อย่างไรก็ตามมันไม่ได้ดูที่สิทธิ์ของผู้ใช้ดูแบบฟอร์มในกลุ่มและทีม

ฉันไม่แน่ใจว่าคุณได้ตั้งค่าการตรวจสอบสิทธิ์ของคุณอย่างไรและคุณจะต้องแก้ไขแบบสอบถามสำหรับสิ่งนี้และความแตกต่างใด ๆ ในโครงสร้าง DB ของคุณ


ขอบคุณสำหรับคำตอบ. อย่างไรก็ตามปัญหาไม่ใช่แบบสอบถามเกี่ยวกับวิธีรับข้อมูลจากฐานข้อมูล ปัญหาคือจะทำอย่างไรให้มีประสิทธิภาพทุกครั้งในทุกคำขอเมื่อแอพมีแบบฟอร์มนับแสนฟอร์มทีมและสมาชิกมากมาย การเข้าร่วมของคุณมีส่วนORคำสั่งซึ่งฉันสงสัยว่าจะช้า ดังนั้นการกดปุ่มนี้ทุกครั้งที่ฉันขอเชื่อจะทำให้เสียสติ
ราอูล

คุณอาจจะได้รับความเร็วที่ดีขึ้นด้วยการสืบค้น MySQL แบบดิบหรือใช้บางอย่างเช่นมุมมองหรือขั้นตอน แต่คุณจะต้องทำการเรียกเช่นนี้ทุกครั้งที่คุณต้องการข้อมูล การแคชผลลัพธ์อาจช่วยได้ที่นี่
Josh

ในขณะที่ฉันกำลังคิดว่าวิธีเดียวที่จะทำให้นักแสดงคนนี้คือแคชซึ่งมาพร้อมกับค่าใช้จ่ายในการบำรุงรักษาแผนที่นี้ทุกครั้งที่มีการเปลี่ยนแปลง ลองนึกภาพฉันสร้างแบบฟอร์มใหม่ซึ่งหากทีมได้รับมอบหมายให้บัญชีของฉันหมายความว่าผู้ใช้หลายพันคนอาจเข้าถึงได้ อะไรต่อไป? แคชนโยบายสมาชิกสองสามพันอีกครั้งหรือไม่
Raul

มีวิธีแก้ปัญหาแคชพร้อมอายุการใช้งาน (เช่น abstractions แคชของ laravel) และคุณยังสามารถลบดัชนีแคชที่ได้รับผลกระทบทันทีหลังจากที่คุณทำการเปลี่ยนแปลงใด ๆ แคชเป็นตัวเปลี่ยนเกมจริงหากคุณใช้อย่างถูกต้อง วิธีกำหนดค่าแคชขึ้นอยู่กับการอ่านและการอัพเดตข้อมูล
กอนซาโล่

2

คำตอบสั้น ๆ

ตัวเลือกที่สาม: Query all identifiers for all permissions (5), then query the Form model using the identifiers in an IN() statement

$teamMorphType  = Relation::getMorphedModel('team');
$groupMorphType = Relation::getMorphedModel('group');
$formMorphType  = Relation::getMorphedModel('form');

$permissible = [
    $teamMorphType  => [$user->team_id],
    $groupMorphType => [],
    $formMorphType  => [],
];

foreach ($user->permissible as $permissible) {
    switch ($permissible->permissible_type) {
        case $teamMorphType:
        case $groupMorphType:
        case $formMorphType:
            $permissible[$permissible->permissible_type][] = $permissible->permissible_id;
            break;
    }
}

$forms = Form::query()
             ->where('user_id', '=', $user->id)
             ->orWhereIn('id', $permissible[$fromMorphType])
             ->orWhereIn('team_id', $permissible[$teamMorphType])
             ->orWhereIn('group_id', $permissible[$groupMorphType])
             ->get();

คำตอบที่ยาว

ในอีกด้านหนึ่ง (เกือบ) ทุกสิ่งที่คุณสามารถทำได้ในโค้ดนั้นดีกว่าประสิทธิภาพการทำงานมากกว่าในคิวรี

ในทางกลับกันการรับข้อมูลเพิ่มเติมจากฐานข้อมูลเกินความจำเป็นจะเป็นข้อมูลมากเกินไปแล้ว (การใช้ RAM และอื่น ๆ )

จากมุมมองของฉันคุณต้องการบางสิ่งบางอย่างในระหว่างและมีเพียงคุณเท่านั้นที่จะรู้ว่ายอดเงินจะขึ้นอยู่กับตัวเลข

ฉันขอแนะนำให้เรียกใช้หลาย ๆ คำค้นหาตัวเลือกสุดท้ายที่คุณเสนอ ( Query all identifiers for all permissions (5), then query the Form model using the identifiers in an IN() statement):

  1. สอบถามตัวระบุทั้งหมดสำหรับการอนุญาตทั้งหมด (5 ข้อความค้นหา)
  2. ผสานผลลัพธ์ทั้งหมดในหน่วยความจำและรับค่าที่ไม่ซ้ำใคร array_unique($ids)
  3. เคียวรีโมเดล Form โดยใช้ตัวระบุในคำสั่ง IN ()

คุณสามารถลองใช้สามตัวเลือกที่คุณเสนอและตรวจสอบประสิทธิภาพโดยใช้เครื่องมือบางอย่างเพื่อเรียกใช้แบบสอบถามหลายครั้ง แต่ฉันมั่นใจว่า 99% ว่าตัวสุดท้ายจะให้ประสิทธิภาพที่ดีที่สุด

สิ่งนี้อาจเปลี่ยนไปมากขึ้นอยู่กับฐานข้อมูลที่คุณใช้ แต่ถ้าเรากำลังพูดถึง MySQL เป็นต้น ในแบบสอบถามที่มีขนาดใหญ่มากจะใช้ทรัพยากรฐานข้อมูลมากขึ้นซึ่งจะไม่เพียง แต่ใช้เวลามากกว่าแบบสอบถามธรรมดา แต่ยังจะล็อกตารางจากการเขียนและสิ่งนี้สามารถสร้างข้อผิดพลาดการหยุดชะงัก (เว้นแต่คุณจะใช้เซิร์ฟเวอร์ทาส)

ในอีกด้านหนึ่งถ้าจำนวนของแบบฟอร์มรหัสมีขนาดใหญ่มากคุณสามารถมีข้อผิดพลาดสำหรับตัวยึดตำแหน่งมากเกินไปดังนั้นคุณอาจต้องการแยกกลุ่มข้อความค้นหาเป็นกลุ่มสมมติว่า 500 รหัส (ขึ้นอยู่กับข้อ จำกัด มาก มีขนาดไม่ใช่จำนวนการผูกข้อมูล) และผสานผลลัพธ์ในหน่วยความจำ แม้ว่าคุณจะไม่ได้รับข้อผิดพลาดของฐานข้อมูลคุณอาจเห็นความแตกต่างของประสิทธิภาพการทำงานที่ดีเช่นกัน (ฉันยังคงพูดถึง MySQL)


การดำเนินงาน

ฉันจะสมมติว่านี่เป็นโครงร่างฐานข้อมูล:

users
  - id
  - team_id

forms
  - id
  - user_id
  - team_id
  - group_id

permissible
  - user_id
  - permissible_id
  - permissible_type

ดังนั้นได้รับอนุญาตจะมีการกำหนดค่าแล้วความสัมพันธ์ polymorphic

ดังนั้นความสัมพันธ์จะเป็น:

  • แบบฟอร์มเป็นเจ้าของ: users.id <-> form.user_id
  • ทีมเป็นเจ้าของแบบฟอร์ม: users.team_id <-> form.team_id
  • มีสิทธิ์ให้กับกลุ่มที่เป็นเจ้าของแบบฟอร์ม: permissible.user_id <-> users.id && permissible.permissible_type = 'App\Team'
  • มีสิทธิ์ให้กับทีมที่เป็นเจ้าของฟอร์ม: permissible.user_id <-> users.id && permissible.permissible_type = 'App\Group'
  • ได้รับอนุญาตให้ใช้แบบฟอร์ม: permissible.user_id <-> users.id && permissible.permissible_type = 'App\From'

ลดความซับซ้อนของเวอร์ชัน:

$teamMorphType  = Relation::getMorphedModel('team');
$groupMorphType = Relation::getMorphedModel('group');
$formMorphType  = Relation::getMorphedModel('form');

$permissible = [
    $teamMorphType  => [$user->team_id],
    $groupMorphType => [],
    $formMorphType  => [],
];

foreach ($user->permissible as $permissible) {
    switch ($permissible->permissible_type) {
        case $teamMorphType:
        case $groupMorphType:
        case $formMorphType:
            $permissible[$permissible->permissible_type][] = $permissible->permissible_id;
            break;
    }
}

$forms = Form::query()
             ->where('user_id', '=', $user->id)
             ->orWhereIn('id', $permissible[$fromMorphType])
             ->orWhereIn('team_id', $permissible[$teamMorphType])
             ->orWhereIn('group_id', $permissible[$groupMorphType])
             ->get();

รุ่นโดยละเอียด:

// Owns Form
// users.id <-> forms.user_id
$userId = $user->id;

// Team owns Form
// users.team_id <-> forms.team_id
// Initialise the array with a first value.
// The permissions polymorphic relationship will have other teams ids to look at
$teamIds = [$user->team_id];

// Groups owns Form was not mention, so I assume there is not such a relation in user.
// Just initialise the array without a first value.
$groupIds = [];

// Also initialise forms for permissions:
$formIds = [];

// Has permissions to a group that owns a Form
// permissible.user_id <-> users.id && permissible.permissible_type = 'App\Team'
$teamMorphType = Relation::getMorphedModel('team');
// Has permissions to a team that owns a Form
// permissible.user_id <-> users.id && permissible.permissible_type = 'App\Group'
$groupMorphType = Relation::getMorphedModel('group');
// Has permission to a Form
// permissible.user_id <-> users.id && permissible.permissible_type = 'App\Form'
$formMorphType = Relation::getMorphedModel('form');

// Get permissions
$permissibles = $user->permissible()->whereIn(
    'permissible_type',
    [$teamMorphType, $groupMorphType, $formMorphType]
)->get();

// If you don't have more permissible types other than those, then you can just:
// $permissibles = $user->permissible;

// Group the ids per type
foreach ($permissibles as $permissible) {
    switch ($permissible->permissible_type) {
        case $teamMorphType:
            $teamIds[] = $permissible->permissible_id;
            break;
        case $groupMorphType:
            $groupIds[] = $permissible->permissible_id;
            break;
        case $formMorphType:
            $formIds[] = $permissible->permissible_id;
            break;
    }
}

// In case the user and the team ids are repeated:
$teamIds = array_values(array_unique($teamIds));
// We assume that the rest of the values will not be repeated.

$forms = Form::query()
             ->where('user_id', '=', $userId)
             ->orWhereIn('id', $formIds)
             ->orWhereIn('team_id', $teamIds)
             ->orWhereIn('group_id', $groupIds)
             ->get();

ทรัพยากรที่ใช้:

ประสิทธิภาพของฐานข้อมูล:

  • แบบสอบถามไปยังฐานข้อมูล (ไม่รวมผู้ใช้): 2 ; หนึ่งที่จะได้รับอนุญาตและอีกหนึ่งที่จะได้รับแบบฟอร์ม
  • ไม่เข้าร่วม !!
  • ORs ต่ำสุดที่เป็นไปได้ user_id = ? OR id IN (?..) OR team_id IN (?...) OR group_id IN (?...)(

PHP ในหน่วยความจำประสิทธิภาพ:

  • foreachวนลูปที่อนุญาตด้วยสวิตช์ภายใน
  • array_values(array_unique()) เพื่อหลีกเลี่ยงรหัสซ้ำ
  • ในหน่วยความจำ 3 อาร์เรย์ของรหัส ( $teamIds, $groupIds,$formIds )
  • ในหน่วยความจำสิทธิ์ที่เกี่ยวข้องการรวบรวมพูดจา (นี้สามารถปรับให้เหมาะสมถ้าจำเป็น)

ข้อดีและข้อเสีย

ข้อดี:

  • เวลา : ผลรวมของการสืบค้นครั้งเดียวน้อยกว่าเวลาของการสืบค้นครั้งใหญ่ที่มีการรวมและ OR
  • ทรัพยากร DB : ทรัพยากร MySQL ที่ใช้โดยแบบสอบถามที่มีการเข้าร่วมและหรือข้อความสั่งนั้นใหญ่กว่าการใช้โดยผลรวมของข้อความค้นหาแยกต่างหาก
  • เงิน : ทรัพยากรฐานข้อมูลน้อยลง (ตัวประมวลผล RAM อ่านดิสก์ ฯลฯ ) ซึ่งมีราคาแพงกว่าทรัพยากร PHP
  • ล็อค : ในกรณีที่คุณไม่ได้สืบค้นเซิร์ฟเวอร์ทาสแบบอ่านอย่างเดียวการสืบค้นของคุณจะทำการล็อคแถวที่น้อยลง (ล็อกการอ่านถูกแชร์ใน MySQL ดังนั้นมันจะไม่ล็อคการอ่านอื่น แต่จะบล็อกการเขียนใด ๆ )
  • ปรับขนาดได้ : วิธีการนี้ช่วยให้คุณสามารถเพิ่มประสิทธิภาพได้มากขึ้นเช่นการสืบค้น

ข้อเสีย:

  • รหัสทรัพยากร : การคำนวณในรหัสแทนที่จะอยู่ในฐานข้อมูลจะใช้ทรัพยากรมากขึ้นอย่างชัดเจนในอินสแตนซ์ของรหัส แต่โดยเฉพาะอย่างยิ่งใน RAM การจัดเก็บข้อมูลกลาง ในกรณีของเรานี่จะเป็นรหัสประจำตัวซึ่งไม่น่าจะมีปัญหาจริงๆ
  • การบำรุงรักษา : หากคุณใช้คุณสมบัติและวิธีการของ Laravel และคุณทำการเปลี่ยนแปลงใด ๆ ในฐานข้อมูลจะเป็นการง่ายกว่าในการอัปเดตในโค้ดมากกว่าถ้าคุณทำการสอบถามและประมวลผลที่ชัดเจน
  • Overkilling? : ในบางกรณีหากข้อมูลไม่ใหญ่มากการปรับประสิทธิภาพให้เหมาะสมอาจทำให้เกินกำลัง

วิธีการวัดประสิทธิภาพ

เบาะแสบางอย่างเกี่ยวกับวิธีการวัดประสิทธิภาพ?

  1. บันทึกคิวรีช้า
  2. วิเคราะห์ตาราง
  3. แสดงสถานะเหมือนตาราง
  4. อธิบาย ; ขยายรูปแบบเอาท์พุทขยาย ; ใช้อธิบาย ; อธิบายผลลัพธ์
  5. แสดงคำเตือน

เครื่องมือทำโปรไฟล์ที่น่าสนใจ:


บรรทัดแรกนั้นคืออะไร? เป็นการดีกว่าหากใช้แบบสอบถามเนื่องจากการรันลูปหรือการปรับเปลี่ยนอาเรย์ต่างๆใน PHP นั้นช้ากว่า
Flame

หากคุณมีฐานข้อมูลขนาดเล็กหรือเครื่องฐานข้อมูลของคุณมีประสิทธิภาพมากกว่าอินสแตนซ์รหัสของคุณหรือเวลาแฝงของฐานข้อมูลแย่มากใช่แล้ว MySQL นั้นเร็วกว่า แต่ก็ไม่ได้เป็นเช่นนั้น
กอนซาโล่

เมื่อคุณปรับการสืบค้นฐานข้อมูลให้เหมาะสมคุณต้องพิจารณาเวลาดำเนินการจำนวนแถวที่ส่งคืนและที่สำคัญที่สุดคือจำนวนการตรวจสอบจำนวนแถว หากทิมบอกว่าการสืบค้นช้าลงฉันก็ถือว่าข้อมูลกำลังเพิ่มขึ้นดังนั้นจึงตรวจสอบจำนวนแถว นอกจากนี้ฐานข้อมูลไม่ได้รับการปรับให้เหมาะสมสำหรับการประมวลผลเนื่องจากเป็นภาษาโปรแกรม
กอนซาโล่

แต่คุณไม่จำเป็นต้องเชื่อฉันคุณสามารถเรียกใช้อธิบายสำหรับวิธีการแก้ปัญหาของคุณแล้วคุณสามารถเรียกใช้มันสำหรับการแก้ปัญหาของฉันของการค้นหาง่ายและเห็นความแตกต่างแล้วคิดว่าถ้าการที่ง่ายarray_merge()และarray_unique()พวงของรหัสก็จะ ทำให้กระบวนการของคุณช้าลงจริง ๆ
กอนซาโล่

ใน 9 จาก 10 กรณีฐานข้อมูล mysql ทำงานบนเครื่องเดียวกันกับที่รันโค้ด เลเยอร์ข้อมูลนั้นใช้สำหรับการดึงข้อมูลและปรับให้เหมาะสมสำหรับการเลือกข้อมูลจากชุดใหญ่ ฉันยังไม่เห็นสถานการณ์ที่ a array_unique()เร็วกว่า a GROUP BY/ SELECT DISTINCTstatement
Flame

0

เหตุใดคุณจึงไม่สามารถค้นหาฟอร์มที่คุณต้องการแทนที่จะทำForm::all()แล้วผูกมัดfilter()ฟังก์ชันหลังจากนั้น

ชอบมาก

public function index() {
    $forms = $user->forms->merge($user->team->forms)->merge($user->permissible->groups->forms);
}

ใช่แล้วนี่เป็นคำถามสองสามข้อ:

  • แบบสอบถามสำหรับ $user
  • หนึ่งสำหรับ $user->team
  • หนึ่งสำหรับ $user->team->forms
  • หนึ่งสำหรับ $user->permissible
  • หนึ่งสำหรับ $user->permissible->groups
  • หนึ่งสำหรับ $user->permissible->groups->forms

อย่างไรก็ตามด้านอาชีพคือคุณไม่จำเป็นต้องใช้นโยบายอีกต่อไปเนื่องจากคุณทราบว่า$formsอนุญาตให้ผู้ใช้ทุกรูปแบบในพารามิเตอร์

ดังนั้นวิธีนี้จะใช้ได้กับทุกรูปแบบที่คุณมีในฐานข้อมูล

หมายเหตุเกี่ยวกับการใช้ merge()

merge()ผสานการรวบรวมและจะทิ้งรหัสแบบฟอร์มที่ซ้ำกันซึ่งพบแล้ว ดังนั้นถ้าด้วยเหตุผลบางอย่างรูปแบบจาก teamความสัมพันธ์ก็เป็นความสัมพันธ์โดยตรงกับuserมันมันจะแสดงเพียงครั้งเดียวในคอลเลกชันที่ผสาน

นี่เป็นเพราะมันเป็นจริง Illuminate\Database\Eloquent\Collectionซึ่งมีmerge()ฟังก์ชั่นของตัวเองที่ตรวจสอบรหัสโมเดล Eloquent ดังนั้นคุณไม่สามารถใช้เคล็ดลับนี้เมื่อรวมเนื้อหาคอลเลกชันที่แตกต่างกัน 2 อย่างเช่นPostsและUsersเนื่องจากผู้ใช้ที่มี id 3และโพสต์ที่มี ID 3จะขัดแย้งกันในกรณีนี้และจะพบเฉพาะหลัง (โพสต์) ในคอลเล็กชันที่ผสาน


หากคุณต้องการให้เร็วยิ่งขึ้นคุณควรสร้างคิวรีที่กำหนดเองโดยใช้ DB facade ซึ่งเป็นไปตาม:

// Select forms based on a subquery that returns a list of id's.
$forms = Form::whereIn(
    'id',
    DB::select('id')->from('users')->where('users.id', $user->id)
        ->join('teams', 'users.id', '=', 'teams.user_id')
        ...
)->get();

ข้อความค้นหาจริงของคุณใหญ่กว่าเนื่องจากคุณมีความสัมพันธ์มากมาย

การปรับปรุงประสิทธิภาพหลักที่นี่มาจากความจริงที่ว่างานหนัก (แบบสอบถามย่อย) ข้ามตรรกะแบบจำลอง Eloquent อย่างสมบูรณ์ สิ่งที่เหลืออยู่ที่ต้องทำคือการส่งรายการของรหัสเข้าไปในwhereInฟังก์ชั่นเพื่อดึงรายการของFormวัตถุ


0

ฉันเชื่อว่าคุณสามารถใช้ Lazy Collections สำหรับ (Laravel 6.x) และอยากโหลดความสัมพันธ์ก่อนที่จะเข้าถึง

public function index(Request $request)
{
   // Eager Load relationships
   $request->user()->load(['forms', 'team.forms', 'permissible.group']);
   // Use cursor instead of all to return a LazyCollection instance
   $forms = Form::cursor()->filter(function($form) use ($request) {
         return $request->user()->can('view', $form);
   });
}
public function view(User $user, Form $form)
{
   return $user->forms->contains($form) ||
      $user->team->forms->contains($form) ||
      // $user->permissible->groups->forms($contains); // Assuming this line is a typo
      $user->permissible->groups->contains($form);
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.