blog Archives | phpGrid - PHP Datagrid https://phpgrid.com/category/blog/ Create PHP grids in minutes, not hours. Tue, 11 Mar 2025 22:26:35 +0000 en-US hourly 1 CodeProjecthttps://wordpress.org/?v=7.0.3 129966043 Understanding Asymmetric Property Visibility in PHP 8.4 https://phpgrid.com/blog/understanding-asymmetric-property-visibility-in-php-8-4/ Mon, 17 Mar 2025 22:26:16 +0000 https://phpgrid.com/?p=10232 PHP 8.4, released in November 2024, introduces Asymmetric Property Visibility, which allows separate visibility levels for reading and writing class properties, enhancing access control while preserving encapsulation. What is Asymmetric Property Visibility? In PHP 8.4, you can now define different visibility levels for reading and writing a property within a class. Previously, PHP allowed properties […]

The post Understanding Asymmetric Property Visibility in PHP 8.4 appeared first on phpGrid - PHP Datagrid.

]]>
PHP 8.4, released in November 2024, introduces Asymmetric Property Visibility, which allows separate visibility levels for reading and writing class properties, enhancing access control while preserving encapsulation.

What is Asymmetric Property Visibility?

In PHP 8.4, you can now define different visibility levels for reading and writing a property within a class.

Previously, PHP allowed properties to be (public), (protected), or (private), but both reading and writing had the same visibility level. With Asymmetric Property Visibility, you can set separate visibility for getting and setting a property.

A Basic Example

class User {
    public string $name { public get; private set; }

    public function __construct(string $name) {
        $this->name = $name; // Allowed: private setter is used inside the class
    }

    public function changeName(string $newName) {
        $this->name = $newName; // Allowed: inside class
    }
}

$user = new User("Alice");
echo $user->name; // ✅ Allowed: public getter
$user->name = "Bob"; // ❌ Error: Cannot modify, setter is private

Key Takeaways

  • (get) visibility is public, allowing read access from anywhere.
  • (set) visibility is private, so only class methods can modify the property.

Example 2: Preventing Direct Modification of Sensitive Properties

class BankAccount {
    public int $balance { public get; private set; }

    public function __construct(int $initialBalance) {
        $this->balance = $initialBalance;
    }
    public function deposit(int $amount) {
        $this->balance += $amount; // ✅ Allowed: inside class
    }
    public function withdraw(int $amount) {
        if ($amount > $this->balance) {
            throw new Exception("Insufficient funds");
        }
        $this->balance -= $amount; // ✅ Allowed: inside class
    }
}

$account = new BankAccount(1000);
echo $account->balance; // ✅ Allowed: public getter
$account->balance = 500; // ❌ Error: Cannot modify, setter is private

Key Takeaways

  • Prevents unauthorized modifications to ($balance) while allowing controlled updates through class methods.
  • Improves security by ensuring logic (e.g., preventing overdrafts) is always enforced.

Caveats & Considerations

  • This feature only applies to typed properties ((int), (string), (array), etc.). Typed properties are supported since PHP 7.4
  • You must specify a visibility level for both (get) and (set) (e.g., ({ public get; private set; })).
  • Asymmetric visibility cannot be applied to untyped properties.

How Was Asymmetric Property Visibility Achieved Before PHP 8.4?

Before Asymmetric Property Visibility, PHP only allowed single visibility for properties ((public), (protected), or (private)). This meant that if a property was readable, it was also writable unless additional methods were used to restrict modifications.

To achieve similar behavior, developers had to use getter and setter methods manually using Getter & Setter Methods (Manual Encapsulation)

For example:

class User {
    private string $name;

    public function __construct(string $name) {
        $this->name = $name;
    }

    // Public getter method
    public function getName(): string {
        return $this->name;
    }

    // Private setter method (prevents external modification)
    private function setName(string $name): void {
        $this->name = $name;
    }

    public function changeName(string $newName): void {
        $this->setName($newName); // Allowed inside class
    }
}

$user = new User("Alice");

echo $user->getName(); // ✅ Allowed: public getter\
$user->setName("Bob"); // ❌ Error: Cannot access private method\
$user->name = "Bob"; // ❌ Error: Cannot access private property

Problems with the Traditional Approach

  1. More Boilerplate Code
  • Requires explicit getter and setter methods for each property.
  • Increases code duplication when dealing with many properties.

2. Less Readable & Natural Code

  • Instead of ($user->name), you need to call ($user->getName()).
  • Assigning a value (($user->name = “Bob”;)) is replaced by a method (($user->changeName(“Bob”);)).

Why Asymmetric Property Visibility Matters

Asymmetric Property Visibility in PHP 8.4 enhances encapsulation by allowing developers to set different visibility levels for reading and writing a property. This means a property can be publicly readable but privately writable, preventing unintended modifications while still making data accessible. 

Previously, achieving this required workarounds like getter and setter methods, but now it can be done more cleanly and intuitively. This feature improves code maintainability, security, and clarity, making it easier to enforce strict control over property access without extra boilerplate.

Final Thoughts

Before PHP 8.4, getter and setter methods were the only way to enforce asymmetric visibility. While effective, it resulted in verbose and less readable code. With Asymmetric Property Visibility, PHP now provides native support for defining different access levels for reading and writing properties, making property management much cleaner and more intuitive.

The post Understanding Asymmetric Property Visibility in PHP 8.4 appeared first on phpGrid - PHP Datagrid.

]]>
10232
Debugging PHP with VSCode and XDebug: A Step-by-Step Guide https://phpgrid.com/blog/debugging-php-with-vscode-and-xdebug-a-step-by-step-guide/ Tue, 11 Mar 2025 04:46:39 +0000 https://phpgrid.com/?p=10227 Debugging is an essential part of PHP development, and using Visual Studio Code with XDebug can greatly enhance your workflow. This guide will walk you through setting up XDebug, enabling breakpoints, stepping through code, using stack traces, and troubleshooting common issues. 1. Installing XDebug Before you can debug PHP with VSCode, you need to ensure […]

The post Debugging PHP with VSCode and XDebug: A Step-by-Step Guide appeared first on phpGrid - PHP Datagrid.

]]>
Debugging is an essential part of PHP development, and using Visual Studio Code with XDebug can greatly enhance your workflow. This guide will walk you through setting up XDebug, enabling breakpoints, stepping through code, using stack traces, and troubleshooting common issues.

