Smarty Fetch is not loading anything into my variable - php-5.3

I have a class that sets up my smarty instances:
class View {
protected $templateEngine;
protected $templateExtension = '.tpl';
public function __construct(){
global $ABS_PUBLIC_PATH;
global $ABS_PUBLIC_URL;
$this->templateEngine = new Smarty();
$this->templateEngine->error_reporting = E_ALL & ~E_NOTICE;
$this->templateEngine->setTemplateDir($ABS_PUBLIC_PATH . '/templates/');
$this->templateEngine->setCompileDir($ABS_PUBLIC_PATH . '/templates_c/');
$this->templateEngine->assign('ABS_PUBLIC_URL', $ABS_PUBLIC_URL);
if(isset($_SESSION['loggedIn'])){
$this->assign('session', $_SESSION);
}
}
public function assign($key, $value){
$this->templateEngine->assign($key, $value);
}
public function display($templateName){
$this->templateEngine->display($templateName . $this->templateExtension);
}
public function fetch($templateName){
$this->templateEngine->fetch($templateName . $this->templateExtension);
}
}
Then in my functions, I use the class like this:
public function showMeSomething()
{
$view = new View();
$view->assign('session', $_SESSION);
$view->display('header');
$view->display('index');
$view->display('footer');
}
Now, I'm trying to fetch some data into a variable, in order to send emails from my template files as well. Unfortunately, this var_dumps below (both of them) output NULL - even though the template file referenced has a lot of HTML in it. Furthermore, changing the word fetch to display below will correctly display the template file. So, the problem certainly lies within the fetch command. I'm not sure what to do to continue debugging.
function emailPrep($data,){
$mailView = new View();
$emailHTML = $mailView->fetch('myEmail');
var_dump($mailView->fetch("myEmail"));
var_dump($emailHTML);
}

Your code must be
public function fetch($templateName){
return $this->templateEngine->fetch($templateName . $this->templateExtension);
}

Related

zend framework 2 understanding the exchangeArray method

From the documentation:
namespace Album\Model;
class Album
{
public $id;
public $artist;
public $title;
public function exchangeArray($data)
{
$this->id = (!empty($data['id'])) ? $data['id'] : null;
$this->artist = (!empty($data['artist'])) ? $data['artist'] : null;
$this->title = (!empty($data['title'])) ? $data['title'] : null;
}
}
Our Album entity object is a simple PHP class. In order to work with Zend\Db’s TableGateway class, we need to implement the exchangeArray() method. This method simply copies the data from the passed in array to our entity’s properties
Ok, we need to. But what's the pourpose of that function?
I mean, I've understood what that function does but I can't understand why it does things in that way.
Is it really necessary to declare all the variables?
Let's say I have a table of 20 columns and I want to select them all.
Then I should declare 20 named variables.
That makes sense if I want to distinguish between public (to print) and private (internal) variables.
Is there any other reason?
It 's not just about defining class members. It 's more about object orientated benefits like encapsulation, inheritance, etc.
Let 's assume your entity looks like this:
declare(strict_types=1);
namespace Application\Entity;
class Album
{
protected $id;
protected $artist;
protected $title;
public function getId() : int
{
return $this->id;
}
public function setId(int $id) : Album
{
$this->id = $id;
return $this;
}
public function getArtist() : string
{
return $this->artist;
}
public function setArtist(string $artist) : Album
{
$this->artist = $artist;
return $this;
}
public function getTitle() : string
{
return $this->title;
}
public function setTitle(string $title) : Album
{
$this->title = $title;
return $this;
}
}
First advantage using entities: there is no possibility to make typos. $data['atrist'] = 'Marcel' will work in most cases. $album->setAtrist('Marcel') will throw an error.
Second advantage is type hinting. Especially when you 're using PHP7 you can use the advantage of type hinting. $album->setId('1') will throw an error because this method expects an integer value.
Third advantage is the possibility of adding some extra code to your entity. what if we need a release date and no release date is given? You can kind of validate things in entities.
protected $releaseDate;
public function getReleaseDate() : \DateTime
{
if ($this->releaseData == null) {
throw new \Exception('no release date given. evacuate!');
}
return $this->releaseDate;
}
Another advantage is hydration in zend framework. Although the exchangeArray method is a kind of simple hydration, zend framework offers way more complex ways of hydration. What, if your release date column in the database table is of type DATE and you want your releaseDate member in your entity to be a \DateTime object representing this date?
// data from your database
$data = [
'id' => 1,
'artist' => 'the outside agency',
'title' => 'scenocide 202',
'releaseDate' => '2010-06-30',
];
// hydration of your entity with zend 's own hydrator classes
$album = (new ClassMethods())
->addStrategy('releaseDate', new DateTimeStrategy('Y-m-d'))
->hydrate($data, new Album());
$releaseDate = $album->getReleaseDate()->format('d.m.Y');
As you can see the release date was a simple string. While hydrating your entity, the release date will be transformed to a \DateTime object through a hydrator strategy.
These benefits are way more than distinguish between public, protected and private variables. An entity only takes and gives variables, that should be in your entity. You can use all the oo things like inheritance (implementing the \JsonSerializable interface is pretty magic sometimes), type hinting, encapsulation, polymorphism and so on ...
Last but not least: IDE support. If your entity object is strictly php doc commented, your IDE knows what you can do with your entity. Less work for you. ;)
Edit: Table Gateway instantiation with hydrating resultset
To use the above described advantges of entity objects with hydrators in a table gateway, you have to instantiate the table gateway like in the following example.
class AlbumTableGateway extends TableGateway
{
public function __construct(Adapter $adapter)
{
$resultset = new HydratingResultset(
(new ClassMethods())->addStrategy('releaseDate', new DateTimeFormatter()),
new AlbumEntity()
);
parent::__construct('album_table', $adapter, null, $resultset);
}
public function fetchById($id)
{
$select = $this->getSql()->select();
$select->columns([
'id',
'artist',
'title',
'releaseDate',
]);
$select->where->equalTo('id', $id);
$result = $this->selectWith($select);
// get the found resultset with $result->current()->getId();
return $result;
}
}
This example assumes that the Table Gateway is created via a corresponding factory.

