What’s the best practice for placement of functions that are used across multiple MVC layers?
I’ve recently had to write some statistics functions that are used both in the View and the Model. If I put them in a helper, I’m stuck loading helpers in the model layer, which is annoying, seems incorrect, and breaks completely when those functions are called from a task (because there is no default context). If I put them in the top level
lib directory, I’m stuck making calls like
Stats::normalPercentile in the view.
Are there any other options? Are there any comments from Symfony devs on where functions like these should be placed?
Edit: Apparently there’s no issue with making static calls in views. I inferred this based on Symfony not writing their helpers as classes (even after significant discussion.) In that case, are there any conventions for placing files like these? Just throw them in
Regarding your edit, symfony’s helpers are written like that to avoid cluttering the view with syntax that might be unfamiliar to less technical folk who normally come into contact with a little PHP – functions being first-class citizens in ‘vanilla’ PHP. It’s a philosophy drawn from Ruby on Rails, which inspired this part of the framework.
Storing files in
lib/ is a personal preference as symfony doesn’t really mind, but the nomenclature would suggest
If it’s good code, you might want to guard it jealously in that little
yourname directory… if it’s really good code, you might want to package it and share it with others 🙂
What’s wrong with static calls? I think it’s perfect for helper functions (better than functions as you have a kind of namespacing).
It’s quite weird to gather stats in a view. Why don’t you do it in an action?
Probably right answer depends on the kind of problem you’re trying to solve (you didn’t explain what exactly your helpers should do). I usually use such helpers for common tasks which don’t require any additional classes or calls (like “stripText”).
Statistical calculations does not belong to the View. Consider adding them to the Model layer. The
lib/model seems both OK to me. For example you could have a class
PercentileSequence which fed with data could be reused in both your views and tasks like this:
// in your action, component or task $this->mySequence = new PercentileSequence($data); // in your view (if PercentileSequence implements Iterator) <?php foreach ( $mySequence as $rank ): ?> <?php echo $rank ?> <?php endforeach; ?> // or use plain old array <?php foreach ( $mySequence->getRanks() as $rank ): ?> <?php echo $rank ?> <?php endforeach; ?>
It should be the same within a task.