I am looking to extend a trait by using it in another trait. However the trait is using a method that looks like it isn't extending. The trait works, so I am wondering how.
Why does this trait have access to the markEntityForCleanup method?
The code is in this repo for Drupal Test Traits
<?php
namespace weitzman\DrupalTestTraits\Entity;
use Drupal\Tests\node\Traits\NodeCreationTrait as CoreNodeCreationTrait;
/**
* Wraps the node creation trait to track entities for deletion.
*/
trait NodeCreationTrait
{
use CoreNodeCreationTrait {
createNode as coreCreateNode;
}
/**
* Creates a node and marks it for automatic cleanup.
*
* #param array $settings
* #return \Drupal\node\NodeInterface
*/
protected function createNode(array $settings = [])
{
$entity = $this->coreCreateNode($settings);
$this->markEntityForCleanup($entity);
return $entity;
}
}
I found the issue.
When using the Drupal Test Traits package you are expected to use your own custom php-unit bootstrap.php and manually load the required packages.
Adding this line to the bottom of the bootstrap script will gain access to the namespace in php.
// <?php is needed for SO to do the syntax highlighting.
<?php
// Register more namespaces, as needed.
$class_loader->addPsr4('weitzman\DrupalTestTraits\Entity\\', "$root/vendor/weitzman\drupal-test-triats\src\Entity");
Related
When in a class there is the ability to autocomplete certain methods, e.g. the constructor or some inherited functions. I'd like to add some custom methods like public function foo():void to the autocomplete if a specific trait is applied. First I thought of Live Templates but they cannot be constrained to be only applied if there is a certain trait present.
Do you have any idea how I could achieve this? Maybe by generating some docblocks?
You can use #method tag in PHPDoc comment for the trait to declare such "virtual" methods. Modern PhpStorm versions can offer such signature when invoking code completion when declaring a new method.
<?php
declare(strict_types=1);
/**
* #method void traitPublic()
*/
trait T
{
private function traitPrivate(): void
{
}
}
class C
{
use T;
}
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.
I'm playing around with packages and I'm able to my code to work (in my controllers) when I do this:
App::make('Assets')->js('bla');
Now I want to set up a static facade so I can do this:
Assets::js('bla');
for this and I'm getting errors. I've been following this blog entry and haven't had any trouble up to this point. But now I'm stuck with a " Call to undefined method" error.
I'm not sure what code you'd need to see, so here's everything: https://github.com/JoeCianflone/msl/tree/jc-working
Specifically here is my workbench: https://github.com/JoeCianflone/msl/tree/jc-working/workbench/Joecianflone/Assets
And here is the controller where I was messing around with it: https://github.com/JoeCianflone/msl/blob/jc-working/app/controllers/HomeController.php
Any help greatly appreciated.
Looks like it was an issue with namespacing, I got it working by changing this:
<?php namespace Joecianflone\Assets\Facades;
use Illuminate\Support\Facades\Facade;
class Assets extends Facade {
/**
* Get the registered name of the component.
*
* #return string
*/
protected static function getFacadeAccessor() { return 'Assets'; }
}
to this:
class Assets extends \Illuminate\Support\Facades\Facade {
/**
* Get the registered name of the component.
*
* #return string
*/
protected static function getFacadeAccessor() { return 'Joecianflone\Assets\Assets'; }
}
What I'm not sure about is why the code from the tutorial worked but mine didn't. I must have skipped a step.
Just a sidenote, if you plan to share your code with the communuty (please do) i encourage you to use 5.3 syntax. Laravel requirements is 5.3 so dont use 5.4 in your package.
I am using a plugin (in this case Authake) and I would like to override/extend some of the functionality, but I'm not sure how I would go about doing this. I've managed to figure out how to customize the view (I created a folder '/app/views/plugins/authake' but I'm wondering how to modify/override/extend the Models and Compoenents of the plugin.
I'm guessing you want to extend the functionality of a model or perhaps a behavior in the plugin?
For example, we could extended the functionality of a Sequence behavior that is part of a Sequence plugin like so:
Create a new file in app/models/behaviors and call it extended_sequence.php
In this file, we'll create an ExtendedSequenceBehavior class that extends SequenceBehavior and overrides the beforeFind method. It will end up looking something like:
<?php
/**
* Import the SequenceBehavior from the Sequence Plugin
*/
App::import('Behavior', 'Sequence.Sequence');
/**
* Extended Sequence Behavior
*/
class ExtendedSequenceBehavior extends SequenceBehavior
{
/**
* Overrides the beforeFind function
*/
public function beforeFind(&$model, $queryData)
{
/**
* Do something different here such as modify the query data
*/
/**
* You could still call the original function as well
*/
parent::beforeFind(&$model, $queryData);
}
}
?>
Note, that we have to import the Sequence behavior using Cake's App::import before we define the ExtendedBehavior class.
Update your model to use the extended class:
var $actsAs = array('ExtendedSequence');
I'm using PHP Storm as my IDE, but I believe that other IDE's such as Netbeans will have the same issue as I'll explain below.
When using a framework like Symfony2, we have the wonderful world of Dependency Injection added. So objects can simply be instantiated using code like the following snippet:
$myThingy = $this->get('some_cool_service');
This is very handy, as objects are already configured beforehand. The one problem is, that auto-completion breaks entirely in basically any PHP IDE, as the IDE does not know what type the get() method is returning.
Is there a way to preserve auto-completion? Would creating for example an extension of Controller be the answer? For example:
class MyController extends Controller {
/**
* #return \MyNamespace\CoolService
*/
public getSomeCoolService() {
return new CoolService();
}
}
and then for application controllers, specify MyController as the base class instead of Controller?
What about using a Factory class, or any other possible methods?
It is more involving, but you can still do this with eclipse PDT:
$myThingy = $this->get('some_cool_service');
/* #var $myThingy \MyNamespace\CoolService */
UPDATE:
The example on this page shows you may also use the other way round with phpStorm:
$myThingy = $this->get('some_cool_service');
/* #var \MyNamespace\CoolService $myThingy */
You could define private properties in your controllers
class MyController extends Controller
{
/**
* #var \Namespace\To\SomeCoolService;
*/
private $my_service;
public function myAction()
{
$this->my_service = $this->get('some_cool_service');
/**
* enjoy your autocompletion :)
*/
}
}
I use base Controller class for bundle. You need to annotate the return in method. At least that works on Eclipse.
/**
* Gets SomeCoolService
*
* #return \Namespace\To\SomeCoolService
*/
protected function getSomeCoolService()
{
return $this->get('some_cool_service');
}
I don't like /*var ... */, because it gets too much into code.
I don't like private properties, because you can wrongly assume that services are already loaded.
I use Komodo Studio, and tagging variables with #var, even inside methods, preserves auto completion for me.
namespace MyProject\MyBundle\Controller;
use Symfony\Component\DependencyInjection\ContainerAware;
use Symfony\Component\HttpFoundation\Request;
class WelcomeController extends ContainerAware
{
public function indexAction()
{
/*#var Request*/$request = $this->container->get('request');
$request->[autocomplete hint list appears here]
}
}
working with netbeans IDE 7.1.2 PHP