Code Completion When Using Factory Class - php

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
*/

Related

Laravel Service Container: Contextual binding on parent class, apply to all children

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();
});
}
}

What's the best design for extra data on behaviour class?

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.

Use Laravel 4 Encrypter within a namespace

I am trying to use Illuminate\Encryption\Encrypter; within a namespace which I created. The code really exists in my file.
Problem:
I want laravel to use the key set under 'app/config/app.php' automaticly. However the constructer wants me to set it properly with my hands.
To see how this task is handled by Taylor Otwell, I searched for an example and saw that under "Illuminate\Cache\DatabaseStore", it was set to $encrypter as an instance, using constructer. Tylor also uses a function to getEncrypter(); as follows:
/**
* Get the encrypter instance.
*
* #return \Illuminate\Encryption\Encrypter
*/
public function getEncrypter()
{
return $this->encrypter;
}
Because I want my class to be automaticly loaded with a function in another class; I can't use IoC Container.
Here are my functions and params:
/**
* The encrypter to be used for several reasons.
*/
protected $encrypter = "Illuminate\Encryption\Encrypter";
/**
* Returns the encrypter.
*
* #return Object
*/
public function getEncrypter()
{
return $this->createEncrypter();
}
/**
* Creates a new encrypter object.
*
* #param $string $encrypter
* #return Obj $encrypter instance
*/
public function createEncrypter()
{
$class = '\\'.ltrim($this->encrypter, '\\');
return new $class;
}
/**
* Sets the crypter used by MyFacadeName
*
* #param Encrypter $encrypter
*/
public function setEncrypter($encrypter)
{
$this->encrypter = $encrypter;
}
What is the difference makes the parser think that Taylor is right and I am wrong? What am I missing?
If you are on Laravel and you cannot access the Facades because they have not been loaded/initialized yet:
\Illuminate\Support\Facades\Config::get('app.key');
your last resort might be to access the $app via $GLOBALS:
public function createEncrypter()
{
$class = '\\'.ltrim($this->encrypter, '\\');
return new $class($GLOBALS['app']['config']->get('app.key'));
}

How to implement Repository Pattern in Codeigniter?

When I programmed in ASP.NET MVC, there was a neat pattern called Repository. I want to implment it in Codeigniter but I do not know how. Here is what I actually want:
$mock_repository = new MockRepository();
$mock_repository->add(new Item(‘title1′, ‘description1′, 1));
$mock_repository->add(new Item(‘title2′, ‘description2′, 2));
$mock_repository->add(new Item(‘title3′, ‘description3′, 1));
$controller = new Item_controller($mock_repository);
$items = $controller->get_items_by_user_id(1);
$this->_assert_equals(count($items), 2);
I am using TOAST for Unit Testing. So how do I instantiate a controller within a test? The test is of course, another controller itself.
From what I know, to create a Generic Repository Pattern like in C#, you need 2 things PHP 5.6 dosen't have:
Real Method Overloading.
Generic Interface or Generic Abstract Class in PHP.
Click here for more on Generic Repository Pattern in C#.
However you can still create pseudo method overloading in PHP with the help of magic method __call, and we can type little more code for the generic part of the pattern.
Note: Before creating this pattern in Codeigniter 3.0 you will need to create a table in the database, and create auto loader for folder application/libraries.
First we need to create Interface in application/libraries folder:
<?php
interface IRepository
{
public function getById($id);
public function select($columns);
public function delete($id);
}
Seconde we need to create Abstract Class implementing the Interface and extending the CI_Model to be able to use the Database librarie:
<?php
abstract class Base_repository extends CI_Model implements IRepository
{
/**
* This must be valid table name in the Database.
*
* #var string $table Name of the table.
*/
protected $table;
public function __construct()
{
parent::__construct();
}
/**
* Pseudo method overloading.
* It's called when method is not declared in the abstract class.
*
* #param string $name Name of the method
* #param mixed $arguments Arguments of the method
*/
public function __call($name, $arguments)
{
switch ($name)
{
case 'save':
if ($arguments[0]->id > 0)
{
$this->update($arguments[0]);
}
else
{
$this->insert($arguments[0]);
}
break;
}
}
/**
* Get row with id.
*
* #param integer $id
* #return mixed
*/
public function getById($id)
{
return $this->db->get_where($this->table, ['id' => $id])->row_array();
}
/**
* Select columns.
*
* #param array $columns
* #return mixed
*/
public function select($columns = ['*'])
{
$this->db->select($columns);
return $this->db->get($this->table)->result();
}
/**
* Insert data.
*
* #param object $item
* #return void
*/
private function insert($item)
{
unset($item->id);
$this->db->insert($this->table, $item);
}
/**
* Update data.
*
* #param object $item
* #return void
*/
private function update($item)
{
$this->db->where('id =', $item->id);
unset($item->id);
$this->db->update($this->table, $item);
}
/**
* Delete data.
*
* #param integer $id
* #return void
*/
public function delete($id)
{
$this->db->delete($this->table, ['id' => $id]);
}
}
Third test the repository. Make a new model in application/model, and extend Base_repository, set table name and overload save method, create entity for this model:
<?php
/**
* The entity class.
*/
class Test
{
public $id;
public $info;
}
class Test_model extends Base_repository
{
/**
* Tell what table we are using.
*/
public function __construct()
{
parent::__construct();
$this->table = 'test';
}
/**
* "Overload" save method and call it from the parent.
*
* #param test $item Make use of the Dependency Injection.
* #return void
*/
public function save(Test $item)
{
parent::save($item);
}
}
Try it in the controller. Load the model and try to get, insert, ect...
To create real models is the same procedure. If you need to add more methods that will be the same for every model add them in the abstract class if you need to create methods only for specific model add it only in this model.
I don't recommend Codeigniter freamwork. Here are some patterns for PHP CLICK!
You would have to completely hijack the system files to load a controller from another controller. It can't be done, methinks.
It can be done with HMVC.
$result = Modules::run('controller/get_items_by_user_id', $params);
$this->_assert_equals($result, $expected);

Netbeans Auto-Complete Not Working For Custom PHP Class

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();
}
}

Categories