1. Installing XDebug

Before you can debug PHP with VSCode, you need to ensure that XDebug is installed on your system.

Check if XDebug is Installed

From a phpinfo page, and check wether XDebug section and it is enabled.

XDebug in phpinfo

Install XDebug If It Is Missing

If XDebug is missing, you can install it using pecl:

pecl install xdebug

After installation, add this line to your php.ini file:

zend_extension=xdebug

Remembere to restart your web server or PHP service:

sudo systemctl restart apache2 # For Apache
sudo systemctl restart php-fpm # For PHP-FPM

Now we need to configure XDebug to connect to VSCode

2. Configuring XDebug for VSCode

Edit your php.ini file and add the following configuration:

[xdebug]
xdebug.mode=debug
xdebug.start_with_request=yes
xdebug.client_host=127.0.0.1
xdebug.client_port=9003
xdebug.log=/var/log/xdebug.log

Important:

Ensure your PHP service is restarted for any changes made in php.ini to take effect.

3. Setting Up VSCode for XDebug

1. Install the PHP Debug Extension

PHP Debug Extension for VSCode

2. Configure VSCode Debugger

  • Open your project in VSCode.
  • Go to the Run and Debug panel (Ctrl+Shift+D).
  • Click on create a launch.json file. It should create default configuration as the following with port 9003. It is absolutely critial to have the same port as what is in xdebug.client_port in php.ini in previous step.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
   "version": "0.2.0",
    "configurations": [        {
            "name": "Listen for XDebug",
            "type": "php",
            "request": "launch",
            "port": 9003
        },
        {
            "name": "Launch currently open script",
            "type": "php",
            "request": "launch",
            "program": "${file}",
            "cwd": "${fileDirname}",
            "port": 9003
        }
    ]
}

3. Start the Debugger

  • Click the green Start Debugging button or press F5.
  • Ensure XDebug is running and listening on port 9003. It actually can be any port number as 9003 is default.

The debugger bar should now appear right below tabs in VSCode.

VSCode Debugger Bar

4. Debugging Features

Setting Breakpoints

  • Open any PHP file.
  • Click in the left margin next to a line number or press F9 to set a breakpoint.
  • Run the debugger (F5) and execute the PHP script in your browser.
  • The script execution will pause at the breakpoint.

Stepping Through Code

While debugging, you can control execution using:

  • Step Over (F10) – Move to the next line of code.
  • Step Into (F11) – Enter into function calls.
  • Step Out (Shift+F11) – Exit the current function.
  • Continue (F5) – Resume execution until the next breakpoint.

Using Stack Trace

  • The Call Stack panel in VSCode shows the sequence of function calls leading up to the breakpoint.
  • Helps trace errors in deeply nested functions.
  • Click on any function in the stack to inspect its execution.

PHP XDebug breakpoint

5. Troubleshooting Common Issues

Issue 1: Debugger Not Stopping at Breakpoints

  • Ensure XDebug is installed and configured correctly in phpinfo (See step 1)
  • Make sure the matching port (e.g. 9003) is set in both php.ini and launch.json.
  • Always restart Apache or PHP-FPM after making changes.

Issue 2: XDebug Not Connecting to VSCode

  • Verify the logs in =/var/log/xdebug.log for connection issues.
  • Ensure VSCode is listening for XDebug (F5 in debug mode).
  • Disable other applications using port 9003 (like another debugger).

Issue 3: Path Mapping Problems

  • Ensure pathMappings in launch.json correctly maps the server path to the local workspace
  • Add $_SERVER[‘DOCUMENT_ROOT’] in your script to verify paths.

Conclusion

VSCode and XDebug together make debugging PHP a seamless experience. By following this guide, you should be able to install and configure XDebug properly, and set breakpoints and step through code, and also troubleshoot common debugging issues.

Finally, if manually tinkering isn’t your thing, you can opt for a hassle-free solution like MAMP or XAMMP.

Happy debugging! 🚀

Richard

The post Debugging PHP with VSCode and XDebug: A Step-by-Step Guide appeared first on phpGrid - PHP Datagrid.

]]>
10227
My Simple Hack to Learn 2X Faster https://phpgrid.com/blog/my-simple-hack-to-learn-2x-faster/ Sun, 29 Dec 2024 20:50:43 +0000 https://phpgrid.com/?p=10214

While learning React, I couldn’t help but notice how slow the instructor spoke in the recorded lectures. It makes sense being intentionally slow to give time for students to think while absorbing the materials. But after a while, it started to feel like I was waiting for molasses to pour on a chilly day. That’s […]

The post My Simple Hack to Learn 2X Faster appeared first on phpGrid - PHP Datagrid.

]]>

While learning React, I couldn’t help but notice how slow the instructor spoke in the recorded lectures. It makes sense being intentionally slow to give time for students to think while absorbing the materials. But after a while, it started to feel like I was waiting for molasses to pour on a chilly day.

That’s when I discovered the magical speed-up button. Just like that, I was zipping through lectures at 2x speed. It’s like turning your study sessions into an action movie — everything’s faster, more intense, and oddly satisfying.

It turns out, this isn’t just a life hack — it’s backed by science! According to a Caltech study, the human brain is actually faster than our ears. “Multimodal learning” — fancy talk for combining audio and visuals — supercharges how much we can absorb. So, not only are you learning faster, but your brain is also giving you a virtual high-five for being efficient.

Why It Works

Our brains is capable to process and retain information much faster than the pace of normal speech. Increasing the playback speed while listening, it helps to
  • Increases Focus: The faster pace reduces the tendency to zone out.
  • Improves Comprehension: Your brain adapts to processing information more efficiently over time.
  • Saves Time: Completes a 2-hour lecture in just 1 hour, leaving room for review or practice.

How to Use the Hack Effectively

It does take some practice to get to 2x speed-listening. For me, 1.2x is a good comfortable starter pace; 1.5x is efficient and manageable for most content; and 2.0x requires focus but significantly speeds up learning. With time and practice, anyone can adapt and effectively process content at faster speeds.

I’ve also experimented with going beyond 2x, but it becomes overwhelming and impractical and causes “burn out”, so I don’t recommend.

