Avoiding the creation of a meta programming language

My largest criticism of Symphony (both version), and most frameworks built on the Zend Toolset (which I refuse to call a framework anymore than I’d call a stack of lumber the framing of a house) such as Magento is that they end up creating their own little programming meta languages in either xml, yaml, or the like.

Consider this excerpt from Magento’s app/design/frontend/base/default/layout/page.xml file



-->
<layout version="0.1.0">
<!--
Default layout, loads most of the pages
-->

    <default translate="label" module="page">
        <label>All Pages</label>
        <block type="page/html" name="root" output="toHtml" template="page/3columns.phtml">

            <block type="page/html_head" name="head" as="head">
                <action method="addJs"><script>prototype/prototype.js</script></action>
                <action method="addJs"><script>lib/ccard.js</script></action>
                <action method="addJs"><script>prototype/validation.js</script></action>
                <action method="addJs"><script>scriptaculous/builder.js</script></action>
                <action method="addJs"><script>scriptaculous/effects.js</script></action>
                <action method="addJs"><script>scriptaculous/dragdrop.js</script></action>
                <action method="addJs"><script>scriptaculous/controls.js</script></action>
                <action method="addJs"><script>scriptaculous/slider.js</script></action>
                <action method="addJs"><script>varien/js.js</script></action>
                <action method="addJs"><script>varien/form.js</script></action>
                <action method="addJs"><script>varien/menu.js</script></action>
                <action method="addJs"><script>mage/translate.js</script></action>
                <action method="addJs"><script>mage/cookies.js</script></action>

                <block type="page/js_cookie" name="js_cookies" template="page/js/cookie.phtml"/>

                <action method="addCss"><stylesheet>css/styles.css</stylesheet></action>
                <action method="addItem"><type>skin_css</type><name>css/styles-ie.css</name><params/><if>lt IE 8</if></action>
                <action method="addCss"><stylesheet>css/widgets.css</stylesheet></action>
                <action method="addCss"><stylesheet>css/print.css</stylesheet><params>media="print"</params></action>

                <action method="addItem"><type>js</type><name>lib/ds-sleight.js</name><params/><if>lt IE 7</if></action>
                <action method="addItem"><type>skin_js</type><name>js/ie6.js</name><params/><if>lt IE 7</if></action>
            </block>

            <block type="core/text_list" name="after_body_start" as="after_body_start" translate="label">
                <label>Page Top</label>
            </block>

            <block type="page/html_notices" name="global_notices" as="global_notices" template="page/html/notices.phtml" />

            <block type="page/html_header" name="header" as="header">
                <block type="page/template_links" name="top.links" as="topLinks"/>
                <block type="page/switch" name="store_language" as="store_language" template="page/switch/languages.phtml"/>
                <block type="core/text_list" name="top.menu" as="topMenu" translate="label">
                    <label>Navigation Bar</label>
                    <block type="page/html_topmenu" name="catalog.topnav" template="page/html/topmenu.phtml"/>
                </block>
                <block type="page/html_wrapper" name="top.container" as="topContainer" translate="label">
                    <label>Page Header</label>
                    <action method="setElementClass"><value>top-container</value></action>
                </block>
            </block>
...

That should be enough to get my point across. This “config” file has become a programming language in it’s own right. It’s about as foolish in my eyes as smarty. And yet, at the same time, I’m having difficulty coming up with an alternative. I understand the need to abstract things - but there’s got to be a better way. Aside from the code bloat, I’m wanting to build an instructional framework to demonstrate principles and handle small tasks. That is NOT what we have here.

(Disclaimer - I like Magento. But it could seriously need some DRY principles applied).

So I’ve been working with my framework bootloader and front controller. The routing schema is pretty simple. The htdocs directory is kept empty except for a landing.php file. Later I intend to develop a way to drop cache files into there and start from those files instantiating as little of the framework as possible. Meanwhile a “map” directory holds the page controller load files.

These files aren’t classes - they are proceedures meant to execute in the scope of the main dispatcher. They are loaded in this method.


protected function parsePage( $route ) {
		ob_start();

		if ( $route instanceof Route ) {
			require $route->path;
		} else {
			require( $route );
		}
		return ob_get_clean();
	}

The cache files will pass a path to themself to this function so $route could be that string or an object that contains two values, the path, and the path after. As you can see, it’s the only variable in scope when the require occurs. Let’s look at what I have for that file.


<?php
namespace PNL;

if ($route->pathAfter) {
	throw new FileNotFoundException();
}

$this->queue('layout');
	
