I've got the following class in a Zend Framework project:
<?php
/**
* User's class
*
* This class should be responsible for all
*
* #author Steve Davies
* #copyright 2012
* #version SVN: $Id$
*/
class Api_Admin_Users extends Api_Core
{
/**
* Class Constructor
*
* #return void
*/
public function __construct() {
parent::__construct();
}
/**
* Get User's name
*
* This returns the user's name
*
* #return void
*/
public function new() {
$user = self::_instance()->_em->getRepository('UserManagement\Users')->find('1');
echo $user->getFullName();
}
}
However when I try and use code hinting on $user->getFullName();, it doesn't work.
Using the following trick from here, it works:
/**
* Get User's name
*
* This returns the user's name
*
* #return void
*/
public function new() {
/* #var $user \UserManagement\Users */
$user = self::_instance()->_em->getRepository('UserManagement\Users')->find('1');
echo $user->getFullName();
}
But, I don't want to have to include that comment line everytime I instantiate the object. When I try to move this to the Class definition - or even the method definition, it fails to work.
Can anyone provide an answer for this?
PHP is a dynamic language and as such it is not trivial to infer variable types from static code analysis (like it is in Java for example).
It's especially difficult with factory methods like yours getRepository('UserManagement\Users').
NetBeans currently has no way of knowing how to translate the function argument to the type of returned variable (unless you're satisfied with some parent class from which all subclasses returned by that factory derive). Unfortunatelly vdoc's are the only way to deal with such cases.
Create a method in Api_Admin_Users to access the repository and add the type hint there. This will benefit all methods in the class. As long as the methods in the repository are type-hinted correctly, you're all set.
class Api_Admin_Users extends Api_Core
{
/**
* Class Constructor
*
* #return void
*/
public function __construct() {
parent::__construct();
}
/**
* Get the repository
*
* #return \UserManagement\Users
*/
public static function getRepository() {
return self::_instance()->_em->getRepository('UserManagement\Users');
}
/**
* Get User's name
*
* This returns the user's name
*
* #return void
*/
public function new() {
$user = self::getRepository()->find('1');
echo $user->getFullName();
}
}
Related
Im trying to implement contextual binding of a DatabaseConnectionClass implementation based on the repository that requires it.
This is required so repostiories fetching data from different databases can do so using the relevant connection.
My database connection interface is as so
/**
* Interface DatabaseConnectionInterface
*
* #package App\Database\Connection
*/
interface DatabaseConnectionInterface {
/**
* Get the database connection
*
* #return Connection
*/
public function getConnection(): Connection;
}
My base repository
/**
* Class MiRepository
*
* Base repository centralising connection injection
*
* #package App\Repositories\Mi
*/
class MiRepository {
/**
* The connection to the database
*
* #var DatabaseConnectionInterface
*/
protected $connection;
/**
* MiRepository constructor.
*
* #param DatabaseConnectionInterface $connection
*/
public function __construct(DatabaseConnectionInterface $connection){
$this->connection = $connection->getConnection();
}
}
An extension of the repository
/**
* Class SchemeRepository
*
* #package App\Mi\Repositories
*/
class SchemeRepository extends MiRepository {
/**
* Find and return all stored SchemeValidator
*
* #return Scheme[]|NULL
*/
public function findAll(): ?array {
$results = $this->connection->select('EXEC [webapi_get_products_schemes]');
if(empty($results)){
return NULL;
}
$schemes = array();
foreach($results as $result){
$schemes[] = Scheme::create($result->SCHEMENAME);
}
return $schemes;
}
}
The service container binding
/**
* Class MiServiceProvider
*
* #package App\Providers
*/
class MiServiceProvider extends ServiceProvider
{
/**
* Register services.
*
* #return void
*/
public function register()
{
$this->app->when(MiRepository::class)
->needs(DatabaseConnectionInterface::class)
->give(function(){
return new MiDatabaseConnection();
});
}
}
The problem is when i try to inject an extension of the base repository i do not think the contextual binding is triggered and i get the exception
Target [App\\Common\\Database\\Connection\\DatabaseConnectionInterface] is not instantiable ...
Has anyone had this problem before, and know of way to use contextual binding on a parent class and have it triggered for all children?
I know this can be achieved by implementing contextual binding definitions for all child classes this seems a bit clunky however.
Thanks in advance!
As far as I know, because PHP and dependency injection as a whole relies on reflection to know the classes the constructors are looking for, it's basically doing a string pattern match to find the right binding. Because you haven't defined a bound string for your extended classes, it can't find a related bind function. So I suspect what you want to do won't work.
The work around to avoid too much repetitive code might be:
public function register()
{
foreach($repo in ['Foo', 'Bar', 'Baz']) {
$this->app->when($repo . Repository::class)
->needs(DatabaseConnectionInterface::class)
->give(function () use ($repo) {
$theClass = $repo . 'DatabaseConnection';
return new $theClass();
});
}
}
I have a game where the player can finish some tasks.
I have separated the behaviour part of the task to its ORM part.
Eventually a copy of the task is being saved somewhere on the player's document (doesn't matter where for this specific question).
The problem is, I am not sure where to put the extra information that I send to the client that is not necessary for the behaviour itself, but it is needed to show the player information regarding the task itself.
This is my task interface:
interface ITask
{
/**
* #param Player $player
*/
public function init(Player $player);
/**
* #param PlayerAction $action
*/
public function progress(PlayerAction $action);
public function reset();
/**
* #return bool
*/
public function isComplete();
}
This is my abstract task:
abstract class BaseTask implements ITask
{
/**
* #var int
*/
public $id;
/**
* #var int
*/
protected $currentValue;
/**
* #var int
*/
protected $targetValue;
public function __construct($targetValue)
{
$this->currentValue = 0;
$this->targetValue = $targetValue;
}
/**
* #param int
*/
public abstract function setCurrentValue($current);
/**
* #return int
*/
public abstract function getCurrentValue();
/**
* #return int
*/
public abstract function getID();
/**
* #param int
*/
public abstract function setID($id);
/**
* #return int
*/
public abstract function getTargetValue();
/**
* #param int
*/
public abstract function setTargetValue($target);
/**
* #return boolean
*/
public function isComplete()
{
if ($this->getCurrentValue() >= $this->getTargetValue())
{
return true;
}
return false;
}
}
Now I need to decide how where to put the extra data, e.g description, title, theme etc...
I thought about two options: I can just put it on the base task
itself, but then what happens if I don't need it? I just leave it
blank? feel like the wrong place for me.
I could create a wrapper
class that will hold the task, but then I will need to always
call the wrapper to get to the task, and it feels kind of
wrong.
Looking for alternative suggestions.
You should inherit the CustomTask from TaskBase.
If you you have limitation in inheritance, encapsulate additional fields into a class called TaskAdditionalInfoBase and associate to the TaskBase.
Then various classes can inherit TaskAdditionalInfoBase to present a custom additional info to the the task.
I'm completely new to Zend framework (though I've already used Symfony2 and I've heard they're similar), and I've started a project in which I have to upgrade a site (that is already fully functional) that was created with Zend 1.11.
The aim of my upgrade is to allow data (that was originally stored in a database, and that will now be stored in nosql, and a database, and could be in the future stored elsewhere) to be more buildable and less strongly coupled with Zend's model. (Model as in the M of MVC).
In order to achieve this, I was asked to use a web service that would interact with the data, and Zend's model.
That way, when the data's structure would be modified, the Zend website wouldn't directly be impacted, (and would still work!) and we'd just have to re-arrange the web service.
Is there any elegant way to make Zend's model interact with a web service rather than a database?
I hope my question is understandable...
Have a nice day,
M.G.
You can use Data mapper pattern. As a reference, you can see how the module ZfcUser has adopted this pattern
You can create an interface of mapper for each entity and create an implementation according to the the data storage.
For example,
Product Entity
class Product
{
/**
* #var int
*/
protected $id;
/**
* #var string
*/
protected $name;
/**
* Get id.
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set id.
*
* #param int $id
* #return UserInterface
*/
public function setId($id)
{
$this->id = (int) $id;
return $this;
}
/**
* Get name.
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set name.
*
* #param string $name
* #return UserInterface
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
}
Product Mapper
<?php
<?php
namespace Product\Mapper;
interface ProductMapperInterface
{
/**
* #var int $id
* #returns \Product\Entity\Product
*/
public function findById($id);
/**
* #var array $criteria
* #returns \Product\Entity\Product[]
*/
public function find(array $criteria, .....);
/**
* #var \Product\Entity\Product $product
*/
public function insert($product);
/**
* #var \Product\Entity\Product $product
*/
public function update($product);
}
To populate the entity, you can use hydrators. As a reference, you can view how ZfcUser uses hydrators.
I am using Netbeans 8 for a Symfony2 project.
I have created a factory class for my model queries (they are static calls and mess up testing).
E.g
<?php
namespace My\Custom\Bundle\Classes\Factories;
use My\Custom\Bundle\Model\UserQuery;
class QueryFactory
{
/**
* Class name
* #access public
*/
const CLASS_NAME = __CLASS__;
/**
* newUserQuery()
*
* Creates a new user query object.
* #access public
* #return My\Custom\Bundle\Model\UserQuery
*/
public function newUserQuery()
{
return UserQuery::create();
}
}
What I want is for the auto complete to work on a variable that is created from a factory method (in this case the Propel methods for the User query).
<?php
namespace My\Custom\Bundle\Controller;
use My\Custom\Bundle\Classes\Factories\QueryFactory;
class ReportingController
{
private $queryFactory;
public function __construct(QueryFactory $query_factory)
{
$this->queryFactory = $query_factory;
}
public function fubar()
{
$user = $this->queryFactory->newUserQuery();
// now want auto complete on the $user (in this case the propel methods)
// $user->filterById(1);
}
}
Any ideas?
I think the problem is #return pointing to My\Custom\Bundle\Classes\Factories\My\Custom\Bundle\Model\UserQuery
try changing it to this
/**
* ...
* #return UserQuery
*/
Without the use statement it should be like this
/**
* ...
* #return \My\Custom\Bundle\Model\UserQuery
*/
How can code completion occur with phpDoc blocks loaded using the T_OBJECT_OPERATOR without having to preset the variables as is shown is the source below?
The only class that matters is the parentExample as it set's the needed $cc that does offer a working solution but it is not desired to preset variables in this manner.
The example code shows the undesired solution and multiple non-working attempts.
As code completion is based on previously set information, preferred to use the full example script not just pieces. Also, as it does relate to phpDocumentor basic phpDoc blocks were included as well. It is desired that these docBlocks get loaded as part of the code completion not just named objects.
<?php
/**
* This is a parent class.
*
* #package Examples/doubledVars
*/
class parentExample
{
/* #var $a parentExample */
public $a;
/**
* This is a var named b
* #var $b parentExample
*/
public $b;
public $c;
public $cc;
// notice^ <------------------------------------------------------SEE ME
/**
* A basic contructor
*/
public function __construct()
{
echo '::PE Class initiated::';
$this -> a = 'we are value "a" in the parent class';
$this -> b = 'we are value "b" in the parent class';
$this -> c = 'we are value "c" in the parent class';
}
}
/**
* This is an Example of doubling occuring due to failed to __construct()
*
* #package Examples/doubledVars
*/
class doubledVars extends parentExample
{
/**
* Value is obtained via parent constuctor.
*
* #return string assigned during construction of parent class.
*/
public function getA()
{
return $this -> a;
}
}
/**
* This is an Example of no doubling occuring due to __construct()
*
* #package Examples/doubledVars
*/
class noDouble extends parentExample
{
/**
* an empty constructor used to prevent doubling during construction.
* child class makes use of parent constructor unless it has it's own.
* or none exsist.
*/
public function __construct()
{
}
/**
* Empty string return
*
* Shows an example of returning values set based on the constructor
* class. In this case there is no default values set at any point, but
* rather value is assigned during the construction of a object.
*
* #return string This string is empty
*/
public function getB()
{
return $this -> b;
}
}
/**
* This is an Example of no doubling occuring due to __construct()
* #see noDouble
*
* #package Examples/codeCompletion
*/
class codeCompletion extends parentExample
{
/**
* #see noDouble::__construct()
*/
public function __construct()
{
//empty constructor prevents doubling
}
public function getC()
{
return $this -> c;
}
}
/** #var $parentExampleDV parentExample */
$parentExampleDV = new parentExample;
// Tried this for Code completion, it did not work <------------------SEE ME
/** #var $doubledVars doubledVars */
$parentExampleDV->doubledVars = new doubledVars;
/* output on next 'echo' will be as follows */
//::PE Class initiated::::PE Class initiated::we are in the parent class
echo '##'.$parentExampleDV->doubledVars->getA().'##';// NO CC <-------SEE ME
echo '<br><br>----------<br><br>';
/** #var $parentExampleDV parentExample */
$parentExampleND = new parentExample;
// Tried this for Code completion, it did not work <------------------SEE ME
/** #var $parentExample->noDouble noDouble */
$parentExampleND -> noDouble = new noDouble;
/* output on next 'echo' will be as follows */
//we are in the parent class
echo '!!'.$parentExampleND->noDouble->getB().'!!';// NO CC <----------SEE ME
echo '<br><br>----------<br><br>';
$parentExampleCC = new parentExample;
$parentExampleCC->cc = new codeCompletion;
echo '##'.$parentExampleCC->cc->getC().'##';//CC working <------------SEE ME
echo '<br><br>----------<br><br>';
I guess It is not possible at this time...