Magical Drupal messages, Empty Emails and Wrong API Responses.
(Client and environment details anonymized.)
The Setup: PowerPoint Documentation Meets Reality
Another day, another legacy system integration nightmare. This time it's about building integrations when "documentation" is a PowerPoint slide and debugging happens through client screenshots.
The Setup
Working on a multi-step employee benefits form for a municipal client. Classic government tech stack: aging Drupal, legacy databases, and web services held together by prayers.
No product owner. No project manager. Just clients who know they want "something" but try their best to articulate what. Communication happens through:
- PowerPoint slides with blurry screenshots
- Word docs with tables that make no sense
- "Can you just make it work like the old system?"
Well I'm supposed to be here to improve this mess... - Endless back-and-forth meetings that clarify nothing
The workflow was supposed to be straightforward:
User checks eligibility → /mon_cet (separate webform)
| Does API the data pass over to the next page? euh well... ? who knows ? ¯\_(ツ)_/¯
↓
User makes their savings choices → /demande_epargne (separate webform!?)
(if eligibilitechoix should happen here) (if email trigger with eligibiliteChoix)
↓
Validates options → /choix_des_options (separate webform again !)
↓
Gets final confirmation → (email trigger)
According to a 5-slide PowerPoint with Comic Sans font, the web service would return eligibiliteChoix: "Yes" for eligible users and "No" for ineligible ones.
Simple enough. Should work perfectly.
Should.
The Double Problem: Hooks + Hidden Truth
Built the integration exactly as the PowerPoint "documented":
function processSubmission($webform_submission) {
$data = $webform_submission->getData();
if ($data['eligibilitechoix'] === 'Non') {
// Handle ineligible user, send email.
return;
}
// Process eligible user...
}
But here's the double kicker:
- You can't test any of this locally
- Drupal hooks fire on every form step, not just completion
No dev environment that connects to the web service. No integration environment. The only way to test is on the production-adjacent staging environment, using the client's actual account.
Meanwhile, hook_webform_submission_insert() fires on every form submission in the multi-step workflow. Users see "1 request sent successfully" followed immediately by "Unable to send email" errors. Imagine all the double API calls?
The Debugging Hell: Screenshots and Guesswork
The development cycle becomes:
- Make code changes blind
- Ask client to deploy to staging
- Wait for deployment
- Ask client to test with their login
- Get back screenshots (without URLs) of error messages
- Try to decode what went wrong from limited context
- Repeat this nightmare cycle
Spent days debugging Drupal's hook behavior:
\Drupal::logger('debug')->info("State: " . json_encode($webform_submission->getState()));
Result: "completed" for every single form submission. Each step in the multi-step workflow triggered the hook, thinking it was done.
The logging showed 4 total executions:
- 2 calls for step 1 submission
- 2 calls for step 2 submission
Each time convinced it was the final step. Each time wrong.
Tried everything:
- Different hooks (
hook_webform_submission_update) - Custom completion flags
- Queue-based delayed processing
- Message suppression hacks
Nothing worked because I was solving the wrong problem.
The Real Culprit: PowerPoint "Documentation"
After exhausting every Drupal debugging avenue, decided to actually look at the web service response instead of trusting the Comic Sans slides:
{
"eligibiliteChoix": "Yes",
"soldeCET": "0.00",
"transfertrealise": [
{ "code":"BENEFIT_A", "valeur":"0.00" },
{ "code":"BENEFIT_B", "valeur":"0.00" }
]
}
Wait. What?
The "eligibility choice" field was returning "Yes" or "No" like the PowerPoint claimed. But the actual webservice that was supplying wasn't doing their job.
The API was also returning numeric strings: "value": "0.00" for ineligible, non-zero values for eligible.
The entire hook debugging rabbit hole was caused by trusting a PowerPoint slide over reality.
Classic scenario: "But the documentation says..."
"That's a screenshot from 2024, not documentation"
"Well, what should it return then?"
"I don't know, ask the other team"
"The other team doesn't exist anymore"
"Can you just... make it work somehow?"
The Fix: Reality Check
Updated the eligibility logic to match what the service actually returns:
function processSubmission($webform_submission) {
$data = $webform_submission->getData();
// Reality: service returns "0.00" for ineligible, not "No"
if ($data['value'] === '0.00') {
// Handle ineligible user and send email!
return;
}
// Process eligible user... fixed after 6PM by e-mail because the client realized that "eligibiliteChoix" wasn't the right value to use.
}
Suddenly that part worked. No more premature hooks. No some blank emails. No more confused users.
The Email Problem
Of course, there was a bonus issue. The email template was skipping all zero values:
The way the logic was built was half front end/office
The Hook Solutions (That Actually Work)
Option 1: Use a different hook
function hook_webform_submission_update($webform_submission) {
// Fires when submissions are updated, not initially created
}
Option 2: Custom workflow tracking
// Set a flag when entire process is complete
if ($form_id === 'final_step' && workflow_is_actually_complete($data)) {
// Send email only now
}
The Lesson
Never trust PowerPoint slides as technical specifications. And never work without proper testing environments.
When you can't test locally, can't reproduce issues, and rely on client screenshots for debugging, every assumption becomes a liability. The development cycle becomes:
- Build based on vague PowerPoint requirements
- Deploy blindly to production-adjacent environment
- Wait for client testing feedback via screenshots
- Try to decode error messages without context
- "That's not what we wanted"
- "What did you want?"
- "Something different..."
- Repeat until everyone gives up
I must admit over the days, I started to lose memory over what the client really wanted.
I spent days debugging Drupal hooks that were working perfectly. But having messages appear randomly from other modules killed me. One issue was believing a PowerPoint presentation and not demanding proper API specifications upfront from the 3rd party managing the API
Key takeaways:
- Don't trust
getState()for workflow completion. It lies. - Don't trust hooks to understand your business logic. They're dumb.
- Don't trust PowerPoint slides as API documentation. They're fiction.
- Demand proper testing environments and data format specs upfront
Final Thought
We used to build integrations with proper dev environments, clear specifications, and the ability to actually test our code. Now I have to build blindly, deploy to production, and pray the client's screenshots contain enough context to debug the inevitable failures.
When there's no real product owner, no project real manager, no actual documentation, and no testing environment - assume everything is wrong, demand better specs upfront, and prepare for the "Oh, did we mention..." conversations that happen after you've already deployed.
The classic "ask the team that doesn't exist anymore" scenario is just the cherry on top of this clusterfuck sundae.
The Kitchen Nightmare: An Allegory
Picture this: You used to work in a proper restaurant kitchen. You had recipe cards with exact measurements, a prep station where you could taste and adjust seasonings, and a sous chef who'd sample everything before it went to the dining room. If something wasn't quite right, you could fix it before the customer ever saw it.
Now imagine you've been asked to cook for a high-end catering event, 13000 people, but here's the catch: You have to prepare everything blindfolded, in a kitchen you've never seen before, using mystery ingredients. There's no recipe - just a crumpled napkin with "make it delicious" scrawled in crayon. You can't taste anything as you go. And once you're done cooking, you have to send the food directly to the guests' tables without ever seeing it yourself.
When the inevitable complaints come back ("This is too salty!" "Where's the garnish we ordered?" "This isn't even the right dish!"), you have to guess what went wrong based on blurry photos someone texted you from the dining room.
Oh, and there's no head chef to consult, no catering manager to clarify what the client actually wanted, and no written contract specifying the menu. The event planner quit last week, and when you ask for guidance, everyone just shrugs and says, "Ask the previous catering team" - the one that disbanded twleve months ago.
And on their way out. I kid you not, they said. "This is the cleanest project of the entire..." It's not
Your survival strategy? Assume the napkin-scrawled instructions are wrong. Demand to see a real menu with ingredients, portions, and cooking times before you even preheat the oven. And brace yourself for the inevitable phone call that starts with, "Oh, did we mention half the guests are vegan and three are allergic to everything?"
Because in this kitchen nightmare, the only thing you can count on is that nobody counted on anything going right.
Thank you for reading.
No PowerPoint presentations were trusted in the making of this post.