//$response = $this->templates->fetch('testing');
//$response['title'] = "Hello World";
//$response['message'] = "This is a triumph. I'm making a note here, huge success.";
// echo $response;

The commented out section was a test that we can fetch a template, bind some data, and echo it out. I feel I need to be able to do this without classes before adding the classes into the mix. We are in an object buffer, so anything that goes out will be caught for postload processing. Since this index doesn’t support SEO rewrites it might catch, the check on path after is required to determine if we throw out to 404. The exception handlers don’t even use this loop. They get this rather elegant block to handle their output.


public static function exception( \\Exception $e) {
	try {
		print( Core::start()->templates->fetch(
				$e->template ? 'exception.'.$e->template : 'exception.default',
				$e->toArray()
			)
		);
		Core::stop();
	} catch ( \\Exception $er ) {
		if (!headers_sent()) {
			header("Content-Type: text/plain;");
			header("HTTP/1.0 500 Internal Server Error");		
			header('X-Generator: PNL');
		}
		print("PNL Framework has encountered an error from which it cannot recover\
");
		print("gracefully. Script terminated without proper closure. Exception Objects Follow\
");
		print("\
INITIAL FATAL EXCEPTION\
\
");
		print_r($e);
		print("\
FINAL FATAL EXCEPTION\
\
");
		print_r($er);
		exit;
	}
	return false;
}

In brief the above error handler first tries to use the normal template engine to do a pretty report of the error. If a new error gets thrown then it dies with what amounts to a BSOD.

What I’m trying to come up with is a layout, blocks loader pattern which will be the normal class load pattern. Although these files can, maybe sometimes will, just load a template and shoot it out, eventually I want to be able to pull on a reusuable block hive. These landing files do what the xml of Magento or yaml files of Symphony do, without introducing a new syntax into the mix. To do that though I have to choose my function and class names carefully, and I will be employing chaining.

If it makes you feel any better, the creators of Symfony seem to agree with you. Whereas Symfony1 had a view.yml file where you’d define the CSS, JS, meta tags, and more, now Symfony2 leaves that all to be done within the template.

But in any case, the reason all these frameworks try to come up with some kind of system is because the content of each page is dynamic, and each page may require a different set of assets. So there has to be some way for a sub-module or sub-template to communicate its dependencies.

Other times, a framework might prefer something like yaml only because it’s a cleaner and more succinct alternative to the pure-PHP version. For example, in Symfony2, these two code examples are equivalent.

// app/config/routing.php
use Symfony\\Component\\Routing\\RouteCollection;
use Symfony\\Component\\Routing\\Route;

$collection = new RouteCollection();
$collection->add('blog_show', new Route('/blog/{slug}', array(
    '_controller' => 'AcmeBlogBundle:Blog:show',
)));

return $collection;
# app/config/routing.yml
blog_show:
    pattern:   /blog/{slug}
    defaults:  { _controller: AcmeBlogBundle:Blog:show }

It seems to me you need to turn to a better framework that allows a better/simpler abstractization in handling templating. Like Jeff said, that leaves that all to be done within the template’s meta language.

I’m building a new framework who’s principle goal will be introduction to and instruction on using the MVC pattern. The target audience is programmers who’ve got a good handle on procedural PHP and are ready to make the leap to OO deployment. Introducing a template meta language (like smarty) or a controller meta language (like Magento or Symphony) runs counter to this stated purpose. To work as an instructional framework it must remain relatively simple. That means, often, refusing to provide tools in the framework for people who don’t know or aren’t willing to learn PHP.

A better framework for this purpose doesn’t exist. I’ve done a survey of the major frameworks out there and deployed test pages in all of them just to see what a beginner is up against. To their credit, all of them are relatively simple to get up and running - but when you go to add anything things start getting complex. When a framework requires adding 6 files to create a “Hello World” page, it has failed as an instructional tool. It might work well at other purposes, but a beginner is going to throw their hands up in frustration when confronted with such a requirement.

If the principle goal is to teach MVC, then this example is probably as simple as you’re ever gonna get. No fancy framework; just well organized flat PHP. It isn’t even strictly necessary to get into OOP.

Principle goal yes. Only, no. I’ll show it when it’s ready.

About templating. I like and use SlimPHP. And I’m a big fan of HAML. I don’t see how you’re going to make a good case against its use.

It sounds to me like a step back from a real MVC, denying access to outer templating.

In fact, a framework should have such a good level of abstractization that it would allow the use of any templating meta language, in one common interface, instead of dismissing a particular one.

True OOP.

[QUOTE=itmitică;5114137]About templating. I like and use SlimPHP. And I’m a big fan of HAML. I don’t see how you’re going to make a good case against its use.