1. Start Gradually

Don’t expect you will be zipping through materials like superman onset. Instead, try at 1.25x or 1.5x speed to get used to faster playback. Gradually increase to 2x speed as your brain adapts to processing quicker speech.

2. Leverage Closed Captions

This is super important as part of “multimodal learning” to engage our visual sensors to read subtitles to help with clarity, especially for technical or unfamiliar content.

3. Take Notes Strategically

Use digital tools like Notion or OneNote to jot down key points quickly. Online classes like Udemy and Coursea have note taking tools built-in with video timestamp.

4. Revisit Critical Sections

It’s perfectly fine to slow down and walk after a sprint, especially when revisiting difficult sections at a normal speed to ensure thorough understanding.

Free Tools for Enhanced Learning

1. Playback Speed Controllers:
  • Chrome Extensions:
  • Native Tools:
    • YouTube, Udemy, Coursera, and similar platforms often have built-in speed controls.
2. Note-Taking Apps:
  • Notion, Obsidian, or Evernote: Great for organizing notes with tags, links, and summaries.
  • AudioNote: Syncs audio or video with your notes.
  • ReClipped: Lets you save video highlights and make notes directly linked to timestamps.
3. Flashcard Tools:
  • Anki (spaced repetition): Use it to create cards from your notes for active recall.
  • Quizlet: Easier to set up and includes premade decks.

Sample Routine for Learning with 2x Speed

I’ve developed an approach to studying at 2x speed that strikes a balance between efficiency and comprehension. My method combines strategic preparation, active note-taking, and consistent review, allowing me to absorb complex concepts quickly while ensuring a solid understanding.

Here’s how I’ve made it work for me and how it can work for you too.

  1. Preparation (5 mins):
  • Review the syllabus or key concepts for the session.
  • Set a specific goal (e.g., “Understand how recursion works”).
2. Study (30–60 mins):
  • Watch the video at 1.2x — 2x speed, adjust accordingly
  • Pause to note down key points or rewatch unclear sections.
3. Review (15 mins):
  • Summarize what you learned.
  • Optional — Create flashcards or a mind map of the main ideas.
4. Practice (30+ mins):
  • Practice exercises or implement the learned concepts in real-world scenarios.

Final Thoughts

This simple hack can transform how you learn, making it faster, more efficient, and more engaging. Combine it with proven techniques like active recall and spaced repetition, and you’ll be well on your way to mastering new skills in no time. Try it out, and unlock your potential!

The post My Simple Hack to Learn 2X Faster appeared first on phpGrid - PHP Datagrid.

]]>
10214
Why Naming Variables Can Distinguish a Good Programmer from a Bad One https://phpgrid.com/blog/why-naming-variables-can-distinguish-a-good-programmer-from-a-bad-one/ Wed, 27 Nov 2024 06:35:39 +0000 https://phpgrid.com/?p=10204 While analyzing some old code from a previous project, I stumbled upon variable names that left me scratching my head. Here’s a snippet of what I found: 123456var type = 0; ... var wfStart = "Server Workflow Start"; var num = 100000; ... var yesOrNo = "Yes"; At first glance, these names seemed cryptic at […]

The post Why Naming Variables Can Distinguish a Good Programmer from a Bad One appeared first on phpGrid - PHP Datagrid.

]]>
While analyzing some old code from a previous project, I stumbled upon variable names that left me scratching my head. Here’s a snippet of what I found:

1
2
3
4
5
6
var type = 0;
...
var wfStart = "Server Workflow Start";
var num = 100000;
...
var yesOrNo = "Yes";

At first glance, these names seemed cryptic at best. After 25 minutes of piecing together the context (aided by poorly written comments), I finally understood what they meant.

What’s wrong here? To me, it seems the original developer rushed through the implementation, disregarding the importance of meaningful variable names. Instead, they left behind a confusing mess for anyone working on the code later.

Imagine the difference if the variables were given descriptive, self-explanatory names. Here’s an improved version:

1
2
3
4
var typeCode = 0;
const SERVER_WORKFLOW_START = "Server Workflow Start";
var maxLimit = 100000;
var isConfirmed = true;

These changes transform the code into something far more understandable. It reflects a clear understanding of the task at hand, good communication of intent.

The Importance of Clarity and Communication

Great variable names make it possible to read code almost like a narrative, reducing the need for excessive comments and helping others - and your future self - understand what’s going on. Poorly named variables, however, add unnecessary confusion.

Consider this example:

1
2
int acctWithdrawn; // number of customers with withdrawn accounts
string ln; // last name of the current customer

These names require a reader to remember the comments or consult documentation to understand what’s going on. With clearer names, this confusion disappears:

1
2
int  customerWidthdrawnAccount;
string customerLastName;

These improved names reveal the variables’ purposes directly. Code, like any text, should be intuitive and readable.

If You Can’t Name It, You Don’t Understand It

If you struggle to name something, it’s likely because you don’t fully understand it yet. Naming variables often requires crystal-clear thinking about what the code is trying to accomplish, so unclear names often signal unclear ideas. If you find yourself reaching for vague terms, try asking, “What exactly is this variable representing?” This exercise helps you clarify your logic, which is beneficial not only for naming but for the overall structure of your code.

To help with this, try using a “descriptive placeholder” name, even if it’s excessively long. For instance, instead of trying to name a counter vaguely, use something like numberOfActiveUsersWhereXisTrue. This will both clarify the variable’s purpose for now and signal for future refactoring to find a concise, precise name as the code becomes more defined.

Here are two JavaScript code examples that demonstrate how to improve variable names for better readability and maintainability:

Example 1: Poor Variable Names

In this example, we have ambiguous and non-descriptive names, making it hard to follow the code’s intent.

1
2
3
4
5
6
7
8
9
10
// Poor variable names
function calc(p, r) {
    let res = 0;
    for (let i = 0; i < r.length; i++) {
        res += r[i];
    }
    return res * (p/100);
}

let price = calc(100, [5, 10, 15]);

Explanation:
calc does not indicate what this function actually calculates.
p and r are not descriptive and don’t explain what values they represent.
res is unclear and doesn’t indicate that it’s the result of the sum of the array.

Improved Example: Good Variable Names

Let’s rename the variables for clarity so that anyone reading the code can understand its purpose at a glance.

