การรวม CakePHP สำหรับ htmx
รองรับเวอร์ชัน CakePHP >= 4.x และ 5.x
cd
ไปที่รูทของโฟลเดอร์แอพของคุณ (โดยที่ไฟล์ composer.json
อยู่) และรันคำสั่งต่อไปนี้:
composer require zunnu/cake-htmx
จากนั้นโหลดปลั๊กอินโดยใช้คอนโซลของ CakePHP:
./bin/cake plugin load CakeHtmx
หากต้องการติดตั้ง htmx โปรดดูเอกสารประกอบ
ขณะนี้ฟังก์ชันหลักถูกรวมไว้ในองค์ประกอบ Htmx หากต้องการโหลดส่วนประกอบ คุณจะต้องแก้ไข src/Controller/AppController.php
และโหลดส่วนประกอบ Htmx ในฟังก์ชัน initialize()
$ this -> loadComponent ( ' CakeHtmx.Htmx ' );
คุณสามารถใช้ตัวตรวจจับเพื่อตรวจสอบว่าคำขอนั้นเป็น Htmx หรือไม่
$ this -> getRequest ()-> is ( ' htmx ' ) // Always true if the request is performed by Htmx
$ this -> getRequest ()-> is ( ' boosted ' ) // Indicates that the request is via an element using hx-boost
$ this -> getRequest ()-> is ( ' historyRestoreRequest ' ) // True if the request is for history restoration after a miss in the local history cache
การใช้ส่วนประกอบนี้ทำให้คุณสามารถตรวจสอบรายละเอียดที่เฉพาะเจาะจงมากขึ้นเกี่ยวกับคำขอได้
$ this -> Htmx -> getCurrentUrl (); // The current URL of the browser
$ this -> Htmx -> getPromptResponse (); // The user response to an hx-prompt
$ this -> Htmx -> getTarget (); // The id of the target element if it exists
$ this -> Htmx -> getTriggerName (); // The name of the triggered element if it exists
$ this -> Htmx -> getTriggerId (); // The id of the triggered element if it exists
redirect
Htmx สามารถทริกเกอร์การเปลี่ยนเส้นทางฝั่งไคลเอ็นต์เมื่อได้รับการตอบกลับด้วยส่วนหัว HX-Redirect
$ this -> Htmx -> redirect ( ' /somewhere-else ' );
clientRefresh
Htmx จะทริกเกอร์การโหลดหน้าเว็บซ้ำเมื่อได้รับการตอบกลับด้วยส่วนหัว HX-Refresh
clientRefresh
เป็นการตอบกลับแบบกำหนดเองที่ให้คุณส่งการตอบกลับดังกล่าวได้ ไม่มีการโต้แย้ง เนื่องจาก Htmx ละเว้นเนื้อหาใดๆ
$ this -> Htmx -> clientRefresh ();
stopPolling
เมื่อใช้ทริกเกอร์การโพล Htmx จะหยุดการโพลเมื่อพบการตอบกลับด้วยรหัสสถานะ HTTP พิเศษ 286 stopPolling
เป็นการตอบกลับแบบกำหนดเองพร้อมรหัสสถานะนั้น
$ this -> Htmx -> stopPolling ();
ดูเอกสารประกอบสำหรับส่วนหัวที่เหลืออยู่ทั้งหมด
$ this -> Htmx -> location ( $ location ) // Allows you to do a client-side redirect that does not do a full page reload
$ this -> Htmx -> pushUrl ( $ url ) // pushes a new url into the history stack
$ this -> Htmx -> replaceUrl ( $ url ) // replaces the current URL in the location bar
$ this -> Htmx -> reswap ( $ option ) // Allows you to specify how the response will be swapped
$ this -> Htmx -> retarget ( $ selector ); // A CSS selector that updates the target of the content update to a different element on the page
นอกจากนี้ คุณยังทริกเกอร์เหตุการณ์ฝั่งไคลเอ็นต์ได้โดยใช้เมธอด addTrigger
$ this -> Htmx
-> addTrigger ( ' myEvent ' )
-> addTriggerAfterSettle ( ' myEventAfterSettle ' )
-> addTriggerAfterSwap ( ' myEventAfterSwap ' );
หากคุณต้องการส่งรายละเอียดพร้อมกับเหตุการณ์ คุณสามารถใช้อาร์กิวเมนต์ที่สองเพื่อส่งเนื้อหาได้ รองรับสตริงหรืออาร์เรย์
$ this -> Htmx -> addTrigger ( ' myEvent ' , ' Hello from myEvent ' )
-> addTriggerAfterSettle ( ' showMessage ' , [
' level ' => ' info ' ,
' message ' => ' Here is a Message '
]);
คุณสามารถเรียกวิธีการเหล่านั้นได้หลายครั้งหากคุณต้องการทริกเกอร์หลายเหตุการณ์
$ this -> Htmx
-> addTrigger ( ' trigger1 ' , ' A Message ' )
-> addTrigger ( ' trigger2 ' , ' Another Message ' )
หากต้องการเพิ่มโทเค็น CSRF ให้กับคำขอทั้งหมดของคุณ ให้เพิ่มโค้ดด้านล่างลงในเลย์เอาต์ของคุณ
document.body.addEventListener( ' htmx:configRequest ' , (event) => {
event.detail.headers[ ' X-CSRF-Token ' ] = " <?= $ this -> getRequest ()->getAttribute('csrfToken') ?> " ;
})
ฟังก์ชัน setBlock()
ช่วยให้คุณสามารถเรนเดอร์บล็อกเฉพาะในขณะที่ลบบล็อกอื่น ๆ ที่อาจเรนเดอร์ออก สิ่งนี้มีประโยชน์อย่างยิ่งเมื่อคุณต้องการอัปเดตเพียงบางส่วนของมุมมองของคุณ
$ this -> Htmx -> setBlock ( ' userTable ' );
ฟังก์ชัน addBlock()
ช่วยให้คุณสามารถเพิ่มบล็อกเฉพาะลงในรายการบล็อกที่ควรแสดงผล
$ this -> Htmx -> addBlock ( ' userTable ' );
ฟังก์ชัน addBlocks()
ช่วยให้คุณสามารถเพิ่มหลายบล็อกในรายการบล็อกที่ควรแสดงผล
$ this -> Htmx -> addBlocks ([ ' userTable ' , ' pagination ' ]);
Htmx รองรับการอัปเดตหลายเป้าหมายโดยส่งคืนการตอบกลับบางส่วนหลายรายการด้วย hx-swap-oop
ดูตัวอย่าง Users index search functionality with pagination update
หมายเหตุ หากคุณกำลังทำงานกับตารางเหมือนในตัวอย่าง คุณอาจต้องเพิ่ม
< script type = "text/javascript" >
htmx.config.useTemplateFragments = true;
</ script >
ในเทมเพลตหรือเค้าโครงของคุณ
ในตัวอย่างนี้ เราจะใช้ฟังก์ชันการค้นหาสำหรับดัชนีของผู้ใช้โดยใช้ Htmx เพื่อกรองผลลัพธ์แบบไดนามิก เราจะล้อมตัวตารางของเราไว้ใน viewBlock ที่เรียกว่า usersTable
เมื่อเพจโหลด เราจะแสดงผล usersTable
viewBlock
// Template/Users/index.php
<?= $ this -> Form -> control ( ' search ' , [
' label ' => false ,
' placeholder ' => __ ( ' Search ' ),
' type ' => ' text ' ,
' required ' => false ,
' class ' => ' form-control input-text search ' ,
' value ' => ! empty ( $ search ) ? $ search : '' ,
' hx-get ' => $ this -> Url -> build ([ ' controller ' => ' Users ' , ' action ' => ' index ' ]),
' hx-trigger ' => " keyup changed delay:200ms " ,
' hx-target ' => " #search-results " ,
' templates ' => [
' inputContainer ' => ' <div class="col-10 col-md-6 col-lg-5">{{content}}</div> '
]
]); ?>
<table id="usersTable" class="table table-hover table-white-bordered">
<thead>
<tr>
<th scope="col"> <?= ' id ' ?> </th>
<th scope="col"> <?= ' Name ' ?> </th>
<th scope="col"> <?= ' Email ' ?> </th>
<th scope="col"> <?= ' Modified ' ?> </th>
<th scope="col"> <?= ' Created ' ?> </th>
<th scope="col" class="actions"> <?= ' Actions ' ?> </th>
</tr>
</thead>
<tbody id="search-results">
<?php $ this -> start ( ' usersTable ' ); ?>
<?php foreach ( $ users as $ user ): ?>
<tr>
<td> <?= $ user -> id ?> </td>
<td> <?= h ( $ user -> name ) ?> </td>
<td> <?= h ( $ user -> email ) ?> </td>
<td> <?= $ user -> modified ?> </td>
<td> <?= $ user -> created ?> </td>
<td class="actions">
<?= $ this -> Html -> link ( ' Edit ' ,
[
' action ' => ' edit ' ,
$ user -> id
],
[
' escape ' => false
]
); ?>
<?= $ this -> Form -> postLink ( ' Delete ' ,
[
' action ' => ' delete ' ,
$ user -> id
],
[
' confirm ' => __ ( ' Are you sure you want to delete user {0}? ' , $ user -> email ),
' escape ' => false
]
); ?>
</td>
</tr>
<?php endforeach ; ?>
<?php $ this -> end (); ?>
<?php echo $ this -> fetch ( ' usersTable ' ); ?>
</tbody>
</table>
ในคอนโทรลเลอร์ภายนอก เราจะตรวจสอบว่าคำขอนั้นเป็น Htmx หรือไม่ และหากเป็นเช่นนั้น เราจะเรนเดอร์เฉพาะ usersTable
viewBlock เท่านั้น
// src/Controller/UsersController.php
public function index ()
{
$ search = null ;
$ query = $ this -> Users -> find ( ' all ' );
if ( $ this -> request -> is ( ' get ' )) {
if (! empty ( $ this -> request -> getQueryParams ())) {
$ data = $ this -> request -> getQueryParams ();
if ( isset ( $ data [ ' search ' ])) {
$ data = $ data [ ' search ' ];
$ conditions = [
' OR ' => [
' Users.id ' => ( int ) $ data ,
' Users.name LIKE ' => ' % ' . $ data . ' % ' ,
' Users.email LIKE ' => ' % ' . $ data . ' % ' ,
],
];
$ query = $ query -> where ([ $ conditions ]);
$ search = $ data ;
}
}
}
$ users = $ query -> toArray ();
$ this -> set ( compact ( ' users ' , ' search ' ));
if ( $ this -> getRequest ()-> is ( ' htmx ' )) {
$ this -> viewBuilder ()-> disableAutoLayout ();
// we will only render the usersTable viewblock
$ this -> Htmx -> setBlock ( ' usersTable ' );
}
}
ในตัวอย่างนี้ เราจะใช้ฟังก์ชันการค้นหาแบบไดนามิกสำหรับดัชนีของผู้ใช้โดยใช้ Htmx สิ่งนี้จะทำให้เราสามารถกรองผลลัพธ์แบบเรียลไทม์และอัปเดตการแบ่งหน้าตามนั้น เราจะล้อมเนื้อหาของตารางไว้ใน viewBlock ที่เรียกว่า usersTable
และการแบ่งหน้าของเราเป็นบล็อก pagination
เมื่อเพจโหลด เราจะแสดงผลทั้ง usersTable
และ viewBlock pagination
// Template/Users/index.php
<?= $ this -> Form -> control ( ' search ' , [
' label ' => false ,
' placeholder ' => __ ( ' Search ' ),
' type ' => ' text ' ,
' required ' => false ,
' class ' => ' form-control input-text search ' ,
' value ' => ! empty ( $ search ) ? $ search : '' ,
' hx-get ' => $ this -> Url -> build ([ ' controller ' => ' Users ' , ' action ' => ' index ' ]),
' hx-trigger ' => ' keyup changed delay:200ms ' ,
' hx-target ' => ' #search-results ' ,
' hx-push-url ' => ' true ' ,
' templates ' => [
' inputContainer ' => ' <div class="col-10 col-md-6 col-lg-5">{{content}}</div> '
]
]); ?>
<table id="usersTable" class="table table-hover table-white-bordered">
<thead>
<tr>
<th scope="col"> <?= ' id ' ?> </th>
<th scope="col"> <?= ' Name ' ?> </th>
<th scope="col"> <?= ' Email ' ?> </th>
<th scope="col"> <?= ' Modified ' ?> </th>
<th scope="col"> <?= ' Created ' ?> </th>
<th scope="col" class="actions"> <?= ' Actions ' ?> </th>
</tr>
</thead>
<tbody id="search-results">
<?php $ this -> start ( ' usersTable ' ); ?>
<?php foreach ( $ users as $ user ): ?>
<tr>
<td> <?= $ user -> id ?> </td>
<td> <?= h ( $ user -> name ) ?> </td>
<td> <?= h ( $ user -> email ) ?> </td>
<td> <?= $ user -> modified ?> </td>
<td> <?= $ user -> created ?> </td>
<td class="actions">
<?= $ this -> Html -> link ( ' Edit ' ,
[
' action ' => ' edit ' ,
$ user -> id
],
[
' escape ' => false
]
); ?>
<?= $ this -> Form -> postLink ( ' Delete ' ,
[
' action ' => ' delete ' ,
$ user -> id
],
[
' confirm ' => __ ( ' Are you sure you want to delete user {0}? ' , $ user -> email ),
' escape ' => false
]
); ?>
</td>
</tr>
<?php endforeach ; ?>
<?php $ this -> end (); ?>
<?php echo $ this -> fetch ( ' usersTable ' ); ?>
</tbody>
</table>
// pagination
<?php $ this -> start ( ' pagination ' ); ?>
<nav aria-label="Page navigation" id="pagination">
<ul class="pagination justify-content-center">
<?php $ this -> Paginator -> setTemplates ([
' prevActive ' => ' <li class="page-item pagination-previous"><a class="page-link" hx-get="{{url}}" hx-target="#search-results" hx-push-url="true" href="#">{{text}}</a></li> ' ,
' prevDisabled ' => ' <li class="page-item disabled pagination-previous"><a class="page-link" hx-get="{{url}}" hx-target="#search-results" hx-push-url="true" href="#">{{text}}</a></li> ' ,
' number ' => ' <li class="page-item"><a class="page-link" hx-get="{{url}}" hx-target="#search-results" hx-push-url="true" href="#">{{text}}</a></li> ' ,
' current ' => ' <li class="page-item active"><a class="page-link" hx-get="{{url}}" hx-target="#search-results" hx-push-url="true" href="#">{{text}}</a></li> ' ,
' nextActive ' => ' <li class="page-item pagination-next"><a class="page-link" hx-get="{{url}}" hx-target="#search-results" hx-push-url="true" href="#">{{text}}</a></li> ' ,
' nextDisabled ' => ' <li class="page-item disabled pagination-next"><a class="page-link" hx-get="{{url}}" hx-target="#search-results" hx-push-url="true" href="#">{{text}}</a></li> ' ,
' first ' => ' <li class="page-item pagination-next"><a class="page-link" hx-get="{{url}}" hx-target="#search-results" hx-push-url="true" href="#">{{text}}</a></li> ' ,
' last ' => ' <li class="page-item pagination-next"><a class="page-link" hx-get="{{url}}" hx-target="#search-results" hx-push-url="true" href="#">{{text}}</a></li> ' ,
]); ?>
<?= $ this -> Paginator -> first ( ' <i class="fas fa-angles-left"></i> ' , [ ' escape ' => false ]) ?>
<?= $ this -> Paginator -> prev ( ' <i class="fas fa-chevron-left"></i> ' , [ ' escape ' => false ]) ?>
<?= $ this -> Paginator -> numbers ([ ' first ' => 1 , ' last ' => 1 , ' modulus ' => 3 ]) ?>
<?= $ this -> Paginator -> next ( ' <i class="fas fa-chevron-right"></i> ' , [ ' escape ' => false ]) ?>
<?= $ this -> Paginator -> last ( ' <i class="fas fa-angles-right"></i> ' , [ ' escape ' => false ]) ?>
</ul>
</nav>
<?php $ this -> end (); ?>
<?= $ this -> fetch ( ' pagination ' ); ?>
ในคอนโทรลเลอร์ภายนอก เราจะตรวจสอบว่าคำขอนั้นเป็น Htmx หรือไม่ และหากเป็นเช่นนั้น เราจะเรนเดอร์เฉพาะ usersTable
viewBlock เท่านั้น
// src/Controller/UsersController.php
public function index ()
{
$ search = null ;
$ query = $ this -> Users -> find ( ' all ' );
if ( $ this -> request -> is ( ' get ' )) {
if (! empty ( $ this -> request -> getQueryParams ())) {
$ data = $ this -> request -> getQueryParams ();
if ( isset ( $ data [ ' search ' ])) {
$ data = $ data [ ' search ' ];
$ conditions = [
' OR ' => [
' Users.id ' => ( int ) $ data ,
' Users.name LIKE ' => ' % ' . $ data . ' % ' ,
' Users.email LIKE ' => ' % ' . $ data . ' % ' ,
],
];
$ query = $ query -> where ([ $ conditions ]);
$ search = $ data ;
}
}
}
$ this -> paginate [ ' limit ' ] = 200 ;
$ users = $ this -> paginate ( $ query );
$ this -> set ( compact ( ' users ' , ' search ' ));
if ( $ this -> getRequest ()-> is ( ' htmx ' )) {
$ this -> viewBuilder ()-> disableAutoLayout ();
// render users table and pagination blocks
$ this -> Htmx -> addBlock ( ' usersTable ' )-> addBlock ( ' pagination ' );
}
}
ได้รับอนุญาตภายใต้ใบอนุญาต MIT