It sounds to me like a step back from a real MVC, denying access to outer templating.

In fact, a framework should have such a good level of abstractization that it would allow the use of any templating meta language, in one common interface, instead of dismissing a particular one.

True OOP.[/QUOTE]

You do not have enough information to make a critique of what I’m doing. I should know because I haven’t provided it. And yet you insist on trying.

As for HAML - PHP is a templating engine. Running a templating engine within another templating engine is inefficient at best. If you cannot grasp that simple fact I’ve nothing to say to you.

BINGO.

… and it’s idiotic at worst. I HATE these so called ‘templating engines’ people put on top of languages like PHP – to the point I refuse to deal with anything that has them anymore. usually it just means someone has failed to grasp the POINT of includes, the POINT of functions, and the entire POINT of languages like PHP.

… and that’s BEFORE we even talk that using off the shelf libraries of userland code in an INTERPRETED language is one of the worst things you can do from a performance standpoint; be it idiotic half-assed rubbish in the Javascript world like jQuery or MooTools, or crippled slow nonsense like Smarty, HAML and ‘the rest’.

The Magento snippet in the OP’s post is a shining example of everything wrong with the “XML for everything” idiocy. XML is NOT an efficient data storage format, and what the devil is the point of writing XML to parse it into SGML/XML? Glad to see I’m not the only one who thinks that’s just a wee bit re-re…

I mean really, what in blue blazes is the point of:
<action method=“addJs”><script>prototype/prototype.js</script></action>

compared to
<script type=“text/javascript” src=“prototype/prototype.js”></script>

It’s even MORE CHARACTERS!!! HERPA-FREAKING-DERP!

Or this idiocy:
<action method=“addCss”><stylesheet>css/styles.css</stylesheet></action>
vs.
<link rel=“styleheet” type=“text/css” src=“css/styles.css” />

Uhm… YEAH. That’s just brilliant guys… (of course both lack proper use of MEDIA types!)

Then there’s this “real winner”
<block type=“page/html_head” name=“head” as=“head”>
vs.
<head>

color:#DDD;

It’s why whenever I encounter this type of idiocy, all I can do is scream at the display “Oh for crying out loud, just let me edit the blasted HTML and PHP!”

Actually, use a bit stronger language than that.

Idiotic bloated slow BS usually made by people who failed to grasp the point of or how to use the technologies at hand… it’s just more turns in the plumbing for crap to get stuck on clogging the drain.

Of course, when we’re talking dipshit coders who’s output ends up filled with absolute URL’s and classes/id’s on elements that don’t even need them, it becomes apparent most of the people making these systems don’t know enough HTML, CSS, PHP, or Javascript to even be opening their mouths on the subject! Take Magento’s website:

                   <li class="log-in" id="log_in_tab">
                <a class="umenu-tabs" id="log_in_lnk" href="#"><span><span><strong>Log In</strong></span></span></a>
                <div class="log-in-menu">
                    <div class="menu" id="top_menu" style="visibility:hidden;">
                        <div class="login-form">
                            <form method="post" action="https://www.magentocommerce.com/products/customer/account/loginPost/">
                                <p>
                                    <label for="login">Username or Email</label> 
                                    <div class="input-box">
                                        <input type="text" class="input-text" id="login" name="login[username]"/>
                                    </div>
                                </p> 
                                <p>
                                    <label for="password">Password:</label>
                                    <div class="input-box">
                                        <input type="password" class="input-text" id="password" name="login[password]" autocomplete="off" />
                                    </div>
                                </p>
                                <input type="hidden" name="login[back_url]" value="" id="login_back_url"/>
                                <script type="text/javascript">window.addEvent("domready", function() {$('login_back_url').value = window.location.toString().replace('https://', 'http://');});</script>                                <div class="col2-set">
                                    <div class="col-1">
                                        <!-- span class="fancy-chb-wrap"><input class="fancy-chb" type="checkbox" id="remember_pass" value="1" name="auto_login" /></span>
                                        <label for="remember_pass">Remember Password</label -->
                                        <!-- label for="hidden_user">Show my name in the online users list&nbsp;&nbsp;</label><input type="checkbox" id="hidden_user" checked="checked" value="1" name="anon"/ -->
                                        <p style="margin-top:5px;"><a href="http://www.magentocommerce.com/products/customer/account/forgotpassword/">Forgot Password</a></p>
                                    </div>
                                    <div class="col-2">
                                        <button type="submit" class="but-login">Login</button>
                                    </div>
                                </div>
                                <div class="or">or</div>
                                <a href="http://www.magentocommerce.com/products/customer/account/create/" class="register-but">Register</a>
                            </form>
                        </div>
                    </div>
                </div>
                                <script type="text/javascript">
                    $$('.login-form .input-text').each(function(inp){
                        inp.addEvent('focus', function(e){inp.getParent('div').addClass('box-over');});
                        inp.addEvent('blur', function(e){inp.getParent('div').removeClass('box-over');});
                    });
                </script>
                                <em id="hover_line"><span><span></span></span></em>
            </li>

