View dependency

Hi guys!

We are starting use the phalcon framework! The first impression was great. But after all I found several issues wihich I don't understand.

First of all I don't like a way in which the dependency injection is used. Now, its used as Registry pattern, not more. Let me explain a little. For ex. I'd like to make my custom View. So I wrote this

$this->di->set(
            'view',
            function () {          
                return new \stdClass();
            }
        );

Let me see what I'll get?

Fatal error: Phalcon\Mvc\Application::handle(): Call to undefined method start() on class stdClass

What? Are you kidding me? It's mean what Phalcon use DI in this way:

class Controller
{
    public function __construct(DependencyInjectionInterface $di)
    {
       $this->view = $di->getShared('view');
    }
}

instead of

class Controller
{
    public function __construct(DependencyInjectionInterface $di, ViewInterface $view)
    {
       $this->view = $view
    }
}

or

class Controller
{
    public function __construct(DependencyInjectionInterface $di)
    {
       $this->setView($di->getShared('view');
    }

    protected function setView(ViewInterface $view)
    {
       $this->view = $view
    }
}

It doesn't make sense.

Ok, let we move forward.

I'm creating an application that communicate via JSON protocol. Or AMF for example. Should I use hierarchical template structure? Or maybe catch output buffering? I think no. The phalcon developers do not think so. I have no way to replace default implementation of view logic. Is this a CMS or a framework? So...

My opinion is that phalcon should has a separate view logic to render, store and engine service. Let me describe a little. View -> should only store the data what you are what to represent. RenderEngine -> explain how this data will be render. Render -> render view with given engine.

For example we have some data to output:

$view = new View();
$view->test = 'hello word';

And we are want to render data to HTML template, so we are going to write follow lines:

$engine = new HTMLTemplateEngine();
$engine->setLayer('main');
$render = new Render();
$render->process($view, $engine);

Or we want to render answer in JSON format:

$engine = new JSONEngine();
$render = new Render();
$render->process($view, $engine);

Something like that. Again with this way we are keep one responsibility principle.

What are you think, does it make sense?



7.0k
edited Mar '14

I'm creating an application that communicate via JSON protocol. Or AMF for example. Should I use hierarchical template structure? Or maybe catch output buffering? I think no. The phalcon developers do not think so. I have no way to replace default implementation of view logic. Is this a CMS or a framework? So...

Maybe you'd better examine in greater detail Phalcon. For example, I have application on Phalcon in real. In this application I request form from Ajax. Form is created by Volt template engine and transmitted to browser via Ajax post request with CSRF protection from Phalcon as JSON. And all works.. Example :

public function signupAction()
    {
        $this->view->disable();
        $signupform = new \FM\Apps\Forms\SignUpForm();
        $form_html = [
            'signupform' => $signupform->renderform()
        ];
        echo json_encode($form_html);
    }

Class SignUpForm compile form (popup window) from view/form/signup.volt and action return JSON string with form.



939
edited Mar '14

Oleg, mate!

You are absolutly right! But I want to emphasize that you can solve this problem using standard phalcon implementation.

But! This way is not optimize and a little out of OOP and SOLID principles. Whats look more reasonably?

public function signupAction()
    {
        $this->view->disable();
        $signupform = new \FM\Apps\Forms\SignUpForm();
        $form_html = [
            'signupform' => $signupform->renderform()
        ];
        echo json_encode($form_html);
    }

or

public function signupAction()
    {
        $signupform = new \FM\Apps\Forms\SignUpForm();
        $this->view->signupform = $signupform->renderform();        
    }


939

Current realisation of view is a bit excessive... Separate view give to us more flexible configuration and remove useless parts.



7.0k

Nothing prevents you to inject any class to view, if you need :) With magic methods (__call)



939
edited Mar '14

Maybe my explanation isn't clean as I think. Let me try again.

In your case you should disable addition functionality what you don't need.

$this->view->disable();

and add operand echo and json_encode to manipulate output in each method also

echo json_encode($form_html);

So right now Phalcon View isn't help you and you should make manipulation with it like at procedure style.

What I suggest

1) View should only contain data to output

 $signupform = new \FM\Apps\Forms\SignUpForm();
$this->view->signupform = $signupform->renderform();

2) Mechanic of output should be realized in RenderEngine

class JSONRenderEngine implements RenderEngineInterface
{
    public function render(ViewInterface $view)
    {
       echo json_encode($view->getData());
    }
}

3) You can set engine in three ways: default in application, default in controller, custom in method. Let choose default in controller for example, so your example should be like this:

class Controller extendes \Phalcon\Controller
{
    public function __construct(DependencyInjectionInterface $di)
    {
       $this->di = $di;
       $this->setRenderEngine($di->getShared('renderEngine');

    }

    public function signupAction()
    {        
        $signupform = new \FM\Apps\Forms\SignUpForm();
        $this->view->form_html = [
            'signupform' => $signupform->renderform()
        ];
        $this->render();
    }

    protected function render()
    {
        $render = $di->getShared('render');
        $render->process($this->view, $this->renderEngine);
    }
}

Where Render is simplest class like this:

class Render implements RenderInterface
{
    public function process($view, $engine)
    {
        $engine->render($view);
    }
}


7.0k

Maybe.

But I don't need view render, when I need JSON response. And Phalcon give me direct access to Volt Compiler. So I get the result quickly. Without unnecessary layer. This is not right, maybe. I can't open code. but it have only a few rows :) However, it has greater speed. :)

I like Phalcon, because I can always have a coding at a low level, if need. And make my code faster. I waited Phalcon a long time :)



939
edited Mar '14
but it have only a few rows

With my way your code will be more simplest and clean.

And make my code faster

This is no affect application speed but if it is affect it give a possitive result!



7.0k

Thanks. But I'll stay with my code style :)