Inject filter into Zend_View - php

I wish to set some properties in MyFilter with constructor injection but it seems impossible with Zend_View::addFilter(string $filter_class_name) since it loads a new instance upon usage. MyFilter implements Zend_Filter_Interface.
Can I somehow inject an instance of a filter to an instance of Zend_View?
Closing since it (hopefully) will be pushed into 2.0, see ticket on JIRA.

You may pass object:
$filter = new Your_Filter($params); // implements Zend_Filter_Interface
$view->addFilter($filter);
You may get view instance from viewRenderer, e.g. using staticHelper.
Edit:
The other method may be:
class MyFilterSetup extends MyFilter implements Zend_Filter_Interface
{
public function __construct($params)
{
$this->_params = $params;
parent::__construct();
}
public function filter($string)
{
// .... $this->_params;
}
}

I'm not certain, but I don't think it's possible. Looking at the sourcecode setFilter() and addFilter() only accept the Filter Classname as a string. You cannot set any options, like you can in Zend_Form for instance. What you could do though is:
class MyFilter implements Zend_Filter_Interface
{
protected static $_config;
public static setConfig(array $options)
{
self::_config = $options;
}
// ... do something with the options
}
and then you set the options where needed with MyFilter::setOptions(), so when Zend_View instantiates the Filter instance, it got what it needs to properly run the filter.

You can't in the 1.x branch, ticket is filed:
http://framework.zend.com/issues/browse/ZF-9718

Can't we create a custom view object extending Zend_View that overrides the addFilter() method to accept either a class or an instance. Then override the _filter() method to deal with both types of filters - string and instance - that we have stored.

Why not assign the filter properties to the view, and then either set the properties when the view is set, or access the view directly in your filtering function? e.g.
$view->assign('MyFilterProperty', 'fubar');
and then in your filter class:
public function setView($aView)
{
$this->_property = $aView->MyFilterPropery;
}
It's kludgy, but it should get the job done.

Related

Symfony 4 Dependency Injection: Inject into object while creating it in code

I'm creating a NavigationBuilder class for my backend. With it, I should be able to add navigation items and then get the html (similar to Symfony's FormBuilder). It is used in a Twig Extension Function.
I have an interface and abstract class for a navigation item (e.g. Nav Link, Divider, Heading, etc.) and I'm creating child classes for these specific items.
For some of these nav items (Link) I need the Symfony Router or RequestStack and I want to inject it into the abstract class so I don't have to pass it as an argument to the constructor of every child class I need it in.
I tried using the method of injecting it with setter methods, because I thought Symfony would do it automatically whenever I create a new object, but obviously that isn't the case.
The NavigationItem class:
namespace App\...\Navigation;
use App\...\NavigationItemInterface;
use Symfony\...\UrlGeneratorInterface;
use Symfony\...\Request;
abstract class NavigationItem implements NavigationItemInterface {
private $router;
private $request;
final public function setRouter(UrlGeneratorInterface $router): self {
$this->router = $router;
return $this;
}
final public function setRequest(Request $request): self {
$this->request = $request;
return $this;
}
final public function matchesCurrentRoute(String $route): Bool {
return $this->getRequest()->get('_route') == $route;
}
/** ... **/
}
My service.yaml file:
App\...\NavigationItem:
class: App\...\NavigationItem
calls:
- method: setRequest
arguments:
- '#request_stack'
- method: setRouter
arguments:
- '#router'
I imagine it to work like this:
$builder = new NavigationBuilder();
$builder
->addItem( new HeaderItem('A Heading') ) // No need for injection
->addItem( new LinkItem('Title', 'route') ) // NEED for injection
->build(); // Returns html
I get this error code:
An exception has been thrown during the rendering of a template ("Notice: Undefined property: App...\DashboardItem::$router").
if you declare a property as private only the class itself, but no child class can use it (directly, that is). declare it protected (talking about the router property in your abstract class) see: https://www.php.net/manual/en/language.oop5.visibility.php
apparently that's not the only problem, and I suppose you confuse dependency injection with auto-wiring. dependency injection only means, that an object doesn't create it's own dependencies, but instead they are from the outside/caller via parameters (in constructor, setters, or specific calls).
auto-wiring works in symfony by either fetching an object from the container (however, by default you always get the same object. but there are ways to define a factory or the option to always retrieve a new object, possibly, not quite sure).

Symfony __construct usage