1
2
3
4
5
6
7
8
9
10
// Improved variable names
function calculateTotalPrice(basePrice, discounts) {
    let totalDiscount = 0;
    for (let discount of discounts) {
        totalDiscount += discount;
    }
    return basePrice * (totalDiscount/100);
}

let totalPrice = calculateTotalPrice(100, [5, 10, 15]);

Explanation:

calculateTotalPrice clearly describes the purpose of the function.
basePrice and discounts specify what values are being passed in.
totalDiscount makes it clear that it’s the total sum of discounts from the array.

Example 2: Using Contextual Variable Names

Let’s look at a second example where the purpose of variables is unclear due to non-descriptive names.

1
2
3
4
5
6
7
8
9
10
// Poor variable names
function prsnData(d, a) {
    for (let v of a) {
        console.log( <span class="code-inline">${d}: ${v}</span>);
    }
}

let name = "Name";
let attributes = ["smart", "kind", "hardworking"];
prsnData(name, attributes);

Explanation:

prsnData is unclear—does it mean person data or print data?
d and a don’t describe the values they hold, making the function difficult to follow.

Improved Version:

1
2
3
4
5
6
7
8
9
10
11
// Improved variable names
function displayPersonAttributes(personName, attributes) {
    for (let attribute of attributes) {
        console.log( <span class="code-inline">${personName}: ${attribute}</span>);
    }
}

// Usage
let personName = "Name";
let attributes = ["smart", "kind", "hardworking"];
displayPersonAttributes(personName, attributes);

Explanation:

displayPersonAttributes is clear and communicates the function’s purpose.
personName and attributes indicate what each parameter represents, making the code easier to understand at a glance.

Using meaningful names greatly enhances readability and shows a careful, thoughtful approach to programming.

Characteristics of Good Variable Names

While good names vary by context, here are some principles to help make your naming conventions solid:

1. Be Descriptive but Concise: Names should convey purpose. For instance, instead of x, userAge is much clearer. At the same time, avoid overly long names that may become cumbersome. Strive for a balance where a variable name is as short as possible while still conveying its purpose. If you have trouble find a good variable name, use aforementioned “descriptive placeholder”, and come back to it later.
 
2. Use Context: Variable names should fit the function or class they’re in. For instance, a variable in a function handling order data might use orderTotal or customerID rather than something generic like data or num.

3. Follow Naming Conventions: Many languages have specific naming conventions (like camelCase in JavaScript and snake_case in Python). These conventions keep code style consistent and make it easier to read across different projects.

4. Avoid Cryptic Abbreviations: Shortening words can lead to confusion, especially if the abbreviation isn’t universally recognized. A name like num may be clear enough, but cnt could confuse readers who don’t know whether it stands for “count,” “content,” or something else.

5. Meaningful Prefixes and Suffixes: For certain data types or structures, adding a prefix can improve clarity. For example, use listOfUsers to indicate an array or list, or isEnabled to show that a variable is a boolean. These prefixes serve as quick cues about the variable’s function and type.

Refactoring and Renaming When Necessary

As code evolves, so should variable names. It’s common to start with one name and later realize it no longer reflects the variable’s purpose accurately. If your variable’s name no longer aligns with its function, take the time to rename it. Many modern IDEs such as VSCode support [refactor->rename](https://code.visualstudio.com/docs/editor/refactoring) features, which make renaming painless across large codebases.

Naming as a Skill to Build Over Time

Variable naming is a skill that improves with practice and attention. Here are a few strategies to strengthen your naming skills:

Practice Mindfulness: When choosing a name, take a moment to consider how it reflects the variable’s role in the code.

Review and Refine: As you revisit old code, critique your own variable names and improve them.

Ask for Feedback: Code reviews are invaluable for learning from other perspectives. Peers can offer insights into alternative names that may be clearer.

Naming variables may sound trivial, but it’s one of the most telling signs of a programmer’s skill and thoughtfulness. A programmer who takes time to name variables thoughtfully is often the one who approaches problems methodically, communicates clearly, and cares about long-term maintainability.

The post Why Naming Variables Can Distinguish a Good Programmer from a Bad One appeared first on phpGrid - PHP Datagrid.

]]>
10204
Transform HTML Table into Card View Using Nothing But CSS https://phpgrid.com/blog/transform-html-table-into-card-view-using-nothing-but-css/ Fri, 25 Oct 2024 00:26:37 +0000 https://phpgrid.com/?p=10187

I’d like share a recent experiment that explores how to transform a plain, old-fashioned HTML table into a dynamic card view, going beyond the traditional rows and columns. Start With a Simple HTML Table Let’s begin with a simple HTML table such as the following. 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051<table>   <thead>     <tr>       <th>Company</th> […]

The post Transform HTML Table into Card View Using Nothing But CSS appeared first on phpGrid - PHP Datagrid.

]]>

I’d like share a recent experiment that explores how to transform a plain, old-fashioned HTML table into a dynamic card view, going beyond the traditional rows and columns.

Start With a Simple HTML Table

Let’s begin with a simple HTML table such as the following.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<table>
  <thead>
    <tr>
      <th>Company</th>
      <th>Contact</th>
      <th>Country</th>
    </tr>
  </thead>
  <tbody>
  <tr>
    <td>Alfreds Futterkiste</td>
    <td>Maria Anders</td>
    <td>Germany</td>
  </tr>
  <tr>
    <td>Centro Moctezuma</td>
    <td>Francisco Chang</td>
    <td>Mexico</td>
  </tr>  
  <tr>
    <td>Alfreds </td>
    <td>Maria </td>
    <td>Germany</td>
  </tr>
  <tr>
    <td>Centro  </td>
    <td>Francisco Chang</td>
    <td>Mexico</td>
  </tr>
  <tr>
    <td>Alfreds </td>
    <td>Maria </td>
    <td>Germany</td>
  </tr>
  <tr>
    <td>Centro comercial </td>
    <td>Francisco </td>
    <td>Mexico</td>
  </tr>
  <tr>
    <td>Alfreds </td>
    <td>Maria Anders</td>
    <td>Germany</td>
  </tr>
  <tr>
    <td>Centro comercial </td>
    <td>Francisco </td>
    <td>Mexico</td>
  </tr>
  </tbody>
</table>

