นี่คือแพ็คเกจ Laravel 4-10 สำหรับการทำงานกับทรีในฐานข้อมูลเชิงสัมพันธ์
รองรับ Laravel 11.0 ตั้งแต่ v6.0.4
รองรับ Laravel 10.0 ตั้งแต่ v6.0.2
รองรับ Laravel 9.0 ตั้งแต่ v6.0.1
รองรับ Laravel 8.0 ตั้งแต่ v6.0.0
รองรับ Laravel 5.7, 5.8, 6.0, 7.0 ตั้งแต่ v5
รองรับ Laravel 5.5, 5.6 ตั้งแต่ v4.3
รองรับ Laravel 5.2, 5.3, 5.4 ตั้งแต่ v4
Laravel 5.1 รองรับในเวอร์ชัน 3
รองรับ Laravel 4 ในเวอร์ชัน 2
สารบัญ:
ทฤษฎี
เอกสารประกอบ
การแทรกโหนด
กำลังดึงโหนด
กำลังลบโหนด
การตรวจสอบและแก้ไขความสม่ำเสมอ
การกำหนดขอบเขต
ความต้องการ
การติดตั้ง
ชุดที่ซ้อนกันหรือโมเดลชุดที่ซ้อนกันเป็นวิธีการจัดเก็บข้อมูลแบบลำดับชั้นในตารางเชิงสัมพันธ์อย่างมีประสิทธิภาพ จากวิกิพีเดีย:
แบบจำลองชุดที่ซ้อนกันคือการกำหนดหมายเลขโหนดตามการสำรวจเส้นทางแบบต้นไม้ ซึ่งจะเข้าชมแต่ละโหนดสองครั้ง กำหนดหมายเลขตามลำดับการเยี่ยมชม และในการเข้าชมทั้งสองครั้ง ซึ่งจะเหลือตัวเลขไว้สองตัวสำหรับแต่ละโหนด ซึ่งจัดเก็บเป็นแอตทริบิวต์สองตัว การสืบค้นมีราคาไม่แพง: สามารถทดสอบความเป็นสมาชิกลำดับชั้นได้โดยการเปรียบเทียบตัวเลขเหล่านี้ การอัปเดตต้องมีการกำหนดหมายเลขใหม่จึงมีราคาแพง
NSM แสดงประสิทธิภาพที่ดีเมื่อมีการอัพเดตแผนผังน้อยครั้ง ได้รับการปรับแต่งให้รวดเร็วในการรับโหนดที่เกี่ยวข้อง เหมาะอย่างยิ่งสำหรับการสร้างเมนูหรือหมวดหมู่ที่หลากหลายสำหรับร้านค้า
สมมติว่าเรามีโมเดล Category
; ตัวแปร $node
เป็นอินสแตนซ์ของโมเดลนั้นและโหนดที่เรากำลังจัดการ อาจเป็นโมเดลใหม่หรือจากฐานข้อมูลก็ได้
โหนดมีความสัมพันธ์ต่อไปนี้ซึ่งทำงานได้อย่างสมบูรณ์และสามารถโหลดได้อย่างกระตือรือร้น:
โหนดเป็นของ parent
โหนดมี children
หลายคน
โหนดมี ancestors
มากมาย
โหนดมี descendants
มากมาย
การย้ายและการแทรกโหนดรวมถึงการสืบค้นฐานข้อมูลหลายรายการ ดังนั้นจึงขอแนะนำอย่างยิ่งให้ใช้ธุรกรรม
สำคัญ! ตั้งแต่เวอร์ชัน 4.2.0 ธุรกรรมไม่ได้เริ่มต้นโดยอัตโนมัติ
หมายเหตุสำคัญอีกประการหนึ่งคือ การยักย้ายโครงสร้างจะถูกเลื่อนออกไป จนกว่าคุณจะกด save
บนโมเดล (บางวิธีเรียกโดยนัยว่า save
และส่งคืนผลลัพธ์บูลีนของการดำเนินการ)
หากโมเดลได้รับการบันทึกสำเร็จ ไม่ได้หมายความว่าโหนดถูกย้าย หากแอปพลิเคชันของคุณขึ้นอยู่กับว่าโหนดได้เปลี่ยนตำแหน่งจริงหรือไม่ ให้ใช้วิธี hasMoved
:
ถ้า ($node->save()) {$moved = $node->hasMoved(); -
เมื่อคุณเพียงแค่สร้างโหนด มันจะถูกผนวกเข้ากับส่วนท้ายของแผนผัง:
หมวดหมู่::สร้าง($แอตทริบิวต์); // บันทึกเป็นรูท
$node = หมวดหมู่ใหม่($attributes);$node->save(); // บันทึกเป็นรูท
ในกรณีนี้ โหนดจะถือเป็น รูท ซึ่งหมายความว่าโหนดไม่มีพาเรนต์
// #1 โดยนัย save$node->saveAsRoot();// #2 ชัดเจน save$node->makeRoot()->save();
โหนดจะถูกต่อท้ายต้นไม้
หากคุณต้องการทำให้โหนดเป็นลูกของโหนดอื่น คุณสามารถสร้างโหนดสุดท้ายหรือลูกแรกได้
ในตัวอย่างต่อไปนี้ $parent
คือโหนดที่มีอยู่บางส่วน
มีหลายวิธีในการต่อท้ายโหนด:
// #1 การใช้ deferred insert$node->appendToNode($parent)->save();// #2 การใช้ parent node$parent->appendNode($node);// #3 การใช้ parent's ลูกความสัมพันธ์$parent- >children()->create($attributes);// #5 การใช้ความสัมพันธ์หลักของโหนด$node->parent()->associate($parent)->save();// #6 การใช้ parent คุณลักษณะ$node->parent_id = $parent->id;$node->save();// #7 การใช้วิธีคงที่หมวดหมู่::create($attributes, $parent);
และมีเพียงสองสามวิธีในการเตรียม:
// #1$node->prependToNode($parent)->save();// #2$parent->prependNode($node);
คุณสามารถสร้าง $node
ให้เป็นเพื่อนบ้านของโหนด $neighbor
ได้โดยใช้วิธีการต่อไปนี้:
ต้องมี $neighbor
โหนดเป้าหมายสามารถเป็นโหนดใหม่ได้ หากมีโหนดเป้าหมายอยู่ โหนดนั้นจะถูกย้ายไปยังตำแหน่งใหม่และพาเรนต์จะถูกเปลี่ยนหากจำเป็น
# บันทึกอย่างชัดเจน$node->afterNode($neighbor)->save();$node->beforeNode($neighbor)->save();# บันทึกโดยนัย$node->insertAfterNode($neighbor);$node-> insertBeforeNode($เพื่อนบ้าน);
เมื่อใช้วิธีการคง create
บนโหนดจะตรวจสอบว่าแอตทริบิวต์มีรหัส children
หรือไม่ หากเป็นเช่นนั้น มันจะสร้างโหนดเพิ่มเติมแบบเรียกซ้ำ
$node = Category::create(['name' => 'Foo','children' => [ ['ชื่อ' => 'บาร์','เด็ก ๆ' => [ [ 'ชื่อ' => 'บาส' ], - - - -
$node->children
ตอนนี้มีรายการโหนดลูกที่สร้างขึ้น
คุณสามารถสร้างต้นไม้ใหม่ได้อย่างง่ายดาย สิ่งนี้มีประโยชน์สำหรับการเปลี่ยนแปลงโครงสร้างของต้นไม้จำนวนมาก
หมวดหมู่::rebuildTree($data, $delete);
$data
เป็นอาร์เรย์ของโหนด:
$ข้อมูล = [ [ 'id' => 1, 'name' => 'foo', 'children' => [ ... ] ], [ 'ชื่อ' => 'บาร์' ], -
มีการระบุรหัสสำหรับโหนดด้วยชื่อ foo
ซึ่งหมายความว่าโหนดที่มีอยู่จะถูกเติมและบันทึก หากไม่มีโหนดอยู่ ModelNotFoundException
จะถูกส่งออกไป นอกจากนี้โหนดนี้มีการระบุ children
ซึ่งเป็นอาร์เรย์ของโหนดด้วย พวกเขาจะถูกประมวลผลในลักษณะเดียวกันและบันทึกเป็นลูกของ node foo
bar
โหนดไม่ได้ระบุคีย์หลัก ดังนั้นจึงจะถูกสร้างขึ้น
$delete
จะแสดงว่าจะลบโหนดที่มีอยู่แล้ว แต่ไม่มีอยู่ใน $data
หรือไม่ ตามค่าเริ่มต้น โหนดจะไม่ถูกลบ
ตั้งแต่เวอร์ชัน 4.2.8 คุณสามารถสร้างแผนผังย่อยใหม่ได้:
หมวดหมู่::rebuildSubtree($root, $data);
ข้อจำกัดนี้จะสร้างแผนผังใหม่เพื่อสืบทอดของโหนด $root
ในบางกรณีเราจะใช้ตัวแปร $id
ซึ่งเป็นรหัสของโหนดเป้าหมาย
บรรพบุรุษสร้างสายโซ่ของผู้ปกครองไปที่โหนด มีประโยชน์สำหรับการแสดงเส้นทางไปยังหมวดหมู่ปัจจุบัน
ลูกหลานคือโหนดทั้งหมดในแผนผังย่อย เช่น ลูกของโหนด ลูกของลูก ฯลฯ
ทั้งบรรพบุรุษและลูกหลานสามารถโหลดได้อย่างกระตือรือร้น
// การเข้าถึงบรรพบุรุษ $node->บรรพบุรุษ;// การเข้าถึงลูกหลาน $node->ลูกหลาน;
เป็นไปได้ที่จะโหลดบรรพบุรุษและผู้สืบทอดโดยใช้แบบสอบถามที่กำหนดเอง:
$result = Category::ancestorsOf($id);$result = Category::ancestorsAndSelf($id);$result = Category::descendantsOf($id);$result = Category::descendantsAndSelf($id);
ในกรณีส่วนใหญ่ คุณต้องให้บรรพบุรุษของคุณเรียงลำดับตามระดับ:
$result = Category::defaultOrder()->ancestorsOf($id);
สามารถโหลดชุดบรรพบุรุษได้อย่างกระตือรือร้น:
$categories = Category::with('ancestors')->paginate(30);// อยู่ในมุมมอง breadcrumbs:@foreach($categories as $i => $category) <เล็ก>{{ $category->บรรพบุรุษ->นับ() ? implode(' > ', $category->ancestors->pluck('name')->toArray()) : 'ระดับบนสุด' }}</small><br> {{ $หมวดหมู่->ชื่อ }} @endforeach
พี่น้องคือโหนดที่มีพาเรนต์เดียวกัน
$result = $node->getSiblings();$result = $node->พี่น้อง()->get();
หากต้องการรับพี่น้องคนถัดไปเท่านั้น:
// รับพี่น้องที่อยู่หลัง node$result = $node->getNextSibling();// รับพี่น้องทั้งหมดที่อยู่หลัง node$result = $node->getNextSiblings();// รับพี่น้องทั้งหมดโดยใช้ query$result = $node->nextSiblings()->get();
หากต้องการรับพี่น้องคนก่อน:
// รับพี่น้องที่อยู่ก่อนหน้า node$result = $node->getPrevSibling();// รับพี่น้องทั้งหมดที่อยู่ก่อน node$result = $node->getPrevSiblings();// รับพี่น้องทั้งหมดโดยใช้ query$result = $node->prevSiblings()->get();
ลองนึกภาพว่าแต่ละหมวดหมู่ has many
นั่นคือสร้างความสัมพันธ์ HasMany
แล้ว คุณจะได้รับสินค้าทั้งหมดของ $category
และทุกรายการสืบทอดได้อย่างไร? ง่าย!
// รับรหัสของลูกหลาน$categories = $category->descendants()->pluck('id');// รวมรหัสของหมวดหมู่นั้นเอง$categories[] = $category->getKey();// รับสินค้า $สินค้า = สินค้า::whereIn('category_id', $categories)->get();
หากคุณต้องการทราบว่าโหนดอยู่ที่ระดับใด:
$result = Category::withDepth()->find($id);$ความลึก = $result->ความลึก;
โหนดรูทจะอยู่ที่ระดับ 0 ลูกของโหนดรูทจะมีระดับ 1 เป็นต้น
หากต้องการรับโหนดตามระดับที่กำหนด คุณสามารถใช้ having
ข้อจำกัดได้:
$result = Category::withDepth()->มี('ความลึก', '=', 1)->get();
สำคัญ! สิ่งนี้จะไม่ทำงานในโหมดเข้มงวดของฐานข้อมูล
โหนดทั้งหมดได้รับการจัดระเบียบภายในอย่างเคร่งครัด ตามค่าเริ่มต้น จะไม่มีการใช้ลำดับ ดังนั้นโหนดอาจปรากฏตามลำดับแบบสุ่มและไม่ส่งผลต่อการแสดงแผนผัง คุณสามารถเรียงลำดับโหนดตามตัวอักษรหรือดัชนีอื่นๆ
แต่ในบางกรณี ลำดับชั้นก็เป็นสิ่งจำเป็น จำเป็นสำหรับการเรียกข้อมูลบรรพบุรุษและสามารถใช้เพื่อเรียงลำดับรายการเมนูได้
หากต้องการใช้วิธีสั่งต้นไม้ defaultOrder
จะใช้:
$result = หมวดหมู่::defaultOrder()->get();
คุณสามารถรับโหนดในลำดับที่กลับกัน:
$result = Category::reversed()->get();
หากต้องการเลื่อนโหนดขึ้นหรือลงภายในพาเรนต์เพื่อให้ส่งผลต่อลำดับเริ่มต้น:
$bool = $node->down();$bool = $node->up();// Shift node โดย 3 พี่น้อง$bool = $node->down(3);
ผลลัพธ์ของการดำเนินการคือค่าบูลีนว่าโหนดเปลี่ยนตำแหน่งหรือไม่
ข้อจำกัดต่างๆ ที่สามารถนำไปใช้กับตัวสร้างแบบสอบถามได้:
โดยที่ IsRoot() เพื่อรับเฉพาะโหนดรูทเท่านั้น
hasParent() เพื่อรับโหนดที่ไม่ใช่รูท
โดยที่ IsLeaf() เพื่อรับเฉพาะใบไม้
hasChildren() เพื่อรับโหนดที่ไม่ลา;
โดยที่IsAfter($id) เพื่อรับทุกโหนด (ไม่ใช่แค่พี่น้อง) ที่อยู่หลังโหนดที่มี id ที่ระบุ
โดยที่IsBefore($id) เพื่อรับทุกโหนดที่อยู่ก่อนโหนดที่มี id ที่ระบุ
ข้อจำกัดลูกหลาน:
$result = Category::whereDescendantOf($node)->get();$result = Category::whereNotDescendantOf($node)->get();$result = Category::orWhereDescendantOf($node)->get() ;$result = Category::orWhereNotDescendantOf($node)->get();$result = Category::whereDescendantAndSelf($id)->get();// รวมโหนดเป้าหมายไว้ในผลลัพธ์ set$result = Category::whereDescendantOrSelf($node)->get();
ข้อจำกัดของบรรพบุรุษ:
$result = Category::whereAncestorOf($node)->get();$result = Category::whereAncestorOrSelf($id)->get();
$node
สามารถเป็นได้ทั้งคีย์หลักของโมเดลหรืออินสแตนซ์โมเดล
หลังจากได้รับชุดโหนดแล้ว คุณสามารถแปลงเป็นแผนผังได้ ตัวอย่างเช่น:
$tree = Category::get()->toTree();
สิ่งนี้จะเติมความสัมพันธ์ระหว่าง parent
และ children
บนทุกโหนดในชุด และคุณสามารถเรนเดอร์แผนผังโดยใช้อัลกอริธึมแบบเรียกซ้ำ:
$nodes = Category::get()->toTree();$traverse = function ($categories, $prefix = '-') use (&$traverse) {foreach ($categories as $category) {echo PHP_EOL.$ คำนำหน้า' '.$category->name;$traverse($category->children, $prefix.'-'); - };$สำรวจ($โหนด);
สิ่งนี้จะแสดงผลดังนี้:
- Root -- Child 1 --- Sub child 1 -- Child 2 - Another root
นอกจากนี้ คุณสามารถสร้างแผนผังแบบเรียบได้: รายการโหนดที่โหนดย่อยอยู่หลังโหนดหลักทันที สิ่งนี้มีประโยชน์เมื่อคุณได้รับโหนดที่เรียงลำดับแบบกำหนดเอง (เช่น เรียงตามตัวอักษร) และไม่ต้องการใช้การเรียกซ้ำเพื่อวนซ้ำโหนดของคุณ
$nodes = Category::get()->toFlatTree();
ตัวอย่างก่อนหน้าจะแสดงผล:
Root Child 1 Sub child 1 Child 2 Another root
บางครั้งคุณไม่จำเป็นต้องโหลดทั้งทรีและเพียงทรีย่อยของโหนดเฉพาะ แสดงในตัวอย่างต่อไปนี้:
$root = Category::descendantsAndSelf($rootId)->toTree()->first();
ในแบบสอบถามเดียว เราได้รับรูทของทรีย่อยและทรีย่อยทั้งหมดที่สามารถเข้าถึงได้ผ่านความสัมพันธ์ children
หากคุณไม่ต้องการ $root
node ให้ทำดังต่อไปนี้แทน:
$tree = Category::descendantsOf($rootId)->toTree($rootId);
หากต้องการลบโหนด:
$โหนด->ลบ();
สำคัญ! ผู้สืบทอดที่มีโหนดนั้นจะถูกลบด้วย!
สำคัญ! จำเป็นต้องลบโหนดเป็นโมเดล อย่า พยายามลบโหนดโดยใช้แบบสอบถามดังนี้:
หมวดหมู่::where('id', '=', $id)->ลบ();
มันจะหักต้นไม้!
รองรับลักษณะ SoftDeletes
ในระดับโมเดลด้วย
หากต้องการตรวจสอบว่าโหนดเป็นผู้สืบทอดของโหนดอื่นหรือไม่:
$bool = $node->isDescendantOf($parent);
หากต้องการตรวจสอบว่าโหนดเป็นรูทหรือไม่:
$bool = $node->isRoot();
การตรวจสอบอื่นๆ:
$node->isChildOf($other);
$node->isAncestorOf($other);
$node->isSiblingOf($other);
$node->isLeaf()
คุณสามารถตรวจสอบว่าต้นไม้หักหรือไม่ (เช่น มีข้อผิดพลาดทางโครงสร้างบางอย่าง):
$bool = Category::isBroken();
สามารถรับสถิติข้อผิดพลาดได้:
$data = Category::countErrors();
มันจะส่งคืนอาร์เรย์พร้อมคีย์ต่อไปนี้:
oddness
- จำนวนโหนดที่มีค่า lft
และ rgt
ไม่ถูกต้อง
duplicates
- จำนวนโหนดที่มีค่า lft
หรือ rgt
เท่ากัน
wrong_parent
-- จำนวนโหนดที่มีค่า parent_id
ไม่ถูกต้องซึ่งไม่สอดคล้องกับค่า lft
และ rgt
missing_parent
- จำนวนโหนดที่มี parent_id
ชี้ไปยังโหนดที่ไม่มีอยู่
เนื่องจากต้นไม้ v3.1 สามารถแก้ไขได้แล้ว การใช้ข้อมูลการสืบทอดจากคอลัมน์ parent_id
จะมีการตั้งค่า _lft
และ _rgt
ที่เหมาะสมสำหรับทุกโหนด
โหนด::fixTree();
ลองนึกภาพคุณมี Menu
model และ MenuItems
มีความสัมพันธ์แบบหนึ่งต่อกลุ่มที่ถูกสร้างขึ้นระหว่างโมเดลเหล่านี้ MenuItem
มีแอตทริบิวต์ menu_id
สำหรับการรวมโมเดลเข้าด้วยกัน MenuItem
รวมชุดที่ซ้อนกัน เห็นได้ชัดว่าคุณต้องการประมวลผลแต่ละทรีแยกกันตามแอตทริบิวต์ menu_id
ในการทำเช่นนั้น คุณต้องระบุแอตทริบิวต์นี้เป็นแอตทริบิวต์ขอบเขต:
ฟังก์ชั่นที่ได้รับการป้องกัน getScopeAttributes() {กลับมา [ 'menu_id' ]; -
แต่ตอนนี้ เพื่อดำเนินการค้นหาแบบกำหนดเอง คุณต้องระบุแอตทริบิวต์ที่ใช้สำหรับการกำหนดขอบเขต:
MenuItem::scoped([ 'menu_id' => 5 ])->withDepth()->get(); // OKMenuItem::descendantsOf($id)->get(); // ผิด: ส่งคืนโหนดจาก scopeMenuItem::scoped([ 'menu_id' => 5 ])->fixTree(); // ตกลง
เมื่อร้องขอโหนดโดยใช้อินสแตนซ์โมเดล ขอบเขตจะใช้โดยอัตโนมัติตามคุณลักษณะของโมเดลนั้น:
$node = MenuItem::findOrFail($id);$node->พี่น้อง()->withDepth()->get(); // ตกลง
หากต้องการรับตัวสร้างแบบสอบถามที่กำหนดขอบเขตโดยใช้อินสแตนซ์:
$node->newScopedQuery();
ใช้แบบสอบถามที่กำหนดขอบเขตเสมอเมื่อกระตือรือร้นในการโหลด:
MenuItem::scoped([ 'menu_id' => 5])->with('descendants')->findOrFail($id); // OKMenuItem::with('ลูกหลาน')->findOrFail($id); // ผิด
PHP >= 5.4
ลาราเวล >= 4.1
ขอแนะนำอย่างยิ่งให้ใช้ฐานข้อมูลที่รองรับธุรกรรม (เช่น InnoDb ของ MySql) เพื่อรักษาความปลอดภัยต้นไม้จากความเสียหายที่อาจเกิดขึ้น
หากต้องการติดตั้งแพ็คเกจในเทอร์มินัล:
composer require kalnoy/nestedset
สำหรับผู้ใช้ Laravel 5.5 ขึ้นไป:
Schema::create('table', function (Blueprint $table) {...$table->nestedSet(); });// หากต้องการลบ columnsSchema::table('table', function (Blueprint $table) {$table->dropNestedSet(); -
สำหรับ Laravel เวอร์ชันก่อนหน้า:
...ใช้ KalnoyNestedsetNestedSet; Schema::create('table', function (Blueprint $table) {...NestedSet::columns($table); -
หากต้องการวางคอลัมน์:
...ใช้ KalnoyNestedsetNestedSet; Schema::table('table', function (พิมพ์เขียว $table) { NestedSet::dropColumns($ตาราง); -
โมเดลของคุณควรใช้ลักษณะ KalnoyNestedsetNodeTrait
เพื่อเปิดใช้งานชุดที่ซ้อนกัน:
ใช้ KalnoyNestedsetNodeTrait; class Foo ขยายโมเดล {use NodeTrait; -
หากส่วนขยายก่อนหน้าของคุณใช้ชุดคอลัมน์ที่แตกต่างกัน คุณเพียงแค่ต้องแทนที่วิธีการต่อไปนี้ในคลาสโมเดลของคุณ:
ฟังก์ชั่นสาธารณะ getLftName() {กลับ 'ซ้าย'; } ฟังก์ชั่นสาธารณะ getRgtName() {กลับมา 'ถูกต้อง'; }ฟังก์ชันสาธารณะ getParentIdName() { ส่งคืน 'ผู้ปกครอง'; }// ระบุฟังก์ชัน mutatorpublic ของแอตทริบิวต์ parent id setParentAttribute($value) {$this->setParentIdAttribute($value); -
หากแผนผังของคุณมีข้อมูล parent_id
คุณจะต้องเพิ่มสองคอลัมน์ในสคีมาของคุณ:
$table->unsignedInteger('_lft');$table->unsignedInteger('_rgt');
หลังจากตั้งค่าโมเดลของคุณแล้ว คุณเพียงแค่แก้ไขแผนผังเพื่อเติมคอลัมน์ _lft
และ _rgt
:
MyModel::fixTree();
ลิขสิทธิ์ (c) 2017 Alexander Kalnoy
อนุญาตให้บุคคลใดก็ตามที่ได้รับสำเนาของซอฟต์แวร์นี้และไฟล์เอกสารที่เกี่ยวข้อง ("ซอฟต์แวร์") อนุญาตโดยไม่เสียค่าใช้จ่าย เพื่อจัดการกับซอฟต์แวร์โดยไม่มีข้อจำกัด รวมถึงแต่ไม่จำกัดเพียงสิทธิ์ในการใช้ คัดลอก ปรับเปลี่ยน ผสาน เผยแพร่ แจกจ่าย ให้อนุญาตช่วง และ/หรือขายสำเนาของซอฟต์แวร์ และอนุญาตให้บุคคลที่ได้รับซอฟต์แวร์นี้สามารถทำได้ ภายใต้เงื่อนไขต่อไปนี้:
ประกาศเกี่ยวกับลิขสิทธิ์ข้างต้นและประกาศการอนุญาตนี้จะรวมอยู่ในสำเนาทั้งหมดหรือส่วนสำคัญของซอฟต์แวร์
ซอฟต์แวร์นี้มีให้ "ตามที่เป็น" โดยไม่มีการรับประกันใดๆ ทั้งโดยชัดแจ้งหรือโดยนัย ซึ่งรวมถึงแต่ไม่จำกัดเพียงการรับประกันความสามารถในการค้าขาย ความเหมาะสมสำหรับวัตถุประสงค์เฉพาะ และการไม่ละเมิด ไม่ว่าในกรณีใดผู้เขียนหรือผู้ถือลิขสิทธิ์จะต้องรับผิดต่อการเรียกร้องค่าเสียหายหรือความรับผิดอื่นใดไม่ว่าในการกระทำของสัญญาการละเมิดหรืออย่างอื่นที่เกิดขึ้นจากหรือเกี่ยวข้องกับซอฟต์แวร์หรือการใช้งานหรือข้อตกลงอื่น ๆ ใน ซอฟต์แวร์.