Is using Configure::read() inside a View against MVC?

As title says, is this OK or Should I add an extra step and read it through a Helper?

Example code inside a Template file:

<?php
/**
 * @var \App\View\AppView $this
 * @var \App\Model\Entity\Complaint $complaint
 */

use Cake\Core\Configure;

?>

<?php if (Configure::read('debug')) : ?>
<div class="alert alert-danger" role="alert">
   DEBUG IS ACTIVE!
</div>
<?php endif; ?>

I’m not an authority on this, but I read from Configure all the time in views. Among other things, I have a settings table with a bunch of runtime settings that get written into the configuration, and many of those are specifically view-related.

In my opinion the View should not contain any business logic (even a simple logic like Configure::read()). Any business logic must be inside a controller which in turn passes only variables to the View.

The point of MVC is to make your life easier now and in the future. Being a purist about things just for the sake of purism is, imo, an approach unlikely to serve you well over time. In the absence of solid understanding or a compelling reason to violate a purist approach, sure, stay purist. Someone else went through the trouble of figuring this stuff out and it’s best when unsure or blind to keep to their formula.

But if you know what you’re doing and why you’re doing it… that’s a healthy first step toward making things work for you regardless of formula. The next step is to consider the impact downstream of your decisions and make sure you aren’t inadvertently shooting yourself in the foot or admit when you’re taking a short-term easy route but sacrificing the long term for it.

That preamble out of the way:

Why not just add an actual debug() statement? If config debug is true, it will show up, if not it won’t. Alternatively, consider adding classes that highlight that you’re on development vs production (which I think is more important than whether debug is turned on or not… and debug should always be off on production, period… a rule, I think, that is more important than MVC).

In the past, I have enabled certain flags to appear depending on user logged in, user role, and IP address. All designed to aid the exact kind of scenario you describe. I do these things in a combination of App Controller and default layout file. Sometimes a session variable thrown in.

Anyway… I see no problem with using Configure::read(‘debug’) in a view file. I would hope it’s in a layout file and not scattered throughout many view files, however. Also, I believe using such a simple, direct and highly visible/obvious means of doing such would serve me far far more than attempting to do it in my controllers and passing this to my views. Too abstract for something so raw and critical.

2 Likes

Thanks to all for answering.

That was just an example.

Actually, I’m using this for javaScript console.log() & alert():

<script>
// [...]
$.ajax({
    // [...]
    beforeSend: function(xhr) {
        xhr.setRequestHeader('X-CSRF-Token', '<?= $this->getRequest()->getAttribute('csrfToken'); ?>');
    },
    success: function(data, textStatus) {
        if (!data.error) {
            // [...]
        } else {
            <?php if (Configure::read('debug')) : ?>
            console.log(data);
            console.log(textStatus);
            <?php endif; ?>
        }
    },
    error: function(jqXHR, textStatus, errorThrown) {
        <?php if (Configure::read('debug')) : ?>
        alert(errorThrown);
        <?php endif; ?>
    }
});
</script>

I think it’s a good idea, but I might be wrong. Also, I know there are JS compilers/minifiers that remove console.log()s but I still use JS the old way…

Might be better in that case to set a view variable in AppController:

if( ... )
$this->set('debug',true);
else
$this->set('debug',false);

And then in your view code, you just do <?if($debug):?>

Possibly might be good to go as far as creating a Helper for this kind of task. Some collection of debug-safe JS routines you can just throw in wherever you want.

Looking by the code used, something like this would be even cleaner in the controller (given that you use PHP 7 or newer):

$this->set('debug', Configure::read('debug') ?? false);

That will automatically check if Configure::read('debug') doesn’t return null (which means the key isn’t set in the config) and if it does default to false (otherwise, it’ll just use the value set in the config obviously).

Getting back on topic, Using Configure::read inside the template is kinda against the purpose of MVC, however, since I’m not a purist, I generally ask myself: “can a front-end developer with very little knowledge on back-end PHP quickly understand this?” and “does this not increase complexity of the template?”.
If the answer is yes: I allow myself to use it in the template.
If the answer is no: I keep it inside the controller.

For example take this piece of code.
I could write it like this in my template (yes, I could use a ternary operator here too but that’s not the point):

<div class="container">
  <?php if(Configure::read('debug') === true): ?>
    <!-- Bypassed blogpost render cache -->
    <?= $this->shortcode->doShortcode($article->body, ['cache' => null]); ?>
  <?php else: ?>
    <!-- Use blogpost render cache -->
    <?= $this->shortcode->doShortcode($article->body, ['cache' => 'blog-rendered-' . $article->hash]);
  <?php endif; ?>
</div>

Yes, it’d be reasonably understandable, but I could also make it easier on my “front-end developers” by doing this in my controller:

$this->set('shortcodeCache', Configure::read('debug') ? null : 'blog-rendered-' . $article->hash);

And then just having the front-end developer only write this:

<div class="container">
  <?= $this->shortcode->doShortcode($article->body, ['cache' => $shortcodeCache]);
</div>

As you can see, I have now achieved the same effect, without making my template bloated and more complex.
Additionally, if the logic to decide whether to use the cache changes (eg. disabling it for certain users/roles, disabling it based on whether the post is popular enough - to save some memory in my cache -, changing the way we get the cache name etc.), the template won’t get bloated for those things and I don’t need to bother my front-end developers with it at all (they don’t care about it, they just know they need to pass $shortcodeCache down and that’s it).

However, something like this:

<?php if(Configure::read('debug') === true): ?>
  <div class="container">
    You are using this app in debug mode!
  </div>
<?php endif; ?>

Barely increases the complexity because it is barely any different from this, and as such, I’ll allow it:

<?php if($debug === true): ?>
  <div class="container">
    You are using this app in debug mode!
  </div>
<?php endif; ?>