It looks like this when rendered in browser.

plain table

Just another html table with rows and columns. Nothing fancy.

So how can we transform the traditional rows and columns layout into something more dynamic?

Discover the Power of CSS Grid

Tables don’t have to be boring. With a few simple CSS tricks, you can easily transform a traditional HTML table into a sleek list or card view.

The best part? No JavaScript, just pure CSS!

CSS grid has been an W3C Candidate Recommendation Draft since 2007, however, it has been adopted by the recent versions of all current major browsers.

CSS grid is designed for both rows and columns, making it ideal for complex layouts such as table. It allows you to manage both horizontal and vertical alignments simultaneously, which gives you much more control than Flexbox, which is primarily one-dimensional (row or column).

CSS Grid Properties to Use

  1. Use CSS grid layout for <thead> and <tbody>.
  2. Use CSS display property and set all <td> to be block elements
1
2
3
4
5
6
table tbody, table thead {
  display: grid;
}
table td {
  display: block;
}

With the CSS above, our plain HTML table already magically transforms into a responsive list view, displaying each record neatly in a single column.

table single column

It’s looking good but a bit chaotic! Let’s sprinkle on some CSS borders to give each row in our list a little breathing room.

1
2
3
table, th, tr {
  border: 1px solid black;
}

There you go. Not too shabby for a list view created without a single line of JavaScript!

table singl column with border

Now we got a nice list made from an old-fashioned html table, how do we turn that nice list into a card view?

Spoiler alert: just sprinkle on a few more lines of CSS!

Transform List into Card View

Our final card trick to transform table into cards is to use CSS grid property grid-template-columns:

1
2
3
4
table tbody {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
}

grid-template-columns is a CSS property used in the CSS Grid layout to define the structure of the grid’s columns. It specifies the number of columns, their widths, and how the space within the grid is divided.

With the repeat() function, the first parameter lets us decide how many columns we want—let’s say 4. The second parameter tells those columns how big to be—1fr, or one fraction of the available space. It’s like telling your columns to all get an equal slice of the space pie.

Our final card view

final card view

Take a moment to explore the code and see the results for yourself over on CodePen. It’s the perfect place to experiment and play around with CSS grid transformations.

Keep in mind that CSS Grid is also responsive, providing developers with enhanced control over how layouts adjust and reflow across various screen sizes and devices.

Optional: Adding data-label to card view

While the card view is visually appealing, it lacks the clarity of column information, leaving users to guess the data represented in each card.

By incorporating a touch of JavaScript, we can seamlessly add data labels for each column, enhancing the association between the labels and their corresponding cells.

1
2
3
4
5
6
7
8
9
10
11
12
// Store each column header to array
var labels = [];
$('table').find('thead th').each(function() {
    labels.push($(this).text());
});

// Add data-label attribute to each cell
$('table).find('tbody tr').each(function() {
    $(this).find('
td').each(function(column) {
        $(this).attr('
data-label', labels[column]);
    });
});

The same code above using ES6 vanilla javascript without jQuery

1
2
3
4
5
6
7
8
9
10
11
12
// Store each column header to array
const labels = [];
document.querySelectorAll('table thead th').forEach(th => {
    labels.push(th.textContent);
});

// Add data-label attribute to each cell
document.querySelectorAll('table tbody tr').forEach(tr => {
    tr.querySelectorAll('td').forEach((td, column) => {
        td.setAttribute('data-label', labels[column]);
    });
});

Here’s card view new look with data label:

card view enhanced

Demo

It’s nothing like the html table that we started with. With CSS Grid, the layout options are endless because it allows for full control over both rows and columns in a two-dimensional space.

Final thought…

This tutorial only scratches the surface of the iceberg. You can easily create more responsive layouts, overlap elements, span items across multiple rows or columns, and adjust grid areas dynamically, making it highly versatile for various layout needs.

Happy gridding!

Richard

The post Transform HTML Table into Card View Using Nothing But CSS appeared first on phpGrid - PHP Datagrid.

]]>
10187
All You Need Is CRUD? https://phpgrid.com/blog/all-you-need-is-crud/ Wed, 02 Oct 2024 00:50:31 +0000 https://phpgrid.com/?p=10180

  Believe it or not, everything is essentially CRUD on the internet. It is the hidden skeleton that supports all of our digital interactions. What is CRUD? First of all, let’s get the jargon out of the way. CRUD stands for Create, Read, Update, and Delete — the four basic operations performed on data in a database […]

The post All You Need Is CRUD? appeared first on phpGrid - PHP Datagrid.

]]>

 

Believe it or not, everything is essentially CRUD on the internet. It is the hidden skeleton that supports all of our digital interactions.

What is CRUD?

First of all, let’s get the jargon out of the way. CRUD stands for Create, Read, Update, and Delete — the four basic operations performed on data in a database or application.

It’s not just about data entry forms or database management; CRUD operations are embedded in nearly every feature and action we perform in applications, including those that might seem more complex at first glance.

Let’s start with an example.

SAP is a massive CRUD

During my years in grad school, I had the pleasure (or displeasure) to use SAP ERP system The first time I launched SAP (back when it was still a Windows app), I was struck by its overwhelming number of datagrids. And not just a few — TONS of them, all intricately linked.

SAP interface with datagrids

Imagine navigating through this cluttered interface — it’s a German product, after all!

Despite its chaotic appearance, SAP’s core is packed with datagrids. These datagrids with columns and rows are fundamentally tied to CRUD operations (Create, Read, Update, Delete). They ensure that managing vast amounts of data is both efficient and intuitive, thanks to CRUD’s reliable framework.

SAP has improved is UI over the years, but datagrid still play an essential role at its core.

When there is datagrid, there must be CRUD (Create, Read, Update, Delete).

HTTP verbs are CRUD

Now, let’s talk about something you might use every day without realizing its connection to CRUD — HTTP verbs.

HTTP verbs (or methods) GET, POST, PUT, DELETE, and PATCH are essentially aligned with CRUD operations because they map directly to the fundamental actions required to manage resources in a web application.

Image credit: useful-web

Here’s how each HTTP verb corresponds to CRUD:

1. GET → Read

  • GET is used to retrieve data from a server, which corresponds to the Readoperation in CRUD. For example, when you visit a webpage or query an API to fetch information, the server processes a GET request to retrieve and return the requested data.

