../courses.php
CRM
CRM101
90
Reports And Business Decisions
Use CRM information to understand what is happening in the business.
Counting "how many leads do we have" by hand, scrolling through fifty contacts and tallying status fields one by one, takes several minutes and is easy to miscount. The exact same number, computed by PHP, takes a fraction of a second and is never wrong. What's actually different about the two approaches, beyond just speed?
A hand count depends on someone reliably noticing and tallying every matching record without missing one or double-counting — a real, human source of error that grows the longer the list gets. A computed count runs the exact same
array_filter() logic already used for search and status filtering in earlier lectures, and then simply counts how many results came back — the same data, examined by a process that doesn't get tired, distracted, or lose count partway through.
A report isn't a new kind of data — it's an existing question, answered by counting or summarizing the same contact records this entire course has already been working with, just phrased as "how many" or "what's the total" instead of "show me the list."
count() on a PHP array returns how many items it contains — combined with
array_filter() from earlier lectures, this is enough to answer "how many leads" or "how many tasks are still open" directly from the same data already in memory.
Several small report numbers — total contacts, total leads, total open tasks — sitting together at the top of the page give a fast, real answer to "what's going on right now" without anyone scrolling through individual records to find out.
A report number is only as honest as the data behind it — if contacts are missing a status field, as covered as a real risk in lecture 3, a "how many leads" count built on that data will quietly be wrong, without showing any error.
This lesson adds a small dashboard of report numbers to the top of the CRM, built entirely from
count()
and
array_filter()
applied to data this course has already been working with for eight lectures.
The CRM, stage seven: real numbers, computed from the actual data
<?php
$contactsFile = __DIR__ . '/contacts.json';
$contacts = json_decode(file_get_contents($contactsFile), true);
$totalContacts = count($contacts);
$totalLeads = count(array_filter($contacts, function ($c) {
return $c['status'] === 'lead';
}));
$openTasks = 0;
foreach ($contacts as $contact) {
$openTasks += count(array_filter($contact['tasks'], function ($t) {
return $t['done'] === false;
}));
}
?>
<div>Total contacts: <?php echo $totalContacts; ?></div>
<div>Total leads: <?php echo $totalLeads; ?></div>
<div>Open tasks: <?php echo $openTasks; ?></div>
$totalContacts = count($contacts); — The simplest possible report: how many items are in the array, full stop, with no filtering needed at all.
count(array_filter($contacts, ...)) — Reuses lecture 3's exact lead-filtering condition, then wraps the result in
count() — the filtered array from earlier lectures and this report's number come from the literal same logic.
$openTasks += count(array_filter($contact['tasks'], ...)); — A loop inside a loop: for every contact, count how many of their own tasks are still undone, and add that to a running total across every contact in the system.
$openTasks = 0;, set before the loop — A running total has to start somewhere — initializing it to zero before the loop begins is what makes
+=
inside the loop actually accumulate correctly across every contact.
Three numbers, three already-known tools —
count()
and
array_filter()
are the entire toolkit behind all three reports here — nothing new had to be learned, only recombined.
A computed count is immune to the specific way human counting fails
A person counting fifty contacts by hand might lose their place, count one twice, or miscategorize a borderline case — none of those specific failure modes apply to
array_filter()
checking the exact same condition against every single record, every time, identically.
A report is only as accurate as the data feeding it
If even one contact is missing its
status
field — the exact risk named back in lecture 3 — the lead count quietly undercounts by exactly one, with the displayed number looking just as confident and correct as if every contact were properly tagged.
Reusing existing filtering logic for a report keeps the count and the underlying list in sync
Because the report's lead count uses the literal same condition as the leads-only filtered view from lecture 3, the two can never quietly disagree with each other — a separate, independently written counting formula could drift out of sync with the actual filtered list over time.
A missing tasks array on one contact would silently skip that contact's count, not crash the whole report
If one contact were missing its
tasks
field entirely, the inner
array_filter()
call for that specific contact would fail, but depending on exactly how PHP handles that specific error, the rest of the report's calculation might continue or might stop entirely — worth testing directly rather than assuming.
A report number that's wrong but looks confident is more dangerous than no report at all
A business owner making a real decision based on "we have 12 leads" when the actual number, properly counted, is 13, is acting on confidently wrong information — exactly the kind of unverified claim the AI course elsewhere in this catalog warns against trusting just because it's displayed clearly.
A count with no clear starting point — avoid
foreach ($contacts as $contact) {
$openTasks += count(array_filter($contact['tasks'], function ($t) {
return $t['done'] === false;
}));
}
A running total, explicitly started at zero — use this
$openTasks = 0;
foreach ($contacts as $contact) {
$openTasks += count(array_filter($contact['tasks'], function ($t) {
return $t['done'] === false;
}));
}
Paste your report-generating PHP code into ChatGPT and ask: "Does every counting variable here have an explicit starting value before the loop, and would a contact missing a tasks or status field break this calculation?" It's good at spotting an uninitialized variable, though testing with a deliberately incomplete contact record is worth doing directly.
Add the three report numbers from this lesson to the top of your CRM page.
Manually count your actual contacts, leads, and open tasks by reading the JSON file, and confirm the computed numbers match.
Remove the status field from one contact and observe whether the lead count silently changes.
Add a fourth report number — total customers — reusing the
array_filter() pattern with a different condition.
Remove the tasks field from one contact entirely and observe exactly what happens to the open-tasks report.
Using a counting variable inside a loop without explicitly initializing it to zero beforehand.
Writing a separate, independent formula for a report number instead of reusing the exact same filtering condition already used elsewhere, risking the two quietly drifting out of agreement.
Trusting a report number as automatically correct just because it was computed, without considering whether the underlying data has any missing or inconsistent fields.
Assuming a missing field on one record will obviously and loudly break a report, rather than checking specifically what actually happens.
Treating manual counting and computed counting as equally reliable, when manual counting has real, predictable human failure modes a computed count doesn't share.
Build report numbers using count and array_filter on existing data, reuse a filtering condition consistently between a list view and its corresponding count, and explain why a confidently displayed report number still depends entirely on the completeness of the data behind it.
Login - Jit4All
Login
Welcome back to Jit4All