If you think you know HTML and CSS, but don’t know what’s wrong with that, do the world a favor, back the devil away from the keyboard, and take up something a bit less detail oriented like macramé.

Seriously, dude, this is nowhere near true. In a former decade, maybe, but today, no. And it would be super awesome if you didn’t keep repeating demonstrably untrue claims.

REALLY? Wrapping existing function calls in extra function calls provides no performance hit? Loading a library where you’re likely using less than 10% of it incurs no performance hit over the internet? All these websites that slap idiotic crap like jquery and mootools atop them don’t send my 2.4ghz Core 2 laptop off to never-never land even in CHROME due to crappy performance from idiotic garbage that doesn’t even belong on websites? (like the endless stupid animated crap?) So bad to the point that useful websites from a decade ago I won’t even visit anymore because of this pointless idiotic bloated ******** that delivers a fraction the functionality they had before this entire sick trend of “just use ___ framework” became a sick catch-phrase?

Userland code is slower than system-level code; it’s why in interpreted languages system code is preferable to userland and why as a rule of thumb, interpreted code should be used as glue ‘outside’ the loop instead of for doing real processing; this is EXACTLY why things like XML format data are bloated, slow, performance hogs.

… and why quite often the majority of ‘useful’ scripting (anything not involving stupid animated crap that shouldn’t be on a website in the first place!) done with tools like jquery end up 30-40% more code than if the developer had gotten off their **** and SHOCK learned javascript in the first place.

… and when it comes to the PHP side with things like CodeIgnitor, or worse off the shelf CMS/PoS softwares it’s just taking something simple and making it more complex, dragging performance into the 9th ring of hell,

But then, I remember serving 5K+ users off a 486/66 running Netware 3.12 shoving around far, FAR more data than any PoS (Point of Sale) software would/should per transaction. The reason that same level traffic can choke off a twin quad-core Xeon with HT these days? Not hard to figure out!

The only ‘reason’ it would be ‘demonstrably untrue’ is if you keep throwing hardware at the problem; congratulations, you just bought a multighz dual xeon to get the performance of a hundred mhz or less 486. Good for you.

That’s an exaggeration, but gets the point across.

At best they’re a crutch for those who probably shouldn’t be making software in the first place, at worst they are nube predation and sleazy shortcuts.

Yeah, you did: an MVC OOP framework. It’s possible we don’t understand the same thing though, when talking about frameworks, MVCs and OOP.

HAML in PHP is nothing more than an object having a function returning a string. Actually, is a bit more complicated than that, but I wanted to get the message across. And to that extent, any class means another meta language.

For me, and for me alone, your research and your understanding of what I’m saying is scatchy, at best. By your definition, PHP itself shouldn’t exist let alone trying OOP with it. But I could be wrong. Otherwise, it’s all fine. Happy coding.

Maybe I missed it, but I haven’t even seen Michael’s view system, so I’m not clear what it is that’s being criticized.

BTW – the moment you start using terms like “reusable block hive” you’ve taken something simple – plugging data into a layout – and turned it into a convoluted mess. Look at your code… IF I’m understanding it right (not sure I am with PHP’s bizzare scope and half-assed half-implemented objects) you’ve got whole bunch of code to pull off what I’d be doing with a require_once and function call inside the require.

It starts to smell like an ‘objects for nothing other than having objects’ and “MVC to the point of missing that MVC is not how PHP is designed to work”.

Increasingly I’m starting to feel like MVC is a sick fad for writing more code for no good reason, as opposed to a cleaner and better way of writing things; it makes no sense in a non-event driven language with a sequential execution order; input -> process -> output is how it’s meant to work; adding all that overhead and needlessly complex code accomplishes what exactly?!?

I’d have to see what it is your example code is actually trying to accomplish, but I have the feeling that like many of the systems out there you’ve taken something simple and overthought it into a giant nonsensical mess.

Which is funny since your post started as a rant about nonsensical messes – but digging into what you were trying to do, pot - kettle.

Though Jeff has a point – we’re not seeing your “view”, so the picture is incomplete.

MVC does not inherently require any overhead. See the very simple example I linked to in post #5.