2. POST → Create

  • POST is used to send data to the server to create a new resource. This aligns with the Create operation in CRUD. For instance, submitting a form to create a new user account or adding a new item to a database typically involves a POST request.

3. PUT → Update

  • PUT is used to update an existing resource on the server. This corresponds to the Update operation in CRUD. PUT requests typically involve sending the complete updated resource to the server, which then replaces the existing resource with the new version

4. DELETE → Delete

  • DELETE is used to remove a resource from the server, which directly aligns with the Delete operation in CRUD. When a DELETE request is sent, the specified resource is removed from the server, reflecting the removal of a record in a database.

By designing HTTP verbs around CRUD concepts, web APIs can manage resources in a way that is both intuitive for developers and effective for data manipulation, maintaining consistency across different systems.

Not Convinced? Let’s Dig Deeper

You might be thinking, “Okay, there are lots of CRUDs, but does that really mean everything is CRUD?” You might argue that complex applications like Facebook or YouTube don’t fit into this model. Or do they?

Why Facebook is also just a CRUD

Post image

In 2016, Anatoly Lubarsky reverse-engineered Facebook’s database schema, revealing that at its core with user data is stored in relational databases, and CRUD operations manage and retrieve this data.

Whether it’s creating posts, reading news feeds, updating profiles, or deleting content, CRUD operations ensure data is consistently handled in the background, even as the complex processes remain invisible to the user.

Facebook’s Database reverse engineered by Anatoly Lubarsky

Users interact with the platform by creating posts, reading news feeds, updating profiles, and deleting content, all of which are underpinned by CRUD operations that ensure the data is consistently stored, retrieved, and modified in the database, while the complex backend processes remain invisible to the user.

Let’s break it down:

1. FB User Login

  • Read: When you log in to FB, the system reads (R) your input credentials (username and password) from the database to verify your identity.
  • Update: The system might update (U) the last login timestamp or session information in the database once you’re authenticated.
  • Create: If you log in for the first time or create a session, the system might create © a new session record.
  • Delete: Old session data or failed login attempts might be deleted (D) as part of maintaining security.

2. Reading FB posts

  • Read: Search operations are primarily about reading (R) data. When you search for something, the system queries the database and reads the relevant records that match your search criteria.
  • Create/Update/Delete: Though less obvious, search engines also involve creating, updating, and deleting indexes in the background to ensure fast and accurate results. For instance, when new content is added or updated on a platform, search indexes are updated (U) or new entries are created ©. When content is removed, those indexes are deleted (D).

3. Updating Profile

  • Updating profiles is a CRUD operation because it involves modifying existing data in the database. When a user changes their profile information, the system updates the corresponding record in the database

Still not convinced?

Let’s take a look at YouTube.

YouTube: A CRUD Classic

Post image

YouTube is actually a great example of a CRUD application. Here’s how YouTube fits into this model:

  1. Create
    Uploading Videos:
    Users can create content by uploading videos. This involves adding a new video record to the YouTube database, including metadata like the title, description, tags, and thumbnail.
  2. Read
    Watching Videos:
    The core functionality of YouTube is allowing users to read (consume) content. This involves retrieving video data from the database and streaming it to the user.
    Searching and Browsing: Users can search for videos, browse recommendations, and view playlists, all of which involve reading data from YouTube’s servers.
     
  3. Update
    Editing Videos:
    Users can update the metadata of their videos, such as changing the title, description, or privacy settings.
    Managing Playlists: Users can update their playlists by adding or removing videos, changing the order, or editing the playlist title and description.
     
  4. Delete
    Deleting Videos: Users can delete their videos, which removes the video and its associated data from YouTube’s database.
    Removing Content from Playlists: Users can also delete videos from playlists or remove entire playlists.

The Myth of Non-CRUD Operations

What I heard the most is that people would say, “My application has non-CRUD operations,” usually referring to complex functionalities that go beyond basic data management, such as real-time data processing, advanced analytics, complex business logic, or workflow automation, which involve more than just creating, reading, updating, or deleting records in a database.

Or are they?

CRUD in disguise

Datagrid is a CRUD, but not all CRUDs are datagrids. CRUD could have many forms and faces.

Even in situations involving complex functionalities like real-time data processing, advanced analytics, or workflow automation, CRUD operations are still essentially everywhere. These advanced features still rely on the underlying ability to create, read, update, or delete data as they interact with databases or data stores.

1. Real-Time Data Processing:

  • In a real-time data system such as stock trading platform that processes real-time data, CRUD operations are still involved. For instance, the system createsnew trade records when transactions occur, reads real-time market data to display to users, updates users’ portfolios with the latest values, and deletesoutdated or canceled orders. While the processing might be complex, the data handling at its core is still CRUD-based.

2. Advanced Analytics:

  • In a business intelligence tool that performs advanced analytics, CRUD operations are essential. The tool creates datasets based on user queries, readslarge volumes of data from various sources, updates dashboards with the latest analysis results, and deletes outdated reports. The sophisticated algorithms and visualizations rely on CRUD to manage and display the underlying data effectively.

3. Workflow Automation:

  • When you automate a workflow, what’s really happening? The system createsnew tasks, reads existing data (because it’s nosy like that), updates the status as things move along, and deletes anything that’s done or obsolete, kind of like cleaning out your closet but with data instead of last season’s shoes. So no matter how complex or high-tech the automation gets, at its core, it’s just CRUD — on autopilot, and maybe with a little more flair.

4. Machine Learning Applications:

  • In a machine learning platform, CRUD operations are involved in managing training datasets and model results. Even though machine learning is a mystical dance of algorithms and data, it’s still fueled by the trusty old CRUD operations — because even fancy AI models need their data served fresh, updated, and occasionally deleted.

Even though the applications may perform sophisticated tasks, add, read, update, delete operations are still the backbone of any data management system. CRUD remains essential to ensure that the application’s complex functionalities can operate effectively.

The list goes on and on.

Once You Spot CRUD, You’ll Start Seeing It Everywhere!

Once you understand how CRUD works, you’ll start recognizing its patterns in all kinds of software.

These four magic letters are so fundamental to data management, it quietly powers a wide variety of interactions — even ones that don’t seem obvious at first glance. The more familiar you are with this concept, the easier it becomes to see how deeply integrated it is in almost every digital system.

