Các pro Laravel cho em hỏi chút về Query Builder với ạ
Mình nghĩ việc refactor sẽ tùy vào việc phần code bạn muốn tách ra đang làm gì
- Với những phần logic đơn giản có thể tách các hàm utilities và re-use lại
- Với những phần logic phức tạp, hoặc đại diện cho một feature hay business logic nào đó, thì bạn có thể sử dụng
Query Object
(thực chất là việc tách class thôi ). Đảm bảo tên class mô tả đúng cái đang thực hiện và nội dụng class tập trung vào 1 vấn đề thôi. Hoặc nguy hiểm hơn thì dùngRepository
(nhưng thực sự theo mình dùng Repository vs Active Record của Laravel là hơi thừa và làm codebase phức tạp hơn) - Tất nhiên là có thể sử dụng pattern này pattern khác vào nữa nhưng mình nghĩ cái đó ko quá quan trọng, miễn sao sau một vài tháng bạn quay lại đọc đoạn code đó vẫn hiểu là đc.
[Laravel] Mọi người cho em hỏi về Redis trong laravell
A thấy rất nhiều component trong Laravel ở dạng driver-based ví dụ như Authentication, Queue, Database, Session, Notifications, Cache,...
Trong trường hợp của em Redis chỉ là một dạng driver của cache component.
Performance thì còn tùy ứng dụng, e có thể dùng Redis, memcached,.. Hoặc nếu driver e cần dùng không được support bởi Framework thì em có thể extend framework và tạo custom cache driver.
Call to undefined function trong lavarel
Nếu bạn đang dùng version <= 5.4 (?) thì có thể require file function.php
bên trong boostrap/autoload.php
, nếu file boostrap/autoload.php
không tồn tại (do framework sử dụng OPCache trong các phiên bản PHP mới hơn, nên file này hơi thừa) thì bạn thêm vào file composer.json
cũng ok.
Hỏi về cách truyền 1 mảng trên route
@thienhungasd Mình nghĩ thay vì dùng route parameter (biến bạn đang đề cập ở đây) bạn nên dùng query string (vì bạn đang dùng GET). Bạn có thể dùng một số package như query-string để format nếu dữ liệu ở dạng mảng (tất nhiên nếu bạn đang dùng ajax nhé). Hoặc PHP thì dùng http-build-query
(maybe !?).
Tại sao lại là Vuejs
Mọi người trả lời khá rõ ràng rồi, bạn có thể tìm hiểu thêm một số bài viết sau nếu cần
- https://scotch.io/bar-talk/vuejs-vs-jquery-use-cases-and-comparison-with-examples
- https://vuejs.org/v2/guide/comparison.html
- https://vuejs.org/v2/guide/reactivity.html
- Virtual DOM vs. Actual DOM
- https://swizec.com/blog/benchmarking-vue/swizec/8240
- https://medium.com/@darrenjennings/data-driven-vue-js-53e84f16e28f
- https://blog.rangle.io/how-to-create-data-driven-user-interfaces-in-vue/
Tại sao Var và Let khác nhau trong trường hợp này
Bạn tham khảo câu hỏi này trên Viblo này: https://viblo.asia/q/nho-giai-thich-gia-tri-bien-i-trong-doan-code-W65GWL2j5DO
BIg O
Bạn tham khảo thử một số bài viết này xem sao:
https://brilliant.org/wiki/big-o-notation
https://brilliant.org/practice/big-o-notation
Ngoài Big-O (big 0) thì còn có Big-Ω (big omega), Big-$\Theta $ (big theta) bạn có thể tìm hiểu thêm nếu thích
Tại sao Laravel ServiceProvider gọi phương thức $this->app->rebinding() "không tồn tại"?
Bạn gửi mail hỏi Taylor Otwell xem sao
...
Mình đùa chút thôi theo mình thì những method signature trong Illuminate\Container\Container
có thể được coi là public API của Laravel Service Container. Và những phương thức đó được khuyên dùng trong thực tế (do đó chúng được đề cập đến trong documentation). Những phương thức trong interface (contract) trên có thể giải quyết được hầu hết các use case khi làm ứng dụng. Mình cũng đảm bảo chẳng mấy ai sử dụng rebinding
trong dự án thực tế cả.
Nhiệm vụ chính của container vẫn là binding và resolving và interface trên vẫn đảm bảo được điều đó.
PHP là một duck typed language thay vì strong typed như trong một số ngôn ngữ khác như Java, .NET. Với các ngôn ngữ dạng strong typed, method signature trong interface thường phải định nghĩa cả kiểu cho parameters và kiểu trả về --> đảm bảo type safety. Trong PHP thì không như vậy thường sẽ ko có kiểu xác định. Do đó với PHP, các phương thức của một object sẽ xác định cách object đó có thể sử dụng thay vì phải phụ thuộc vào sự kế thừa từ một class khác hoặc một thể hiện cụ thể của interface. Tất nhiên PHP vẫn có thể là một strong typed nếu muốn
Lỗi throttle trong Laravel
Middleware sử dụng RateLimiter
, một component của Laravel Cache system. Bạn thử kiểm tra xem cache driver hiện tại bạn đang dùng là gì. Kiểm tra file config/cache.php
và file .env
nếu cần. Nếu driver là array thì mình nghĩ sẽ có vấn đề Có thể nó không gây ra lỗi của bạn mà chỉ đơn giản là middleware đó sẽ không có tác dụng thôi.
Nếu không phải do cache driver thì mình nghĩ bạn đang sử dụng middleware đó cho toàn bộ các route. Hiểu đơn giản là nếu bạn dùng middleware đó cho một nhóm các route thì khi một route bị rate limited các route khác cũng tèo luôn.
Ví dụ:
Route::middleware('throttle:5,1')->group(function () {
Route::get('/foo', function () {
return 'Bar';
});
Route::get('/bar', function () {
return 'Baz';
});
});
Sau 5 lần truy cập /foo
liên tiếp trong 1 phút, exception sẽ throw và 429 error code sẽ trả về. Lúc này bạn truy cập /bar
cũng tèo luôn
Nguyên nhân là Laravel sẽ dùng một key trong cache để xác định xem việc truy cập route có khả khi không - <key>:timer
. Cache key đó được xác định bởi một hash string - dùng sha1
với request signature. Signature đó được xác định bởi identifier của user (thường là ID) nếu đã đăng nhập. Hoặc là một string có dạng <domain>|<ip>
nếu chưa đăng nhập. Có thể thấy signature này không phân biệt các route trong một nhóm với nhau, nên một cái tèo thì những cái khác cũng tèo.
Thế nên nếu bạn wrap tất cả các route trong middleware đó thì một cái tèo thì bạn sẽ không truy cập được route nào nữa
Bạn chỉ nên sử dụng middleware đó cho một hoặc một nhóm các route nhất định nào đó thôi.
Chú ý là kể cả khi bạn định nghĩa tham số khác nhau cho các route group khác nhau. Nếu các requests đến từ cùng 1 user hay 1 IP thì số lượng request có thể thực hiện sẽ phụ thuộc nhau và không dễ để xác định chính xác. Túm lại là do request signature không đổi sau mỗi request vì chúng ta sử dụng hash....
url() và route()
Mình nghĩ nó phụ thuộc vào bạn hay team của bạn khi xây dựng ứng dụng. Trên thực tế có 3 cách chính để generate URL đến một route nào đó sử dụng các helper functions: action()
, url()
và route()
action('Controller@method', $parameters)
: cách này ít được sử dụng do nó phụ thuộc vào tên của controller và tên của phương thức bên trong nó. Nếu thay đổi tên thì việc update khá bất tiện. Và nếu route của bạn chỉ là một closure thì tất nhiên sẽ ko sử dụng cách này được.url($path, $parameters)
: cách này cũng hay được sử dụng, nó khá đơn giản. Bạn có thể không cần phải đặt tên cho route hay định nghĩa controller (sử dụng route closure chẳng hạn). Tuy nhiên, khi thay đổi route path việc update cũng hơi mệt chút.route($path, $parameters)
: cách này có lẽ được sử dụng nhiều nhất. Tuy nhiên, bạn phải đặt tên cho các route. Tất nhiên, nếu tên route thay đổi bạn sẽ vẫn phải update, nhưng trên thực tế thường sẽ có chuẩn để đặt tên cho các route nên việc thay đổi chúng là rất ít khi xảy ra. Theo mình việc search-replace theo route name sẽ dễ hơn là search-replace theo route path
Khi muốn generate URL đến một model instance nào đó, thay vì sử dụng các helper functions trên, bạn có thể sử dụng accessor trong Laravel (hoặc có thể sử dụng một phương thức trong model), như thế này chẳng hạn. Sau này thì bạn chỉ cần gọi phương thức hoặc custom attribute thôi.
use Illuminate\Database\Eloquent\Model;
class Lesson extends Model
{
public function getPathAttribute()
{
// constructing path to a given model
}
public function path()
{
// constructing path to a given model
}
}
$lesson = Lesson::find(1);
$path = $lesson->path;
$path = $lesson->path();
Mình nghĩ sử dụng cách nào thì nó cũng không ảnh hưởng đến performance đâu. Điều quan trọng là bạn chỉ nên sử dụng một cách thôi, đừng sử dụng mix các cách trên với nhau
Nhờ giải thích giá trị biến i trong đoạn Code
Mình nghĩ có một số lý do như sau:
var
là let
có scope khác nhau. var
có scope là function block còn let
chỉ là một block thông thường (ví dụ như for
loop có thể coi là một block)
for(let i = 0; i < 5; i++) {
console.log(i);
}
console.log(i); // Uncaught ReferenceError: i is not defined
for(var i = 0; i < 5; i++) {
console.log(i);
}
console.log(i); // 5
Lý do thứ 2 là do bạn sử dụng setTimeout
để wrap console.log(i)
statement. Để hiểu rõ hơn nguyên nhân trước hết bạn cần hiểu về Event Loop trong JavaScript. Nói ngắn gọn thì trình duyệt sử dụng event loop để kiểm tra và thực thi các pending events (hay pending messages) trong event queue (hay message queue). setTimeout
sẽ đặt quá trình thực thi hàm vào event queue nếu đang có các công việc khác cần phải xử lý.
Trong ví dụ của bạn hàm setTimeout
có giá trị delay là 0ms. Tuy nhiên điều đó không có nghĩa là hàm bên trong nó sẽ được thực hiện ngay lập tức. Thời gian delay chỉ là thời gian ngắn nhất mà sau đó event sẽ được xử lý chứ không phải là thời gian chính xác. Khi delay không xác định hoặc có giá trị là 0
thì trình duyệt sẽ cố gắng thực thi hàm đó sớm nhất có thể, cụ thể là nó sẽ được xử lý trong quá trình chúng ta thường gọi là next tick (khái niệm khá quen thuộc trong Node.js)
(function() {
console.log(1);
setTimeout(function(){
console.log(3);
}, 0);
console.log(4);
})();
Trong ví dụ trên kết quả sẽ là 1 4 3
chứ không phải là 1 3 4
Khi sử dụng var
thì for
loop đã đi qua tất cả các iteration trước khi hàm bên trong setTimeout
được thực thi. Lúc này thì giá trị của i
đã là 5
(giá trị của i
sẽ bị override sau mỗi iteration - vòng lặp) rồi nên console.log()
sẽ chỉ trả về giá trị là 5
Một cách hiểu khác là khi sử dụng từ khóa var
, chúng ta ngầm định rằng mỗi vòng lặp của for
loop sẽ nhận được một bản sao của i
tại thời điểm mà vòng lặp đó được thực hiện. NOPE!!! Tuy nhiên nếu bạn tìm hiểu một chút về scope trong JavaScript thì có thể thấy rằng mặc dù các callback function trong setTimeout
được định nghĩa riêng biệt nhưng chúng đều chia sẻ một scope chung, trong trường hợp này là global scope. i
không được định nghĩa bên trong callback function của setTimeout
vì vậy nó sẽ được tìm kiếm ở scope bên ngoài chứa nó, ở đây là global scope. Do không dùng strict mode nên i
sẽ là một global variable. Do đó cả 5 lần thực hiện đều dùng chung một reference đến i
. Để fix thì chúng ta có thể wrap setTimeout
function bên trong một scope mới, cách dễ nhất là sử dụng IIFE và truyền giá trị của i
vào. Sử dụng IIFE giúp chúng ta tạo mới một scope đồng thời cũng cho phép callback function của setTimeout
ghi nhớ giá trị của i
trong scope đó (closure trong JS)
for(var i = 0; i < 5; i++) {
(function(j) {
setTimeout(function() {
console.log(j);
}, 1000);
})(i);
}
for(var i = 0; i < 5; i++) {
(function() {
var j = i;
setTimeout(function() {
console.log(j);
}, 1000);
})();
}
Dependency Injection có phải là một design pattern?
Theo anh thì nó như thế này: https://viblo.asia/p/laravel-service-container-in-depth-tips-to-customize-your-application-RQqKLnqNl7z#ioc--di-3
async/await - foreach & for
Theo mình hàm Array.prototype.forEach
sẽ có dạng như sau:
Array.prototype.forEach = function (callback) {
for (let index = 0; index < this.length; index++) {
callback(this[index], index, this);
}
}
Ở đây callback
sẽ được gọi trực tiếp trên từng phẩn tử của mảng tuy nhiên chúng ta không đợi await callback
đó được thực xong trên một phần tử trước khi chuyển sang phần tử tiếp theo. Đó là lý do tại sao console.log
sẽ chạy liên tục và promises
vẫn sẽ là mảng rỗng.
Bạn có thể custom lại hàm forEach
như sau:
Array.prototype.asyncForEach = async function (callback) {
for (let index = 0; index < this.length; index++) {
await callback(this[index], index, this);
}
}
Và sử dụng nó cho ví dụ trên:
(async() => {
const promises = [];
URLS.asyncForEach(async(item, key) => {
console.log('Page ID Spawned', key);
promises.push(await wait(1000));
});
await Promise.all(promises);
})();
Send Mail Laravel not working on FROM
Vấn đề có thể liên quan đến mail driver bạn đang sử dụng - Gmail SMTP. Explain... https://productforums.google.com/forum/#!topic/gmail/o5hlYNQNxmk
Có lẽ bạn cần thay đổi configuration của tài khoản Gmail bạn đang sử dụng: https://support.google.com/mail/answer/22370
Dùng API Route trong Laravel như thế nào?
Nếu bạn check class RouteServiceProvider
- https://github.com/laravel/laravel/blob/master/app/Providers/RouteServiceProvider.php#L66 thì mặc định các API route sẽ có prefix
là api
và sử dụng middleware group là api. Middleware group này thực hiện một số việc như: Rate Limit và Route Model Bindings (tương tự như câu trả lời của anh kopitop đã đề cập).
Tiếp theo bạn cần check configuration hiện tại trong config/auth.php
- https://github.com/laravel/laravel/blob/master/config/auth.php#L44
Driver mặc định là token
tức là sử dụng TokenGuard
- https://github.com/laravel/framework/blob/5.5/src/Illuminate/Auth/TokenGuard.php. Driver này yêu cầu bạn phải có trường api_token
trong request (có thể qua query string hoặc request data). Bạn có thể đọc source code của class trên để hiểu hơn.
Nếu bạn muốn sử dụng OAuth2 để authorize các API request thì có thể sử dụng Laravel Passport, lúc này driver sẽ là passport
thay vì token
.
P/S: với các request bình thường yêu cầu có session thì bạn có thể tham khảo: https://github.com/laravel/framework/blob/5.5/src/Illuminate/Auth/SessionGuard.php để so sánh
[PHP][Laravel] Tôi có nên sử dụng SoftDelete trong Model không?
Mình nghĩ không nên sử dụng Soft Deleting nếu không thực sự cần thiết, do khi liên quan đến relationship thì sẽ có rất nhiều vấn đề (đặc biệt khi muốn restore lại một instance nào đó). Một điểm khác nữa là Soft Deleting không thực sự hiệu quả khi thực hiện trên collection các model instance (phải delete từng instance một). Còn cách quản lý thì mình nghĩ phải làm thủ công thôi sử dụng model event như restoring
, restored
, deleting
, deleted
,... (hoặc sử dụng model observer để gộp các event kia nếu cần).
Xin kinh nghiệm học tại Laracasts
Mình không gặp tình trạng như bạn nhưng đây là một số góp ý của mình:
- Mình thấy giọng anh Jeffrey Way cũng khá là dễ nghe, nếu nghe một thời gian cũng thấy khá thích . Laracasts hiện không có subtitle nên đôi lúc cũng gây khó khăn cho người mới học qua video.
- Thường thì anh ấy chỉ hướng dẫn trực tiếp trên code editor nên đôi khi cũng khá khó để nắm bắt nếu không quen. Tuy nhiên một số video sẽ có source code trên GitHub mình có thể tham khảo lại.
- Laracasts chia thành cách skills, chủ đề, độ khó (trình độ) khác nhau nên mình nghĩ nên tập trung vào những gì mình cần thôi không nên xem tất cả các video mới ra. Video nào hay thì nên bookmark lại để xem lại. Hoặc subscribe một series nào đó, khi có bài học mới sẽ nhận được mail thông báo.
- Thường mình phải áp dụng được những gì học qua video vào thực tế sẽ nhớ lâu hơn rất nhiều.
- Nếu cảm thấy khó hiểu thì bạn nên có giấy bút để note-taking và ghi lại những keyword quan trọng.
- Nên đọc phần comment bên dưới mỗi video để xem mọi người bình luận về nội dung trong video đó, đôi khi có những ý kiến khá hay.
- Bạn không cần hiểu rõ từng câu chữ (nếu chưa quen), và cũng nên tìm hiểu mỗi số từ liên quan đến chuyền nghành cntt. Những từ chuyên nghành thường đơn nghĩa nên cũng khá dễ nhớ.
- Bạn nên đọc và hiểu rõ Laravel Documentation trước khi xem video để nắm bắt nội dung nhanh hơn và chính xác hơn.
- Một số series bạn nên xem đầu tiên: What's New in Laravel?, Laravel Fundamentals, How Do I?
- Sử dụng forum của Laracasts: https://laracasts.com/discuss
Tạo ràng buộc unique với điều kiện trong Laravel và MySQL ?
Mình nghĩ việc thêm điều kiện cho unique()
khi định nghĩa bảng không khả thi lắm.
Bạn có thể thử thêm unique constraint cho hai trường code
và is_deleted
(compound index) xem sao, mình nghĩ đây là cách đơn giản nhất. Như vậy thì mình có thể có cùng một mã code cho cả hai trạng thái.
$table->string('code', 13)->nullable();
$table->boolean('is_deleted')->default(false);
$table->unique(['code', 'is_deleted']);
Tổ chức
Chưa có tổ chức nào.