4

I need to render email templates in variable to send them later (which are stored in .phtml files), and i really don't want to implement my special class for handling this.

Is it possible to render not controller action view, but custom one?

I tried following code, but it outputs NULL :((

// Controller context
$view = new Phalcon\Mvc\View();
$view->setViewsDir('app/views/');
$view->setVar('var1', 'var2');
// Setting some vars...
$view->start();
$view->partial($emailTemplatePath);
$view->finish();
$result = $view->getContent();
var_dump($result); // Gives null
avasin
  • 9,186
  • 18
  • 80
  • 127

6 Answers6

4

In addition to the response by Nikolaos, you can use $view->getRender() to render a single view returning its output.

$view->setViewsDir('apps/views/');
echo $view->getRender('partials', 'test'); // get apps/views/partials/test.phtml
twistedxtra
  • 2,699
  • 1
  • 18
  • 13
  • this is suitable to render only files, that are views for some controller action. in my case, i have different folder with different email templates. – avasin Jan 16 '13 at 13:37
  • 2
    see the first parameter as a sub-directory under the views directory: echo $view->getRender('templates/email', 'some'); // get apps/views/templates/email/some.phtml – twistedxtra Jan 16 '13 at 17:27
  • When I do this, my whole website template (index.phtml) is also appended into my content. Any idea why ? – RPDeshaies Jul 06 '14 at 13:59
2

You need to check the path of the $emailTemplatePath. It should point to the correct file i.e.

// points to app/views/partials/email.phtml
$view->partial('partials/email');

If you are using Volt and have registered that as your engine, then your file will need to be:

// app/views/partials/email.volt
Nikolaos Dimopoulos
  • 11,495
  • 6
  • 39
  • 67
  • I've tried to do the same in my example (in question), but $view->getContent() returns null.. :(( – avasin Jan 16 '13 at 13:38
  • If you are using Volt, don't forget define template engine by the method `registerEngines()`. – borzov Feb 11 '15 at 09:54
1

use $view->render('partials/email') instead of calling partial method.

Mehdi Maghrouni
  • 1,529
  • 22
  • 23
Daniel
  • 1,531
  • 13
  • 16
  • This is the easiest answer, just there is a lack of `return false;` in controller. Without `return false;` it render the current actions view file. – Serdar D. Jun 21 '16 at 00:03
1

I have a project where I use email and pdf templates and what I did was to have the rendering all take place within components.

Firstly, my folder structure contains (and I will only put here what is relevant) a cache, components and views directory. Let's look at the email setup rather than the PDF as this is more relevant to your situation.

/app
    /cache
        /email
    /components
    /views
        /email
            /elements

Of course there is public, controllers etc but let's not think about them for this.

I'm using Swift mailer for mine but I hope you will be able to use this all the same. In /app/components/Swift.php I have a __construct that calls for this->init_template_engine();

/**
 * Create a volt templating engine for generating html
 */
private function init_template_engine() {
    $this->_template = new \Phalcon\Mvc\View\Simple();
    $di = new \Phalcon\DI\FactoryDefault(); 
    $this->_template->setDI($di);
    $this->_template->registerEngines([
      '.volt' => function($view, $di) {

            $volt = new \Phalcon\Mvc\View\Engine\Volt($view, $di);

            $volt->setOptions([
                'compiledPath' => APP_DIR."cache".DS."email".DS,  // render cache in /app/cache/email/
                'compiledSeparator' => '_'
            ]);

            return $volt;

      // or use ".phtml" => 'Phalcon\Mvc\View\Engine\Php' if you want, 
      // both will accept PHP code if ya don't fancy it being a 100% volt.
        },
    ]);

    // tell it where your templates are
    $this->_template->setViewsDir(APP_DIR.'views'.DS.'email'.DS); 

    return $this->_template;
}

The constants above (like APP_DIR) are something I have already made in my bootstrap and all they do is store full paths to directories.

Once the $_template variable has a template engine set up I can then use it to render my templates.

/**
 * Returns HTML via Phalcon's volt engine.
 * @param  string $template_name
 * @param  array $data
 */
private function render_template($template_name = null, $data = null) {
    // Check we have some data.
    if (empty($data)) {
        return false; // or set some default data maybe?
    }

    // Use the template name given to render the file in views/email
    if(is_object($this->_template) && !empty($template_name)) {
        return $this->_template->render($template_name, ['data' => $data]);
    }

    return false;
}

A sample volt email template may look like this:

{{ partial('elements/email_head') }}

<h2>Your Order has been dispatched</h2>

<p>Dear {{ data.name }}</p>

<p>Your order with ACME has now been dispatched and should be with you within a few days.</p>

<p>Do not hesitate to contact us should you have any questions when your waste of money arrives.</p>
<p>Thank you for choosing ACME Inc.</p>

{{ partial('elements/email_foot') }}

All I have to do then is grab the html and use swiftmailer's setBody method and I'm done:

->setBody($this->render_template($template, $data), 'text/html');

You don't need to place separate view engines like this in components, it could become memory hungry like that, but it does show the whole process. Hope that makes sense :)

Andrew Myers
  • 451
  • 3
  • 13
1

The easiest way to render a view and return it as a variable is to use the Phalcon\Mvc\View\Simple class. In your controller, declare a new instance of the Simple view class and attach a rendering engine to it. You can then use its render() method to select a view file and pass in variables:

// create a simple view to help render sections of the page
$simple_view = new \Phalcon\Mvc\View\Simple();
$simple_view->setViewsDir( __DIR__ . '/../views/' );
$simple_view->setDI( $this->di );
$simple_view->registerEngines(array(
    '.volt' => 'Phalcon\Mvc\View\Engine\Volt'
));

// use the simple view to generate one or more widgets
$widget_html = array();
$widget_objects = $widget_search->getWidgetObjects();
forEach( $widget_objects as $widget ){
    $widget_html[] = $simple_view->render('index/widgetview',array('widget'=>$widget));
}

// pass the html snippets as a variable into your regular view
$this->view->setVar('widget_html',$widget_html);
hanmari
  • 1,384
  • 12
  • 19
0

I usually use Volt engine and a simple way is a redefine view in DI container, like that:

$view = $this->view;

$content = $view->getRender('mail', 'show',
  array(
    "var1" => "some value 1",
    "var2" => "some value 2"
  ),
  function($view) {
      $view->setRenderLevel(\Phalcon\Mvc\View::LEVEL_LAYOUT);
  }
);

echo $content;
borzov
  • 131
  • 2