I am relatively new to Symfony (version 4) and trying to implement the __construct method for dependency injection.
Currently, I am "injecting" dependencies via my own implementation (before I was aware of the __construct method) like so:
routes.yaml
fetch:
path: /fetch/{req}
controller: App\Controller\Fetch::init
requirements:
req: ".+"
/fetch route calls the init() method, which serves as the constructor.
Controller Class
namespace App\Controller;
use Symfony\Component\HttpFoundation\Response;
use App\Services\Utilities; // a bunch of useful functions
class Fetch extends BaseController {
private $u;
public function init(Utilities $u) {
$this->u = $u; // set the $u member with an instance of $u
}
private function do_fetch(){
$this->u->prettyprint('hello service'); // use one of $u's methods
}
}
If you would indulge me, I came up with this ad-hoc scheme before reading the docs, which detail this almost exactly (I get a cookie).
The one difference is that the docs use __construct() in place of my init() method. The following is an example from the doc page linked above:
// src/Service/MessageGenerator.php
use Psr\Log\LoggerInterface;
class MessageGenerator
{
private $logger;
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}
public function getHappyMessage()
{
$this->logger->info('About to find a happy message!');
// ...
}
}
But when I swap init() for __construct(), and update the routes.yaml, I get an error.
// .....
class Fetch extends BaseController {
private $u;
public function __construct(Utilities $u) {
$this->u = $u; // set the $u member with an instance of $u
}
// ....
fetch:
path: /fetch/{req}
controller: App\Controller\Fetch::__construct
requirements:
req: ".+"
Its asking me to provide an argument to __construct since that method takes one ($u) but this was not the case when init() was acting as the constructor.
Moreover, I feel like since the __construct() method is a built-in hook, Symfony should know to use it without my having to explicitly tell it to in routes.yaml. However, excluding it throws an error as well.
routes.yaml (__construct not explicitly indicated)
fetch:
path: /fetch/{req}
controller: App\Controller\Fetch
requirements:
req: ".+"
What am I missing here?
__construct is a magic method in PHP. The problem with your init method is that it does not enforce that the object must have an instance of the object you need in order to be built. Sometimes an object property will not be needed. In this case, I recommend creating a setter as a way to optional set that property.Try to make your class properties private, and only allow them to be mutated or retrieved through setters and getters...this will provide a standard API to your obejct, and avoid random state manipulation.
You can use the DIC in Symfony's router to construct your controller instead of extending the base controller class by registering your controllers as services. This greatly decouples you code and allows all kinds of additional flexibility. You should always favor composition over inheritance.

Get the calling object from superclass

I've built a "model" superclass for a MVC framework. In most methods i do need only the class name so i've used get_called_class() but for save and edit methods i need to pass the object with values.
In my design, when you create a model object and you save or edit you have to do:
$object->save($object); or $object->update($object, $id).
I really don't like this, because looks as a bad design. I would like just to say:
$object->save(); and $object->update($id);
Since you are effectively saving the current object.
Models classes extends a Model parent that defines their behaviour and create the DB connection for them.
The methods of superclass that i would like to make does not take as an argument $object but rather i would like to say "get the calling object".
public function save($object) {
return self::$db->save($object);
}
public function update($object,$id) {
return self::$db->update($object, $id);
}
I know that this can be easily doable the in the object model with
public function save () {
parent::save($this);
}
But i would like not to have to reimplement this behaviour for every single model!
Thank you in advance.
The use of any existing ORM library isn't discussed here, since i want to provide a querybuilder and simple ORM that is PDO based as default. Because i do not want to have any 3rd party dependency as default
Define your base model as abstract class and inherit default behavior to child model classes.
abstract class Model
{
public function save() {
return self::$db->save($this);
}
public function update($id) {
return self::$db->update($this, $id);
}
}
class UserModel extends Model;
$myModel = new UserModel();
$myModel->save();

Hide Restler method from swagger-ui

Using Restler 3.0.0-RC6, which internally packages swagger-ui, I have an API method defined like so:
<?php
namespace v1:
class PostgreSQL {
public function fetchArray($sql, $args = null) {
And then all of my classes that I include via Restler's addAPIClass extend that PostgreSQL class. That means when swagger runs, every single API shows a fetchArray function. I'd like to have that method not appear in the swagger documentation as it's not really part of the API. Other 'things' on the website also use the class though so I can't change the modifier from public.
What's the proper syntax to hide that method from swagger-ui's webpage?
There are two ways to achieve this,
One is to mark the fetchArray method as private with #access private comment. This will remove fetchArray from all api urls while keeping the fetchArray still accessible for PHP
Problem in your case is that you don't want to modify the PostgreSQL as its part of a framework that is maintained by composer. Instead of directly extending it from the base class use an intermediary class which adds the comment and then extend that class as shown below
class Base {
public function fetchArray(){
return array();
}
}
class Intermediary extends Base {
/**
* #access private
*/
public function fetchArray(){
return array();
}
}
class MyApi extends Intermediary { //instead of extends Base
//other api methods here
//see in the explorer to note that fetchArray is no longer listed
}
Another way is to just exclude it on Explorer with
use Luracast\Restler\Explorer;
Explorer::$excludedPaths = array('myapi/fetcharray','another/fetcharray');
You should not extend your API layer class from a data layer class. Just use the data layer class.
class DataLayer
{
public function fetchArray()
{
return array();
}
}
class ApiLayer
{
private $dl;
function __construct()
{
$this->dl = new DataLayer();
}
public function getAll()
{
return $this->dl->fetchArray();
}
}

How to implmenet this mechanism using Abstract Class in PHP?

From the past two days i have been diving into the concepts of OOPS in PHP, and i found Abstract Class to be very useful concept and i wanted to implement it in my application. and here is why i want to implement it.
My Application Consist of Several Unstructured Pattern which uses several different classes without any hierarchies, due to this i have to use several repeated codes. i want to cut this all up and structure it properly, basically what i want to do is
Define a parent class which is not instantiable from outside.
Define all properties in this parent class so that i can re-use the same property for different child classes.
Define re-usable class methods and objects so that child class can use it without the need of defining it again and again (Inheritance).
Basically My Abstract class should be capable of inheriting the re-usable methods and properties and at the same time it should act as an Interface.
To demonstrate you clearly let me show you some sample codes which i have been using.
public $error = array(); //used to handle error mechanism and to hold the errors.
private $data = array(); //used with Accessor Methods (__set and __get)
private $validate; //holds Validate Object
private $dbh; //holds Database Object
public function __set($property, $value) {
if( in_array($property, $this->data)) {
return $this->data[$property] = $value;
} else {
return false;
}
}
public function __get($property) {
return 'Access Denied to Class Property [ '.$property.' ]';
}
Above codes are repeated for almost every class, this is the reason i want to define it once in a parent class and control the mechanism from there.
As i am still Novice to Many OOPs concept i am unable to understand how do i achieve what i want using Abstract Class. below is the sample code i tried using which ofcourse is wrong for declaring an abstract method.
abstract class Property {
protected $error = array();
protected $data = array();
protected $dbh;
protected $validate;
abstract protected function connectDB($dbhandle) {
return $this->dbh = $dbhandle;
}
abstract protected function setValObj($valObj) {
return $this->validate = $valObj;
}
public function __set($property, $value) {
}
public function __get($property) {
}
}
here is what i want to do.
When a child class is initiated it should be forced to define methods as declared in abstract class.
A Child class should only be able to call and pass the arguement but not extend an abstract method. the mechanism should be handled by parent class. this is what i tried to do in my code.
i know i am missing something, or might be i have not got the concept right, could somebody explain me what exactly should i be doing to achieve the same result.
1 . Define a parent class which is not instantiable from outside.
All abstract classes can not be instantiated, only extended. So this is what you already have:
abstract class Property {
On to the next:
2 . Define all properties in this parent class so that i can re-use the same property for different child classes.
Just write them into that abstract class (often called base class or abstract base class or template class as well). All classes extending from a base class, will have access to protected or public member methods and properties. If you make a variable or function private, it's only available to code in the base class.
So just define all you want to have in the base class to be shared amongst all extending classes and you only need to type it once.
3 . Define re-usable class methods and objects so that child class can use it without the need of calling it again and again (Inheritance).
This works automatically. As you extend from the base class, the public and protected class methods defined therein are automatically accessible through the extending class. You do not (but you can unless specified with final) need to add that function again to make it available. E.g. all public methods from the base class are automatically available publicly on all classes that extend from it.
Then you continue:
here is what i want to do.
1 . When a child class is initiated it should be forced to define methods as declared in abstract class.
You can do so by defining these needed methods as abstract. Abstract methods needs to be implemented by the extending class. However you can not put code into abstract methods in the base class. That's left there for the extending class.
2 . A Child class should only be able to call and pass the arguement but not extend an abstract method. the mechanism should be handled by parent class. this is what i tried to do in my code.
If you want to prevent a subclass to overwrite a function, declare it as final in your base class. Final methods can not be further extended.
But probably you want to do something that is technically not possible, e.g. prevent that a method can be extended while you require that is should be extended.
In your code you're using magic functions to access the properties / values. Those don't count in the sense that their name changes. So you loose the control of the inheritance for a bigger part of your class design.
However, you can implement array access to offer getter/setters. It's bound to a concrete interface and you then can disallow access through the base class and prevent extending of this area for classes that will extend from it.
Let me know if you would like to have some example code, probably SPL is new to you as well.
Provide variable inheritance via ArrayAccess
As you've been running into the problem that inheritance can not be easily used on the magic function __get() and __set() which are available, I had the idea to make that part of the access concrete that does not change (get, set) while it's still possible to name the property variable. An interface that is available with PHP that already does this is ArrayAccess. It was designed to give access to properties via the style we know from standard php arrays ([]) and it's normally used for that. But for this example it has the benefit to already provide an interface as well that fits the general need.
First a demonstration how such a class behaves in use:
# give birth to the object
$object = new PropertyClass; // one of your property classes
# get:
$value = $object['propertyA'];
# set:
$object['propertyA'] = 'new value';
# unset:
unset($object['propertyA']); // and gone ;)
# isset:
isset($object['propertyA']); // true / false
Okay, as this shows, this looks like an array, but is an object. The rest of $object works as known, so this is no limitation, but an addition.
As you can imagine already with this code, there must be a get and set routine as well for reading and setting the properties values like with __get() and __set(). Additionally there must be something for isset and unset, so four. This is the interface definition of ArrayAccess:
ArrayAccess {
/* Methods */
abstract public boolean offsetExists ( mixed $offset )
abstract public mixed offsetGet ( mixed $offset )
abstract public void offsetSet ( mixed $offset , mixed $value )
abstract public void offsetUnset ( mixed $offset )
}
You can extend from that in PHP by implementing the interface. That's not extends but implements. This works with every interface in PHP, but this interface is something special as well. It's provided by the SPL/PHP itself and in the moment a class of yours actually implement the functions, the functionality as described in the code above is automatically added to your class.
As those functions are available publicly, you could call them with their name as well naturally.
So actually this interface qualifies for a properties object as you want to build one and will give you an interface you can put your constraints on.
So the only question left is: How can this look like for your properties class?
Implementing ArrayAccess to a variable properties class
<?php
/**
* Property Object base class based on ArrayAccess
*/
abstract class PropertyObject implements ArrayAccess
{
/** Interface Methods */
/**
* implementing classes must return all names of their properties
* in form of an array.
*/
abstract protected function returnNames();
/** class */
/**
* value store
*
* #var array
*/
private $store = array();
/**
*
* By this design, properties can only contain A-Z and a-z.
*
* look like.
*
* #return bool
*/
private function isValidPropertyName($name) {
return ctype_alpha($name);
}
private function checkOffsetArgument($offset) {
if ($this->isValidPropertyName($offset)) return;
throw new InvalidArgumentException(sprintf('"%s" is not a valid property name.', $offset));
}
private function setNames(array $names) {
foreach($names as $name) {
$this->checkOffsetArgument($name);
}
$len = count($names);
$this->store = $len
? array_combine($names, array_fill(0, $len, null))
: array()
;
}
/**
* final constructor to obtain control
*/
final public function __construct() {
$this->setNames($this->returnNames());
}
/**
* ArrayAccess impl.
*
* #return bool
*/
public function offsetExists($offset) {
$this->checkOffsetArgument($offset);
return array_key_exists($offset, $this->store);
}
/**
* ArrayAccess impl.
*
* #return mixed
*/
public function offsetGet ($offset) {
$this->checkOffsetArgument($offset);
return $this->store[$offset];
}
/**
* ArrayAccess impl.
*/
public function offsetSet($offset, $value) {
$this->checkOffsetArgument($offset);
if (!$this->offsetExists($offset)) {
throw new InvalidArgumentException(sprintf('Property "%s" can not be set.', $offset));
}
$this->store[$offset] = $value;
}
/**
* ArrayAccess impl.
*/
public function offsetUnset($offset) {
$this->checkOffsetArgument($offset);
unset($this->store[$offset]);
}
}
/**
* I feel so concrete.
*/
class ConcreteType extends PropertyObject
{
protected function returnNames() {
return array('propertyA');
}
}
$obj = new ConcreteType;
var_dump($obj['propertyA']); # NULL, maybe you need other default values.
$obj['propertyA'] = 'hello';
var_dump($obj['propertyA']); # string(5) "hello"
var_dump(isset($obj['propertyA'])); # bool(true)
// this will trigger an exception
try {
$obj['XProperty'] = 'good night.';
} catch (Exception $e) {
var_dump($e->getMessage()); # string(36) "Property "XProperty" can not be set."
}
// the following might be unwanted but can be prevented in base class:
unset($obj['propertyA']);
var_dump(isset($obj['propertyA'])); # bool(false)
I think you need to implement mixin interface. According to my knowledge PHP does not support this natively. Some PHP frameworks (like Yii framework) implemented it by itself. I found one example here. But I am sure you will be able to find better examples.

Categories