I am using a framework that allows adding new components to the framework's base class. Is there any way to document these new methods without changing the frameworks files so I can click through to the method in my IDE.
I highly recommend against trying to inject a subclass. If the framework instantiates the class you're extending directly, you'll need to find a way to get it to use your subclass instead.
NetBeans and PhpStorm (and probably many others) will combine elements from multiple definitions of the same class/interface. This allows you to add properties and methods to any existing class without modifying the original source.
/**
* Framework controller base class.
* Provides helpers via __call().
*/
class Framework_Controller { ... }
Now create a file in your code base that you never require containing the same class definition. Your IDE should still parse it and merge its elements with the class above:
if (false) { // Safety first!
/**
* ACME Co. controller base class.
*
* #method ACME_Model_User getUser Load user via authentication helper
*/
class Framework_Controller { /* nothing to add */ }
}
You can try using an interface and declaring the methods normally instead of with #method. That is what we did with Zend_View since it's already an interface. I haven't tried mixing class with interface to see if PhpStorm likes it.
It depends mainly on IDE you are using. I think you should extend base class and add there some new methods/properties with phpdoc comments. Of course changing framework's files is no solution as you already mentioned
You could extend the original class, redefine the function, with new doc, and call the parent function.
e.g.
class newClass extends originalClass
{
/**
* New PHPDoc
*/
function functionName($a)
{
return parent::functionName($a);
}
}
Try to use #see or inline #link directives.
Related
I have a FeatureContext class, whose methods implement step definitions for my feature scenarios.
Is it possible to obtain information about current scenario or feature within FeatureContext class? To be specific, I need the path of the feature file, so I can create directory paths relative to dirname('file.feature').
The context class resides somewhere in vendor directory structure, i.e. far away from the actual feature file, so getting the path using __DIR__ would not work.
Any ideas?
Thanks, Sascha
I did find an answer to my question: "hooks"
class MyContext implements Context
{
// ...
/**
* #BeforeScenario
*/
public function beforeScenario(BeforeScenarioScope $scope)
{
var_dump($scope->getFeature()->getFile());
}
}
I have a trait that must always be mixed in to a subclass of \PHPUnit_Framework_TestCase. PhpStorm doesn't know this. Is there anything I can do to get PhpStorm to autocomplete and "typecheck" things like assertNull inside the trait?
<?php
trait MyTestUtils
{
public function foo()
{
$this->assertNu // autocomplete?
}
}
The best I could come up with so far is putting the following in each method:
/** #var \PHPUnit_Framework_TestCase|MyTestUtils $this */
But this is repetitive and doesn't understand protected memebers. Is there a better option?
Besides using the php docblock to document $this, the only other way I'm aware of, which also, arguably makes your trait more "safe" anyway, is to define abstract methods on the trait itself, e.g.:
trait F {
/**
* #return string[]
*/
abstract public function Foo();
/**
* #return self
*/
abstract public function Bar();
}
abstract class Bar {
use F;
/**
* #return bool|string[]
*/
public function Baz () {
if ($this->Bar()) {
return $this->Foo();
}
return false;
}
}
UPDATE: Since PhpStorm 2016.1.2 (build 145.1616) autocompletion in traits works out-of-the-box. It is smart enough to figure out what classes use the trait, and then provide the autocompletion. Link to the issue: https://youtrack.jetbrains.com/issue/WI-16368
Previously replied with:
You can use:
#method \PHPUnit_Framework_TestCase assertTrue($condition, $message = '')
...in docblock of the trait itself, but the downside is that you'd need to put #method for each method that you'd like to have autocomplete for, which is not too bad if you're using a sane number of method calls in your trait. Or, "document" only those methods that you're using most often.
I would argue that this is not a valid use-case for a PHP trait. Your trait, as written is not guaranteed to only be used on classes that extend \PHPUnit_Framework_TestCase. This introduces very tightly coupled code. The best practice of Traits is for them to be very loosely coupled and only be aware of their own contents.
I would instead recommend that you either:
create a subclass of \PHPUnit_Framework_TestCase that your test cases that need this functionality can extend
create custom assertion classes. These can many times be used for doing groups of custom assertions.
Both techniques are detailed here: http://phpunit.de/manual/4.1/en/extending-phpunit.html
These are the two recommended best practices for where to place helper methods such as these.
Working with Symfony2 and trying to figure out how best to incorporate Vendor libraries. Calling vendor library methods is very easy using the routing configs: use the appropriate namespace, generate the class name, the method to call, and the arguments from a couple path components and query vars, voila, instant integration.
I'm having trouble with forms, though. My goal seems like it should be very easy. I want to make forms in Symfony2 from vendor classes. As a specific example, consider the google-api-php-client. It seems like ->createForm() would work best, because it bridges to the ORM and validation so nicely. However, it relies on a a MyBundle\Form\ThingType file and class. To create this class, I need an entity within my bundle. I can't (or haven't been able to figure out how to) just use existing "Entities" from vendor libraries. Creating the "Entity" in the Symfony nomenclature when a "Model" already exists in the API lingo seems to be inflexible and very un-D.R.Y.
The other method I've gotten to work is using
$formBuilder = $this->createFormBuilder(new GoogleApi\Contrib\Event);
then
foreach(get_object_vars($event) as $prop) { $formBuilder->add($prop); }
but this does not utilize the seemingly ready-made bridge between the API documentation and the built-in validation tools, and it also means each individual data type is going to have to be declared individual or array to decide whether to include a collection of class-based forms or a single, class-based form.
In short, I want to use the properties and dataType information available in the API, and, if necessary, the Resource representations like this one to create a simple function (like my call function) for creating nested, self-validating forms for the classes in the Google API. I want to accomplish this without creating a bunch of "Entities" and "FormTypes" that simply rewrite what is already written in the library.
Did the vendor library not have any installation details? You should generally calls vendor things from the controller using service calls like $this->get('vendor.name.form_object') rather than calling the class at the service will include any needed dependencies.
Also the entity that you would create in your bundle would only be the basic entity that would then extend their premade abstract classes. For example (taken from https://github.com/FriendsOfSymfony/FOSUserBundle)
<?php
// src/Acme/UserBundle/Entity/User.php
namespace Acme\UserBundle\Entity;
use FOS\UserBundle\Entity\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="fos_user")
*/
class User extends BaseUser
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
public function __construct()
{
parent::__construct();
// your own logic
}
}
If you want to add any of your own entity items then you can do it in this, but still keep the methods and properties from the base entity/model.
doeas anybody use the Query\Builder from Doctrine as Standalone Tool ?
It seems like The Query Manager needs a defined
Class of the requested Document in MongoDB.
If you have a defined Class like:
<?php
namespace Documents;
/** #Document */
class User
{
// ...
/** #Field(type="string") */
private $username;
}
Then you can do the following:
<?php
$user = $dm->createQueryBuilder('User')
->field('username')->equals('jwage')
->getQuery()
->getSingleResult();
Is there a way to do use the Query\Builder without defining the Document Classes ?
Thanks in advance for any help.
You can use the QueryBuilder as soon as you have ClassMetaData.
This class metadata is about mapping class properties to internal information, such as data types, associations, ...
You can define this class metadata without having real classes.
There are different approaches, but one of them would be to use the Doctrine\ODM\MongoDB\Tools\DisconnectedClassMetadataFactory class, and feed related information using yaml or xml mapping.
You will have to configure your DocumentManager with the good classMetadataFactoryName option.
I need some classes to befriend other classes in my system. Lack of this feature made me publicize some methods which shouldn't be public. The consequences of that are that members of my team implement code in a bad and ugly way which causes a mess.
Is there a way to define a friendship in php 5.3?
(I am aware of http://bugs.php.net/bug.php?id=34044 You might want to vote there if there is no simple solution).
I was seeking the same functionality and was able to implement a solution. To use it, just derive from class Friendship and specify the classes that are friends of your derived class. You can find it here: http://rommelsantor.com/clog/2011/04/23/php-5-3-class-friendship-support
In short, no. The generally accepted approach is to either educate your team on how to develop against your libraries or redesign. The first solution can be done quite easily by building docs with phpdoc and setting the visibility in the docbloc comments with #visibility, and of course actually documenting the classes. The second I wouldn't be able to comment on without knowing a little more detail.
/**
* Some helper class for LibraryInterface
*
* ATTENTION!
* This class should not be used outside this package.
*
* #visibility package
* #package mypackage
*/
class Helper
{
public function doStuff()
{
/* does stuff */
}
}
/**
* Class for accessing some part of the library.
*
* #visibility public
* #package mypackage
*/
class LibraryInterface
{
public function doStuff()
{
$this->helper->doStuff();
}
}
I'm not sure what you mean by "befriend". You can use abstract classes, in which any new class can "implement" that class. Or you can have classes extend other classes and make the methods, variables, etc "protected" as opposed to public or private.
If your team implements any code "in a bad and ugly way", then you may have bigger problems.