Case 1: Multi-level categories.

In SQL, you can do something like this.

id name parent_id depth
1 Food 0 0
... ... ... ...
34 Noodle 1 1
35 Rice 1 1
... ... ... ...
102 Spaghetti 34 2

How about the code?

To get all the recursive children of Food, you could fetch
SELECT * FROM `categories` WHERE `depth` = 1 AND WHERE `parent_id` = 1
Then you will get array of all the level 2 category, to get the next level you could do
SELECT * FROM `categories` WHERE `depth` = 2 AND WHERE `parent_id` IN (34, 35)
After you know how to get those, you actually can combine these statement straight to get the level 2
SELECT * FROM `categories` WHERE `depth` = 2 AND WHERE `parent_id` IN (SELECT `id` FROM `categories` WHERE `depth` = 1 AND WHERE `parent_id` = 1)
Finally you could combine them to get the deepest depth first, and then loop to get all sub of Food. Or another way is by using JOIN, but it will be very very complicated and less readable even though it's faster than subqueries.

Case 2: Separate configuration for each users.

In SQL, you can do something like this.

id username password config
1 john_doe $2y$10$NhRNj6QF.... {"notification":true,"dark_mode":true,"nsfw":true}
102 jane_doe $2y$10$jSAr/Rwmjh... {"notification":false,"dark_mode":true,"nsfw":false}

How about the code?

Pretty Straight forward, only one information, latest database is now JSON supported. Even if it doesn't, you can still use "text" data type then convert JSON in the back-end

Case 3: A product has two types of payment method with different logic.

In SQL, you can do something like this.

id payment_id payment_type
1 3 lorem bank
102 103 ipsum bank

How about the code?

For simplicity, it's basically like this

class Foo
    protected $bankList = [
        "lorem bank" => "LoremBank",
        "ipsum bank" => "IpsumBank",

    public function getPayment(): PaymentMethod
        return new $this->bankList[$this->payment_type]($this->payment_id);
        // return new $this->bankList['lorem bank'](3);
        // return new LoremBank(3);

Which later return either Object of Class LoremBank or IpsumBank which both have the same interface (PaymentMethod), so that later the programmer could call $payment->pay($debitInformation) with different logic (different API or different cost charged)

Case 4: OAuth ?


user_id token refresh_token
1 veryuniquetoken veryuniquerefreshtoken
102 superuniquetoken superuniquerefreshtoken

Wait, why two types of token?

User should bring all two tokens together to do anything, and the server will response with a different refresh token. Well, usually only when doing "critical" things to minimize response time. But Why?
Let's say, a user connects to a "phishing" wi-fi which will we called the 3rd person, then the 3rd person will know the user's tokens are veryuniquetoken and veryuniquerefreshtoken. Then the user goes home and still refreshing its token every request.
Then the 3rd person tries this "old" refreshtoken, and BOOM, he failed to get the victim(user)'s account because the refreshtoken has already been changed simultaneously.

Hmmm, is something wrong?

Please report here if I give wrong explanation or you have different opinion on the best approach.