stoimen.com/blog

web developing

Archive for the ‘PHP’ Category

So Called – Subpatterns

Patterns - preg_match

In PHP 5.2.2+ you can name the sub patterns returned from preg_match with a specific syntax.

Named subpatterns now accept the syntax (?<name>) and (?’name’) as well as (?P<name>). Previous versions accepted only (?P<name>)

This is extremely helpful, when dealing with long patterns. As you may know you can simply use the “old school” way and to call the matches by their number based index:

    $haystack = '01 Jan 1970';
    $pattern = '/(\d{1,2})\ (Jan|Feb)\ (19\d\d)/';
 
    preg_match($pattern, $haystack, $matches);
 
    print_r($matches);

Although it may look difficult to maintain, now you can simply name the sub patterns of preg_match and to call them with their associative array keys. This is more clear when writing code and it’s definitely more maintainable.

    $haystack = '01 Jan 1970';
    $pattern = '/(?<day>\d{1,2})\ (?<month>Jan|Feb)\ (?<year>19\d\d)/';
 
    preg_match($pattern, $haystack, $matches);
 
    print_r($matches);
 
    // now there's $matches['day'], $matches['month'] ...
  • 0 Comments
  • Filed under: PHP, micro tutorial
  • Double Trouble

    duplicate
    This is a well known problem, which is well described as a bug in Zend Framework’s issue tracker. Once you add some scripts with the inlineScript helper you’ll receive them twice in the code. This makes the page slower and leads to some crashes.

    $scripts->appendFile('my-file1.js')
            ->appendFile('my-file2.js')
            ->appendScript('alert("test")');

    This will print the alert twice.

    <script src="my-file1.js"></script>
    <script src="my-file2.js"></script>
    <script>
    //<!--
    alert("test");
    //-->
    </script>
    <script>
    //<!--
    alert("test");
    //-->
    </script>

    Quick Solution

    Although this is the worst solution I’ve ever made – it works! There is a check for duplicates in the HeadScript helper around line 240:

    if (!$this->_isDuplicate($content)) {
    ...

    and then a check in the _isDuplicate method(), ~ line 270:

    if (($item->source === null)
        && array_key_exists('src', $item->attributes)
        && ($file == $item->attributes['src']))
    {
        return true;
    }

    The thing you’ve to do is to add such a check for the appendScript() and not only for appendFile() method – again ~ line 230:

    case 'script':
    	if (!$this->_isDuplicate($content)) {
    	    $item = $this->createData($type, $attrs, $content);
    	    if ('offsetSet' == $action) {
    	        $this->offsetSet($index, $item);
    	    } else {
    	        $this->$action($item);
    	    }
    	}
    	break;

    And then slightly modify the _isDuplicate method:

    foreach ($this->getContainer() as $item) {
        if (($item->source === null)
            && array_key_exists('src', $item->attributes)
            && ($file == $item->attributes['src']))
        {
            return true;
        }
        if ($item->source == $file) {
            return true;
        }
    }
    return false;


    There is an easy way to send requests with Zend_Http_Client either in GET and POST. Actually you can request not only with GET and POST methods, but with any other http request method.

    $httpClient = new Zend_Http_Client('http://....');
    // request via post
    $response = $httpClient->request(Zend_Http_Client::POST);
    // or get
    $response = $httpClient->request(Zend_Http_Client::GET);

    However the interesting and useful thing is that you can perform authenticated requests:

    $httpClient = new Zend_Http_Client('http://username:password@example.com');
    // or define it later
    $httpClient = new Zend_Http_Client('http://example.com');
    $httpClient->setAuth('username', 'password');

    That’s an opportunity to send/receive authenticated POST requests.

    $httpClient = new Zend_Http_Client('http://username:password@example.com');
    // now post
    $httpClient->request(Zend_Http_Client::POST);

    There is a view helper that can inject a head or inline script into your code.

    Simply by putting some JavaScript code into the view script wont do the job, because the .phtml file is grabbed and parsed by the Zend Framework and thus the code there wont be parsed as JavaScript and it wont be executed as well by the browser.

    The Most Simple Way …

    is to put some place holder into the layout .phtml file and than from the controller’s action you can assign some JS code:

    // layout.phtml
    <?php
    ...
    echo $this->layout()->scriptTags;
    ...
    <?php
     
    class IndexController extends Zend_Controller_Action
    {
    	public function indexAction() 
    	{
    		$this->view->layout()->scriptTags = '<script src="my.js"></script>';	
    	}	
    }

    Solution No. 2

    Although the first solution is correct it’s not the most clearest way, because you put the JavaScript code into the PHP, and this sooner or later becomes a mess.

    <?php
     
    class IndexController extends Zend_Controller_Action
    {
    	public function indexAction() 
    	{
    		$this->view->layout()->scriptTags = '<script src="my.js"></script>';
    						  . '<script>alert("here\'s my" + "test")</script>';
    	}	
    }

    The IDE is not highlighting the code, and you’ve to deal with too many quotes, which is bad! There is a better solution however – the inline script:

    // script tags
    /* @var $scripts Zend_View_Helper_InlineScript */
    $scripts = $this->view->inlineScript();
    $scripts->appendFile('my.js');

    Simply the Best

    Yeah, the best solution is something even better than the second one. Although the solution I’ve just mentioned is fine for including JS files, when you’ve to add some JS code you’ll have to put it again into the PHP.

    $msg = 'some dynamically generated message';
     
    // script tags
    /* @var $scripts Zend_View_Helper_InlineScript */
    $scripts = $this->view->inlineScript();
    $scripts->appendFile('my.js');
    $scripts->appendScript('alert("' . $msg . '")');

    If there’s no relation between JavaScript and PHP you can simply put all this code into a separate .js file and load it from there. This is by the way the best solution because the file is cached by the browser, if the cache is enabled. But most of the time you perhaps have to send some variables from PHP to the JavaScript code.

    It would be perfect if you had some kind of a variable placeholders – exactly as you have it in the Zend Framework’s view scripts!

    Another View

    This is completely possible – just forget about the default view – it renders the view script and it’s bind to the /views/scripts folder. You can make another, completely new, view instead! Here’s some source:

    $view = new Zend_View();
    $view->setBasePath('path_to_the_js_folder');
     
    $view->msg = 'Some dynamically generated message';
     
    // script tags
    /* @var $scripts Zend_View_Helper_InlineScript */
    $scripts = $this->view->inlineScript();
    $scripts->appendFile('my.js');
    $scripts->appendScript($view->render('inline.js'));

    Thus now in the JS file you can have some placeholders!

    // inline.js
     
    // some js code
    // ...
    alert('<?php echo $this->msg ?>');

    Typical Setup

    Typically Zend Framework is setup to bind every controller’s action to a specific view. The names of the action and the view script must be the same, or at least must be similar – following the ZF’s convention.

    Thus if you name an action, let’s say, indexAction(), you’ve to create an index.phtml file into the views/scripts/index/ folder. Let me remind you that this is what is called a typical setup, but this may vary from one installation to another.

    Thus everything’s fine and the MVC does its best. After the user requests a specific uri, the framework parses it and finds the controller, than the action and than the view script – and there is a view script for every single action.

    typical zend framework setup

    When there are two or more actions – there are two or more .phtml (view scripts) files.

    typical zend framework setup for two or more actions

    Some Exceptions

    Sometimes you have very similar logic, but very different markup between two actions. As the logic goes to the controller/action and the markup into the view, the question is can you simply have one action in the controller, but with two different .phtml file as a view scripts? Of course switching between those two (or more) with some conditionals.

    Solution No. 1

    However once I posted a simple, and working, solution. There you have again two actions and two scripts:

    <?php
     
    class IndexController extends Zend_Controller_Action
    {	
    	public function firstAction()
    	{
    		// place all the logic you need here
    		// and every view placeholder assignment
    		$this->view->title = "My Title";
     
    		// if the logic requires a different markup
    		// simply redirect to another view
    		if (some_expression) {
    			$this->_forward('second');	
    		}	
    	}
     
    	public function secondAction()
    	{}
    }
     
    // in the application/views/scripts/index
    // 1. first.phtml
    <h1><?php echo $this->title ?></h1>
     
    // 2. second.phtml
    <h2><?php echo $this->title ?></h2>

    As you can see in the second action there’s no logic – it’s only serving the role of a bridge between the views. Everything is setup into the first action, but the second action is doing the relation with the second.phtml view script.

    Solution No. 2

    However there’s another solution with only one action and two scripts which makes something like that shown on the diagram bellow:

    zend framework one action multiple=

    The only thing to do is to add some code to your action:

    <?php
     
    class IndexController extends Zend_Controller_Action
    {	
    	public function firstAction()
    	{
    		// place all the logic you need here
    		// and every view placeholder assignment
    		$this->view->title = "My Title";
     
    		// if the logic requires a different markup
    		// simply redirect to another view
    		if (some_expression) {
    			echo $this->view->render('index/second.phtml');
    			$this->_helper->viewRenderer->setNoRender(true);
    		}	
    	}
    }
     
    // in the application/views/scripts/index
    // 1. first.phtml
    <h1><?php echo $this->title ?></h1>
     
    // 2. second.phtml
    <h2><?php echo $this->title ?></h2>

    Note that you’ve to setNoRender on the view renderer once you render the other script!