Extending or Overriding CakePHP plugins without modifying original - php

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');

Related

Add to custom methods to method signature autocomplete

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

Why is this method available in this trait?

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");

Overriding controllers in Prestashop 1.7

Hi I want to override a controller (in /controllers/front/MyAccountController.php) I tried different things :
In a custom module : /modules/my_module/override/controllers/front/MyAccountController.php
class MyAccountController extends MyAccountControllerCore
{
/**
* Assign template vars related to page content
* #see FrontController::initContent()
*/
public function initContent()
{
exit("test");
}
In /override/controllers/front/MyAccountController.php
// SAME CODE //
I also tried with this code :
class MyAccountControllerCore extends FrontController
{
/**
* Assign template vars related to page content
* #see FrontController::initContent()
*/
public function initContent()
{
exit("test");
}
What is the correct wayto do it, please ?
All this methods should work,
Did you check the option Disable all overrides in Advanced Parameters > Performance
It should be to No.
You can also delete the file app/cache/prod/class_index.php to force PrestaShop to scan the override folder.
To override MyAccountController controller you need to extend MyAccountControllerCore class and in initContent function add parent::initContent() and clear cache it may work.

In phpdoc, define class properties in separate file

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.

Generating classes at runtime in yii framework is a bad idea?

Let's assume that we have module called 'UsersModule' with the following model in it:
class User extends CActiveRecord
{
// Some code here
}
We use this module in different applications and some time we want to extend User model to add some custom methods or properties to it. More over, often we want to change tables in database to store this new properties in it. But we don't want to change code in the UsersModule itself because it comes from the master repository (GitHub for ex.) and when we fix some bugs in it we want to simply update this module from repository in all our projects. At the same time we want to save custom changes made for the projects. So we have the following idea:
In UsersModule.php we do the following:
class UsersModule extends CWebModule
{
public $usersBaseClass = 'UsersBase';
}
In Users.php:
$extendClass = Yii::app()->getModule('users')->usersBaseClass;
$version = '1.0';
$usersFile = Yii::getPathOfAlias('application.runtime').'/Users_extends_'.$extendClass.'_v'.$version.'.php';
if(!file_exists($usersFile)) {
$code =<<<PHP
<?php
/**
* This is the model class for table "{{users}}".
*/
class Users extends {$extendClass}
{
/**
* Returns the static model of the specified AR class.
* #param string \$className active record class name.
* #return Users the static model class
*/
public static function model(\$className=__CLASS__)
{
return parent::model(\$className);
}
}
PHP;
file_put_contents($usersFile, $code);
}
if(!class_exists('Users', flase))
require_once($usersFile);
Also we introduce UsersBase.php:
class UsersBase extends CActiveRecord
{
// All base Users model logic is here
}
So when we use Users class somewhere in our application our code in Users.php generates real Users class that extends desired base class. In each project when we want to extend our Users model we can do the following:
In configs/main.php of the project:
'modules' =>
'users => array(
'usersBaseClass' => 'MyUsers'
)
And also we add MyUsers.php some where in our application:
class MyUsers extends UsersBase
{
// All the custom logic goes here
}
So my question is:
Is it a good idea to generate classes automatically in runtime or not?
Genrating php code during runtime could work, but not the best solution imho. You should use some kind of table inheritance.
More info:
http://www.yiiframework.com/wiki/198/single-table-inheritance/
http://learnyii.blogspot.hu/2012/04/yii-table-inheritance-single-active.html

Categories