It’s like discovering the hidden building blocks behind the digital world.

All you need is CRUD!

Richard

The post All You Need Is CRUD? appeared first on phpGrid - PHP Datagrid.

]]>
10180
PHP Composer to Autoload a Third Party Library https://phpgrid.com/blog/php-composer-to-autoload-a-third-party-library/ Wed, 18 Jan 2023 22:27:18 +0000 https://phpgrid.com/?p=10058

What is exactly a Composer in PHP? PHP Composer is a dependency management tool for PHP. It allows developers to declare the libraries their project depends on and it will manage (install/update) them for you. Composer uses a file called “composer.json” to manage dependencies. In this file, you list the dependencies your project has, along […]

The post PHP Composer to Autoload a Third Party Library appeared first on phpGrid - PHP Datagrid.

]]>

What is exactly a Composer in PHP?

PHP Composer is a dependency management tool for PHP. It allows developers to declare the libraries their project depends on and it will manage (install/update) them for you.

Composer uses a file called “composer.json” to manage dependencies. In this file, you list the dependencies your project has, along with version constraints. Once you have defined your dependencies, you can use the Composer command line tool to install them.

Adding a package dependence

To add a package dependence manually in Composer, use “require” command.

For example, if you want to add the package “monolog/monolog” as a dependency to your project, you would run the following command in your project’s root directory:

1
composer require monolog/monolog

This will add the package to the require section of your composer.json file and install the package and its dependencies into the “vendor” directory.

You can also specify the version number of the package that you want to install by doing the following:

1
composer require monolog/monolog:1.0.*

The above command will install version 1.0 or any version that starts with 1.0 like 1.0.1, 1.0.2

Once you have added a package as a dependency, you can update or remove it using Composer as well. You can run “composer update” command to update all the dependencies or update only a specific package this way:

1
composer update monolog/monolog

And to remove a package, use remove command.

1
composer remove monolog/monolog"

Once you have all the required dependencies, simply run the following install command

1
composer install

Composer will download the dependencies and their dependencies recursively and install them in a directory called “vendor”. The dependencies can then be autoloaded using the Composer’s autoloader.

What is Composer autoloading?

Now move on to an important Composer feature: autoload. Autoloading is a way to automatically include the necessary files when a class is used in an application, without having to manually include or require each file. This can greatly simplify the organization and maintenance of your codebase.

So instead of having to manually include a large number of files at the top of each script, you can simply use the classes you need and let the autoloader handle the rest. You can organize your code into different namespaces and directories, without having to worry about manually including the correct files.

In other words, Composer autoload replaces the old way of using include and require on top of every PHP script.

More about autoloading: https://getcomposer.org/doc/01-basic-usage.md#autoloading

Autoload a 3rd party library manually

You can also manually add a 3rd party library, such as phpGrid, to the autoload section in Composer. There are a few ways to load a 3rd party class in the Composer autoloader.

1. Using the “classmap” autoloading method

This method allows you to specify a list of specific files that should be included in the autoloader. You can add the classmap entries to the “autoload” section of your composer.json file like this:

1
2
3
4
5
6
7
"autoload": {
    "classmap": [
        "path/to/example/class1.php",
        "path/to/example/class2.php",
        "path/to/example/class3.php"
    ]
}

2. Use “files” autoloading method

This method allows you to specify a list of files that should be included in the autoloader. You can add the files entries to the “autoload” section of your composer.json file like this:

1
2
3
4
5
"autoload": {
    "files": [
        "path/to/phpGrid/conf.php"
    ]
}
Using files autoload is recommended method to add phpGrid in Composer.
X

You can combine different autoload methods in the same composer.json file, with a combination of psr-4, classmap and files.

Don’t forget to run composer dump-autoload

It is important to note that when you use the classmap and files autoloading method, you need to run the composer dump-autoload command after adding or modifying the files/classmap, for the autoloader to be updated.

1
composer dump-autoload

That’s is for all about PHP Composer and its autoloading. Hope you finding it useful in your PHP coding journey, and happy gridding!

The post PHP Composer to Autoload a Third Party Library appeared first on phpGrid - PHP Datagrid.

]]>
10058
How does Javascript debounce work? https://phpgrid.com/blog/how-does-javascript-debounce-work/ Tue, 01 Nov 2022 17:11:59 +0000 https://phpgrid.com/?p=10051

What is debounce? A recent increasing popular technique in web applications is an interesting one. It is so called “debounce”. Debouncing in JavaScript is used to limit the rate at which a function can fire. It works by delaying the execution of a function until a certain amount of time has passed without it being […]

The post How does Javascript debounce work? appeared first on phpGrid - PHP Datagrid.

]]>

What is debounce?

A recent increasing popular technique in web applications is an interesting one. It is so called “debounce”. Debouncing in JavaScript is used to limit the rate at which a function can fire. It works by delaying the execution of a function until a certain amount of time has passed without it being called. This can be useful in cases where a function is called multiple times in a short period of time, such as when a user is typing into an input field, and you only want to perform an action after they have finished typing.

Debounce real world analogy

A real world analogy of debounce is to a physical button, once is pressed, it remains in the pressed state (.e.g stays in the housing socket) for a number period of time, during which cannot be pressed again since it is already in pressed down position, before it “bounces” back that can be pressed again.

Javascript implementation

To implement debouncing in JavaScript, you can use a function that sets a timer whenever it is called. If the function is called again before the timer has expired, the timer is cleared and reset, delaying the execution of the function until the timer has expired.

Here is an example of a debounced function in JavaScript:

1
2
3
4
5
6
7
8
9
function debounce(fn, delay) {
  let timer;
  return function() {
    clearTimeout(timer);
    timer = setTimeout(() => {
      fn.apply(this, arguments);
    }, delay);
  };
}

In this example, we have a debounce function that takes two arguments: a callback function fn and a delay time delay. It returns a new function that sets a timer whenever it is called, and calls the callback function only if the timer has expired and no further calls have been made to the returned function.

You can use this debounced function as a wrapper for any function that you want to limit the rate of execution.

1
const debouncedFunction = debounce(myFunction, 1000);

This code creates a new debounced function that calls the myFunction once per second at most.