Sure, Doesn’t require any overhead – right.

Though none of the examples really come close to what I’d call good coding practice – from the ‘function fear’ first example card stacked to intentionally look stupid, to the ‘let’s pass massive amounts of output WITH markup in a variable’, to the “let’s use a massive userland library to make something we have to parse using USERLAND code” all to do the job of echo, single quotes, and functions/includes… RIGHT.

Though can’t say I’ve heard it called a ‘front controller’ using a single entry/exit point. I’m used to that being a “single entry non-reentrant” – going with the concept of the “single point security gate”. Only one entry, only one point you need to cover. Or at least, that’s what it was called in ADA.

Not that I’ve ever written a single program in ADA… that’s my story and I’m sticking to it… :smiley:

Really to me, that sounds like a job for a index.php to act as a traffic cop, a common.php with a function in it to break down the user input to figure out what needs to be done, various implementation.php for each of the subfunctions to be done in building the page content, and a set of template.php’s including the bits and pieces of the theme… What you need some bloated stupid parser running as userland code to use curly brackets instead of what you could do in native code with single quotes and comma’s? You did notice it goes on to suggest that absolute train wreck of pointless bloated slow garbage known as Twig, right?

I mean seriously,


        {% for post in posts %}
        <li>
            <a href="{{ path('blog_show', { 'id': post.id }) }}">
                {{ post.title }}
            </a>
        </li>
        {% endfor %}

vs.


foreach ($posts as $post) {
  echo '
    <li>
      <a href="', $scriptURL, 'blog_show&amp;', $post['id'], '">
        ',$post['title'],'
      </a>
    </li>';
}

Is really worth relying on some module you can’t guarantee will even be installed or desired on a clients system, mutliple extra includes for it’s autoloader classes, the intialization of a dozen or more variables, the extra processing time of basically parsing the template TWICE… Shall I go on?

Of course if you open and close <?php ?> like a re-re on every line, you probably don’t quite agree… personally I think <?php ?> should be removed from the PHP specification as unnecessary.

Are you brain damaged or something?! I show you an overhead-less MVC example, yet you instead reference a full framework, as if that somehow invalidates the overhead-less version?

Are we reading the same article – since it seems the entire point of the one in said link is moving you to symfony and twig?!?

The ‘intermediate’ example being no real winner either if that’s what you’re referring to… the what, two paragraphs and two code examples out of some twenty para’s and ten code examples on that page?

You meant this, right?

if so, you either didn’t read the entire article or failed to grasp it’s point. Hence the title “from flat PHP to Symfony”? You know, the entire POINT being to become reliant on some bloated fat library consisting ENTIRELY of overhead?

Yeah, and I’m the one with brain damage. If that article is your idea of overhead-less, you need to learn what overhead means!

I explicitly linked to that intermediate example, so yes, that’s what I’m referring to. The few code examples in that section are as lightweight as code can get and still be MVC.

Methinks we have different definitions of MVC… and lightweight. That’s not MVC at that point… since it’s top-down and non-relational, without multiple entry points.

Certainly isn’t lightweight, from outright embarrassingly bad code like this:


<?php $title = 'List of Posts' ?>

<?php ob_start() ?>
    <h1>List of Posts</h1>
    <ul>
        <?php foreach ($posts as $post): ?>
        <li>
            <a href="/read?id=<?php echo $post['id'] ?>">
                <?php echo $post['title'] ?>
            </a>
        </li>
        <?php endforeach; ?>
    </ul>
<?php $content = ob_get_clean() ?>

<?php include 'layout.php' ?>

Herpafreakingderp – I see somebody failed “reductions” in algebra 1.

To just plain idiotic nonsense like:


function close_database_connection($link)
{
    mysql_close($link);
}

Which wins this years pointless code award.

In any case, that part is NOT a MVC – NOT EVEN CLOSE! Not even the same BALLPARK. That’s just top-down parsing broken into pieces… ooh. Not even broken into sensible pieces either like splitting up that theme template into subfunctions since some things (like everything from BODY up and #footer down) tend to be shared across pages that unified index.html tends to share.

Hence the garbage:


    header('Status: 404 Not Found');
    echo '<html><body><h1>Page Not Found</h1></body></html>';

With the invalid/semi-broken HTTP header (should be “HTTP/1.1 404 Not Found”) and markup in the alleged “controller”. (that doesn’t seem to be a controller, seems to be model since it’s processing the input instead of routing it)

When they can’t even get the response codes right, not realize that a ?> followed by a <?php is completely pointless, and wraps single function calls in functions, you’ll excuse me if it’s not exactly blowing my skirt up.