Render partial in other module ZF2

In my project I have to modules
Module1
Module2
In Module1 I have a view that needs to render a view that I have in Module2, so what I'm doing is:
$this->partial('partials/hello/title.phtml','Module2',array('data' => $data))
and seems I'm calling correctly the view, but inside of the view title.phtml I'm unable to use data
Undefined variable: data in /site/src/module/Module2/view/partials/hello/title.phtml
Do I need add something related to the configuration?
Thanks!
You aren't calling it correctly, try:
$this->partial('partials/hello/title.phtml', array('data' => $data));
See: http://framework.zend.com/manual/2.3/en/modules/zend.view.helpers.partial.html
The fact that the partial is in a different module doesn't matter. Having to specify the module name as the second parameter was a thing in ZF1 only.
Another solution is add your own view-path resolver in module-bootstrap:
class Module
{
/* #var \Zend\ServiceManager\ServiceManager $SM */
public static $SM;
/* #var \Zend\EventManager\EventManager $EM */
public static $EM;
public function onBootstrap(MvcEvent $e)
{
self::$SM = $e->getApplication()->getServiceManager();
self::$EM = $e->getApplication()->getEventManager();
//change view resolver to resolve views from {Module}/view/{Controller}/{Action}.phtml path
self::$EM->attach('dispatch', function($e) {
self::$SM->get('ViewRenderer')->resolver()->attach(
new \Engine\View\Resolver\MCA() , 10
);
});
}
....
Resolver gets a string, and must to return path or false (if not resolved), just write resolver to understand other-modules paths:
<?php
namespace Engine\View\Resolver;
use Zend\View\Renderer\RendererInterface as Renderer;
/**
* Resolves view scripts based on a stack of paths
*/
class MCA implements \Zend\View\Resolver\ResolverInterface
{
public function resolve($name, Renderer $renderer = null)
{
$path = explode('/', $name);
if (count($path)<3){
return false;
}
$module = array_shift($path);
$resolvedPath = ROOT_PATH . '/module/'. ucfirst($module) . '/view/' . implode('/', $path). '.phtml';
if (!file_exists($resolvedPath)){
return false;
}
return $resolvedPath;
}
}
There can be collisions, but you can regulate priority of resolvers (10 in example).

Set layout variables for use by the (404) error pages in ZF2

At present I set a couple of variables to be used by the app's overall layout.phtml, using the onDispatch method of a BaseController, which all my other controllers extend:
public function onDispatch(MvcEvent $e)
{
$config = $this->getServiceLocator()->get('config');
$this->layout()->setVariable('platformName', $config['platform']['name']);
$this->layout()->setVariable('platformYear', $config['platform']['year']);
}
This works fine, until I test some error pages and find that these pages do not get provided with the variables, as it's not using the base controller.
How can I get around this problem and provide the error pages with the same variables?
Change the event you're listening for.
In this case, I'd move this logic to the application bootstrap event or the application render event (I haven't tested this, but it would probably work fine).
One example, in your Module.php
public function onBootstrap($e)
{
$config = $e->getApplication()->getServiceManager()->get('config');
//$e->getViewModel()->setVariable();
}
Haven't tested that commented out line, but it should get you headed in the right direction.
EDIT: Found an example of using the render event
public function onBootstrap($e)
{
$event = $e->getApplication()->getEventManager();
$event->attach('render', function($e) {
$config = $e->getApplication()->getServiceManager()->get('config');
$e->getViewModel()->setVariable('test', 'test');
});
}
(Necro)
When using onDispatch in a Controller, remember to return the parent with the event and all:
public function onDispatch(MvcEvent $e)
{
// Your code
return parent::onDispatch($e);
}
Otherwise, the logic on your Actions in that Controller will be ignored.