The post How does Javascript debounce work? appeared first on phpGrid - PHP Datagrid.

]]>
10051
When to use encodeURI() and encodeURIComponent()? https://phpgrid.com/blog/when-to-use-encodeuri-and-encodeuricomponent/ Fri, 25 Mar 2022 19:14:58 +0000 https://phpgrid.com/?p=9924

People talk about URL and URI as if they are the same things. However, the difference is subtle but important one. So what is a URI and how is it different from a URL? In short, • URI identifies, URL identifies and locate • URL is a subset of URI Clear as mud? Let’s put […]

The post When to use encodeURI() and encodeURIComponent()? appeared first on phpGrid - PHP Datagrid.

]]>

People talk about URL and URI as if they are the same things. However, the difference is subtle but important one.

So what is a URI and how is it different from a URL?

In short,

• URI identifies, URL identifies and locate
• URL is a subset of URI

Clear as mud? Let’s put semantic out of the way.

The URI is anything that uniquely identifies a resource, such as a name, or an ISBN number. A URL identifies a resource and describes how to access it (the protocol). Although all URLs are URIs, not all URIs are also URLs.

What is the purpose of encoding?

This is because only characters from the standard 128-character ASCII set are allowed in URLs. Many special characters, such as spaces and slashes, are not permitted.

For example, characters such as ~!@#$&*()=:/,;?+’ are special characters need to be encoded in URL.

encodeURIComponent() and encodeURI()

encodeURIComponent() and encodeURI() are native javascript utility functions encodes a URI that replaces URL reserved characters with their UTF-8 encoding.

encodeURI() should be used to encode an entire URI, and encodeURIComponent() should be used to encode a URI Component, which is a string that is expected to be part of a URL, which is similar to PHP rawurlencode function.

Let’s see a few examples:

encodeURI a URL (OK)

1
2
encodeURI("https://www.example.com/my file has special &amp; 8=-/*characters.html")
// Output: https://www.example.com/my%20file%20has%20special%20&amp;%208=-/*characters.html

encodeURIComponent a query parameter (OK)

1
2
3
let param = encodeURIComponent('special */- parameter')
let url = "https://example.com/?foo=" + param + "&amp;bar=xyz";
//Output: https://example.com/?foo=special%20*%2F-%20parameter&amp;bar=xyz

encodeURIComponent entire URL (WRONG!)

1
2
encodeURIComponent('https://www.example.com/my file has special &amp; 8=-/*characters.html')
// Ouput: 'https%3A%2F%2Fwww.example.com%2Fmy%20file%20has%20special%20%26%208%3D-%2F*characters.html'

Summary

Encoding URLs have become increasing important due to the popularity of the front-end frameworks, such as React and Vue. These features are essential in today’s single-page web apps for dynamic routes. Use encodeURI if you have a whole URL. However, if you only have a portion of a URL, encodeURIComponent is the way to go.

 

Technical readings:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI

The post When to use encodeURI() and encodeURIComponent()? appeared first on phpGrid - PHP Datagrid.

]]>
9924
Typed Properties in PHP 7.4 https://phpgrid.com/blog/typed-properties-in-php-7-4/ Tue, 15 Mar 2022 18:02:44 +0000 https://phpgrid.com/?p=9908

Introduction Many languages, especially scripting languages, have a loosely typed variables that are weakly typed. In the weak typed languages, variables can hold any type of values. For example, when you assign a number to a variable, it will be treated as a number; or string when assigned a text, etc. Typed class properties were […]

The post Typed Properties in PHP 7.4 appeared first on phpGrid - PHP Datagrid.

]]>

Introduction

Many languages, especially scripting languages, have a loosely typed variables that are weakly typed. In the weak typed languages, variables can hold any type of values. For example, when you assign a number to a variable, it will be treated as a number; or string when assigned a text, etc.

Typed class properties were introduced in PHP 7.4 around 2019. It has only two requirementss:

1. Typed Properties can only be in classes,
2. It must has one of the following visibility modifiers: public, protected, or private; or var.

With the exception of void and callable, all types are allowed:

* string
* int
* bool
* float
* array
* iterable
* object
* ? (nullable)
* self & parent
* Classes & interfaces

This is what they look like in action:

1
2
3
4
5
6
7
8
9
10
class Orders
{
    public int $id;

    public ?string $description

    protected static string $status

    private array $list;
}

Why typed properties?

Strong typed properties allows tools like code-analysis to help programmers in preventing runtime problems during coding, safe refactoring and application scaling.

It ensures the same data type being used through out the code, and catches at ‘mixed’ types early at ‘compile’ time, albeit PHP being a dynamic language. For example, when multiplying a string by an integer or assigning an integer to a string variable type, the type checking can help you uncover issues without running the code by doing a quick and simple static analysis.

Initialize typed properties

It’s possible to provide a default value to typed properties.

1
2
3
4
5
6
7
8
9
10
class Orders
{
    private int $id;

    public ?string $description = 'my description';

    protected static string $status = 'Status';

    private array $list = [1, 2, 3];
}

It’s worth noting that it’s OK to have an uninitialized property outside of the constructor such as $id in code sample above as long as nothing it is not accessed before it is initialized (assigned with a value).

If typed values not initialized, the second obvious place to initialize would be the constructor:

1
2
3
4
5
6
7
8
9
class Order
{
    public int $id;

    public function __construct(int $id)
    {
        $this->id = $id;
    }
}

Strict types

Because PHP is the dynamic language, even with the typed properties, it will always try to coerce or convert types whenever possible. If you supply a string instead of an integer, PHP will attempt to convert it automatically.

The following code (with typed variables) is valid and will convert ‘1’ to 1.

1
2
3
4
5
6
7
8
class Order
{
    public int $id;
}

$order = new Order;

$order->id = '9'; // converted to integer 9

To enforce our typed variables, declare strict types before class:

1
declare(strict_types=1);

It will throw a TypeError:

1
2
Fatal error: Uncaught TypeError:
Typed property Order::$id must be int, string used

Final thought

Typed variables are a huge step forward for PHP’s future. Despite this, PHP is not a strong type programming language, and it probably never will be.

Happy coding!

You can find more details on PHP.net official typed properties.

The post Typed Properties in PHP 7.4 appeared first on phpGrid - PHP Datagrid.

]]>
9908