In EF4, Is there a way to have unmapped properties make it across the wire?

I have a custom field that I've added to one of my EF entities in a shared.cs file like so:
public partial class Content
{
public int Test = 5;
}
On the client side, the OnCreated handler for that same class looks like this:
partial void OnCreated()
{
this.Test = 42;
}
I've added an event handler to the SavingChanges event for the context on the server like this:
partial void OnContextCreated()
{
this.SavingChanges += (sender, e) =>
{
foreach (object o in GetChangedEntities())
{
if (o is Content)
{
// Break to see what the value of Test is;
}
}
}
}
When I break at the comment (which is not really a comment my code :), the value of Test is always 5. In fact, I can't seem to set it to 42 anywhere on the client and have that value make it to the server.
I have set breakpoints all over the place, and the value is definitely being set to 42 on the client-side. Is there something that I'm doing wrong, or is this behavior just not supported? Incidentally, I've also tried this as a property instead of a field--just in case.
I needed to mark my property/field as a [DataMember] like this:
public partial class Content
{
[DataMember]
public int Test = 5;
}
and then move it out of the shared.cs file to a CustomProperties.cs (or similar) file in the server project to avoid multiple delcarations. Now it crosses the wire just fine.

How to get and set http headers in an Action, the testable way

I have an action that returns either a FileContentResult or a NotModifiedResult, which is a custom result type that returns HTTP 304 to indicate that the requested resource has not been modified, like this:
[ReplaceMissingPicture(Picture = "~/Content/Images/nothumbnail.png", MimeType = "image/png")]
public ActionResult Thumbnail(int id)
{
var item = Service.GetItem(id);
var requestTag = Request.Headers["If-None-Match"] ?? string.Empty;
var tag = Convert.ToBase64String(item.Version.ToArray());
if (tag == requestTag)
{
return new NotModifiedResult();
}
if (item.Thumbnail != null)
{
var thumbnail = item.Thumbnail.ToArray();
var mime = item.PictureMime;
Response.AppendHeader("ETag", tag);
return File(thumbnail, mime);
}
else
{
return null;
}
}
This action needs to access the Response object, which is of course not present during testing, so that makes this action untestable. I could add conditional statements around it, so that it runs during testing, but then I can't test for the headers being set correctly.
What would be a solution to this problem?
FYI, the ReplaceMissingPicture filter returns a specific resource in case null was returned from this action, to keep the MapPath() call out of the controller for the very same reason.
The first step would be to create an interface which simplifies the services you need:-
public interface IHeaders
{
public string GetRequestHeader(string headerName);
public void AppendResponseHeader(string headerName, string headerValue);
}
Now create a default implementation:-
public Headers : IHeaders
{
public string GetRequestHeader(string headerName)
{
return HttpContext.Current.Request[headerName];
}
public void AppendResponseHeader(string headerName, string headerValue)
{
HttpContext.Current.Response.AppendHeader(headerName, headerValue);
}
}
Now add a new field to your Controller:-
private IHeaders myHeadersService;
add new constructor to you controller:-
public MyController(IHeaders headersService)
{
myHeadersService = headersService;
}
modify or add the default constructor:-
public MyController()
{
myHeadersService = new Headers();
}
now in your Action code use myHeadersService instead of the Response and Request objects.
In your tests create your own implementation of the IHeaders interface to emulate/test the Action code and pass that implementation when constructing the Controller.
How about creating a subclass of FileResult--say ETagFileResult--that in its ExecuteResult() method sets the ETag header, and then defaults to the base class implementation? You can test that class with a mocked context (as you presumably are with your NotModifiedResult) to be sure that it's doing the right thing. And remove the entire complication from the testing of the controller.
Failing that, it's possible to set a mocked context on the controller in your test (after instantiating the class, before calling the action method). See this question, for instance. But that seems like more work.
(Also, by the way, it looks like you're quoting the tag value twice there: once when tag is set, and once more when you actually set the header....)

Resources