Unable to inject Laravel's DB class into an abstract class located in another namespace folder.
Getting Error "Call to undefined method Illuminate\Support\Facades\DB::table()"
-Check:Working-
FrontController.php
<?php
use MyProject\MainPages\Front;
class indexController extends \BaseController {
/**
* #var Front
*/
private $Front;
/**
* #param ProductRepository $productRepo
*/
function __construct(Front $Front)
{
//Test
//$this->Front = $Front->goSetup();
}
}
-Check:Working-
Front.php
<?php namespace MyProject\MainPages;
use MyProject\MainPages\NavigationSkeleton;
class Front extends NavigationBluPrint {
/**
* Begins the process, Step 1
*/
protected function goSetup() {
// $this->DB->table() etc
}
}
-Not Working-
NavigationBluPrint.php
<?php namespace MyProject\MainPages;
use \DB;
abstract class NavigationBluPrint {
/**
* #var DB Laravel Database connection
*/
protected $dB;
public function __construct(DB $dB)
{
// SetDB so when extended it's already set for extended classes
$this->dB = $dB;
// Test below
$x = $this->dB->table('products')->get(); //Error: Call to undefined method Illuminate\Support\Facades\DB::table()
echo '<pre>';
print_r($x);
echo '<pre>';
}
}
If I need to do something with App:: to make this work, I dont understand how it's done. Thank you
Solution Found:In case someone else runs into the same problem.
In abstract class "NavigationBluPrint.php"
I replaced \DB; with=> use \Illuminate\Database\DatabaseManager as DB;
It seems to fix the problem, although I'm not sure whether its instantiating a new DB from start or using the same one. If former then it kind of defeats the purpose.
You're type hinting the facade for the DB class, not the DB class itself.
It's false the idea of using static method, via object and it is impossible.
you should create repository for your database operation then you can inject them greatly.
directions to create Eloquent repository or DB repository :
Here I found out a great article to do this.
Related
I have the following class
namespace MyApp;
use MyApp\SomeInterface;
class MyClass
{
public function __construct(SomeInterface $s)
{
//Some Logic here
}
//Another methods implemented There
}
The SomeInterface contains the following:
namespace MyApp
interface SomeInterface
{
/**
* #return SomeObject
*/
public function someMethodToImpement();
}
And I want to create a mock over my phpunit Test Class:
namespace Tests\MyApp;
use PHPUnit\Framework\TestCase;
use MyApp\MyClass;
use MyApp\SomeInterface;
class MyClassTest extends TestCase
{
public function someTest()
{
$fakeClass=new class{
public function myFunction($arg1,$arg2)
{
//Dummy logic to test if called
return $arg1+$arg2;
}
};
$mockInterface=$this->createMock(SomeInterface::class)
->method('someMethodToImpement')
->will($this->returnValue($fakeClass));
$myActualObject=new MyClass($mockInterface);
}
}
But Once I run it I get the error:
Tests\MyApp\MyClassTest::someTest
TypeError: Argument 1 passed to MyApp\MyClass::__construct() must implement interface MyApp\SomeInterface, instance of PHPUnit\Framework\MockObject\Builder\InvocationMocker given, called in /home/vagrant/code/tests/MyApp/MyClassTest.php on line
Do you know why that happens and how actually will create the mock Interface?
Instead of constructing the mock via
$mockInterface=$this->createMock(SomeInterface::class)
->method('someMethodToImpement')->will($this->returnValue($fakeClass));
Split it into seperate lines:
$mockInterface=$this->createMock(SomeInterface::class);
$mockInterface->method('someMethodToImpement')->will($this->returnValue($fakeClass));
And will work like a charm.
I've had a similar issue. I fixed it by adding those interfaces as another mock() parameter
class Product implements PriceInterface, ProductDataInterface {
// ...
}
Test:
// throws error
$product = Mockery::mock(Product::class);
// works fine
$product = Mockery::mock(Product::class, 'PriceInterface, ProductDataInterface');
Link to documentation
So I stick PDO into my SLIM using this:
$container['dbh'] = function($container) {
$config = $container->get('settings')['pdo'];
$dsn = "{$config['engine']}:host={$config['host']};dbname={$config['database']};charset={$config['charset']}";
$username = $config['username'];
$password = $config['password'];
return new PDO($dsn, $username, $password, $config['options']);
};
However, every time I use $this->dbh->execute() (or some other PDO method), PhpStorm warns me method 'execute' not found in class
Realistically it doesn't make a difference but I'd like my PhpStorm to stop warning me about things that it doesn't need to.
This is mostly an answer adding to #rickdenhaan's comment.
I noticed that you're using $this, which implies you have a class somewhere.
You can typehint dynamic/fake properties in a class like so:
/**
* #property PDO $dbh
*/
class MyApp {
}
For more help, read the PHPDoc documentation, eg here.
In some situations, you might not be able to influence the original class being instantiated. In that case, you can have a stub file; basically a class used only for type hinting:
// Let's assume you cannot modify this class.
class App {}
// This is the stub class, we declare it as abstract to avoid instantiation by mistake.
// We make it extend `App` to get metadata from there.
abstract class AppStub extends App {
/** #var PDO */
public $dbh;
}
// ...later on in your code..
/** #var AppStub $this */
// tada!
$this->dbh->execute();
Controller classes approach
Your main app + routing:
$app = new \Slim\App();
$app->get('/', \YourController::class . ':home');
$app->get('/contact', \YourController::class . ':contact');
And your controller:
class YourController
{
protected $container;
// constructor receives container instance
public function __construct(ContainerInterface $container) {
$this->container = $container;
}
public function home($request, $response, $args) {
$this->getDb()->execute(); // no IDE errors anymore!
return $response;
}
public function contact($request, $response, $args) {
return $response;
}
/**
* #return PDO
*/
protected function getDb()
{
return $this->container->get('dbh');
}
}
If your class is in a namespace, you should use \PDO to indicate that you are referring to a class in the root namespace.
If PhpStorm has problems with identifying variable/object, so for example it has warning 'Method some_method not found in...' for example for code like:
$my_object->some_method();
then you can help PhpStorm to identify class by adding variable type definition in comment like this:
/**
* #var \Some\Class $my_object
*/
$my_object->some_method();
General example. Add this comment before using $my_object variable (for example at the beggining of method were you will use variable $my_object, or before first usage of this variable):
/**
* #var \Some\Class $my_object
*/
and now every time you will use this variable in method, PhpStorm will know that this variable is an instance of \Some\Class, so warnings will disappear in following lines, for every usage of this variable. For example warnings will not show for this kind of usage:
/**
* #var \Some\Class $my_object
*/
...
$my_object->some_method();
...
$my_object->some_method1();
...
$my_object->some_method2();
...
$my_object->some_method();
I have:
1. IntegrationTestCase extends TestCase
2. UnitTestCase extends TestCase
3. AcceptanceTestCase extends TestCase
In these I have quite a lot of non-static methods which are used in a lot of tests. All of my Test classes extend one of these 3 classes.
Now in a lot of Test classes I have a setUp method which preps the data and services needed and assigns them to class variables:
class SomeTestClass extends IntegrationTestCase
{
private $foo;
public function setUp()
{
parent::setUp();
$bar = $this->createBar(...);
$this->foo = new Foo($bar);
}
public function testA() { $this->foo...; }
public function testB() { $this->foo...; }
}
Problem is setUp is ran for each test defeating what I wanted to do and if what setUp method does takes a long time this is multiplied by the number of test methods.
Using public function __construct(...) { parent::__construct(..); ... } creates a problem because now lower level methods and classes from Laravel are not available.
For the next person running into this issue:
I had the problem that I wanted to migrate the database before running my tests but I didn't want the database to be migrated after each single test because the execution time would be way too high.
The solution for me was using a static property to check if the database was already migrated:
class SolutionTest extends TestCase
{
protected static $wasSetup = false;
protected function setUp()
{
parent::setUp();
if ( ! static::$wasSetup) {
$this->artisan('doctrine:schema:drop', [
'--force' => true
]);
$this->artisan('doctrine:schema:create');
static::$wasSetup = true;
}
}
}
Solution given by Saman Hosseini and similar didn't workout for me. Using the static property to flag getting reset for the next test class.
To overcome this I've wrote separate test class to test the test database connection & initialize the test database for once & made sure this runs before all the other tests
<?php
namespace Tests\Unit;
use Tests\TestCase;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Artisan;
/**
* #runTestsInSeparateProcesses
*/
class DatabaseConnectionTest extends TestCase
{
/**
* Test the database connection
*
* #return void
*/
public function testDatabaseConnection()
{
$pdo = DB::connection()->getPdo();
$this->assertNotNull($pdo);
}
/**
* Initialize the test database for once
*
* #return void
*/
public function testInititializeTestDatabase()
{
Artisan::call('migrate:fresh');
Artisan::call('db:seed');
}
}
I recommend using the template methods called setUpBeforeClass and tearDownAfterClass
The setUpBeforeClass() method is called before the first test is executed and the tearDownAfterClass() method is called after last test is executed.
We use these two methods to share settings with all the tests.
For example, it is wise to get the database connection once in the setUpBeforeClass() method then get connection multiple times in the setUp() method.
And likewise, it is wise to close the database connection only once in the tearDownAfterClass() method then close the database connection after every test in the tearDown() method.
I am not sure what issues you see for setUpBeforeClass is static except for the one mentioned by Mark Baker. I assume you do know what you are doing, though. Here is a sample of possible usage.
class BeforeAllTest extends PHPUnit_Framework_TestCase
{
private static $staticService;
private $service; // just to use $this is tests
public static function setUpBeforeClass() {
self::createService();
}
public static function createService(){
self::$staticService = 'some service';
}
/**
* just to use $this is tests
*/
public function setUp(){
$this->service = self::$staticService;
}
public function testService(){
$this->assertSame('some service', $this->service);
}
}
UPDATE: just somewhat similar approach you can see at https://phpunit.de/manual/current/en/database.html (search for 'Tip: Use your own Abstract Database TestCase'). I am sure you are already using it since you are doing intensive db testing. But nobody restricts this way for db-issues only.
UPDATE2: well, I guess you would have to use smth like self::createService instead of $this->createService (I've updated the code above).
I am working with Symfony2 and trying to write some PHPUnit test for one of my classes.
This is what I have done so far following Symfony2 testing Docs i created a folder under Tests directory with a file myClassTest.php ini it:
<?php
namespace Test\TestBundle\Tests\Template;
use Test\TestBundle\Dto\Template\myTemplate;
class myTemplateTest extends \PHPUnit_Framework_TestCase
{
public function testMyMethod()
{
$test = new myTemplate();
}
}
This is myTemplate:
<?php
namespace Test\TestBundle\Dto\Template;
use Test\TestBundle\Doctrine\DatabaseRepository;
use Test\TestBundle\Validation\ValidationClass;
class myTemplate
{
/**
* #var ValidationClass
*/
private $validate;
/**
* #var DatabaseRepository
*/
private $db;
/**
* #param ValidationClass $validation
* #param DatabaseRepository $databaseRepository
*/
public function __construct(
ValidationClass $validation,
DatabaseRepository $databaseRepository
) {
$this->validate = $validation;
$this->db = $databaseRepository;
}
}
Errors:
Argument 1 passed to Test\TestBundle\Dto\Template\myTemplate::__construct()
must be an instance of Test\TestBundle\Validation\ValidationClass, string given,
called in Dev/project/src/Test/TestBundle/Tests/Template/myTemplateTest.php
More Errors:
This error points to the injected service in the construct $validation
Dev/project/src/Test/TestBundle/Dto/Template/myTemplate.php:42
This error corresponds to the instantiate class of myTemplate class
Dev/project/src/Test/TestBundle/Tests/Dto/Template/myTemplateTest.php:15
I understand the errors well i think I do but i have no idea how to fix it and these errors are shown when i run phpunit test.
For testing with PHPUnit, you should use Mocks and Stubs for imitation logic in your depends classes.
Before initialize myTemplate in test case, you should create a mock of this objects, or create original objects.
$validationMock = $this->getMock('ValidationClass');
$dbRepositoryMock = $this->getMock('DatabaseRepository');
$myTemplate = new myTemplate($validationMock, $dbRepositoryMock);
And after you can use invocation system for control called methods.
For more information, please visit PHPUnit site:
https://phpunit.de/manual/current/en/test-doubles.html
I have a class which I need to use to extend different classes (up to hundreds) depending on criteria. Is there a way in PHP to extend a class by a dynamic class name?
I assume it would require a method to specify extension with instantiation.
Ideas?
While it's still not possible and not exactly your answer i needed the same thing and didn't wanted to use eval, monkey-patching etc. So i used a default class by extending it in conditions.
Of course it means if you have 100 classes to extend you need to add 100 conditions with another extending operation but for me this looked like the right way.
<?php
if(class_exists('SolutionClass')) {
class DynamicParent extends SolutionClass {}
} else {
class DynamicParent extends DefaultSolutionClass {}
}
class ProblemChild extends DynamicParent {}
?>
Yes. I like the answer with eval, but a lot of people afraid of any eval in their code, so here's one with no eval:
<?php //MyClass.php
namespace my\namespace;
function get_dynamic_parent() {
return 'any\other\namespace\ExtendedClass';// return what you need
}
class_alias(get_dynamic_parent(), 'my\namespace\DynamicParent');
class MyClass extends DynamicParent {}
It is possible to create dynamic inheritance in PHP using the power of the magic __call function. It takes a little bit of infrastructure code to work but isn't too daunting.
Disclaimer
You really ought to think at least twice before using this technique as it's actually kind of bad thing to do.
The only reason I'm using this technique is because I don't want to have to either create the interface definitions or setup the dependency injections when creating templates for a site. I want to just be able to just define a couple of function 'blocks' in a template and then have inheritance automatically use the correct 'block'.
Implementation
The steps required are:
The child class now extends a 'DynamicExtender' class. This class intercepts any calls made by the child class, to methods that don't exist in the child class and redirects them to the parent instance.
Each 'ParentClass' is extended to a 'ProxyParentClass'. For every accessible method in the parent class, there exists an equivalent method in the 'ProxyParentClass'. Each of those methods in the 'ProxyParentClass' checks to see if the method exists in the ChildClass and calls the childs version of the function if it exists, otherwise it calls the version from ParentClass
When the DynamicExtender class is constructed you pass in what parent class you require, the DynamicExtender creates a new instance of that class, and sets itself as the child of the ParentClass.
So, now when we create the child object we can specify the parent class required and the DynamicExtender will create it for us, and it will appear as if the child class is extended from the class we requested at run-time rather than it being hard-coded.
This may be easier to understand as a couple of images:
Fixed inheritance is fixed
Dynamic inheritance with proxies
Demo implementation
The code for this solution is available on Github and a slightly fuller explanation of how this can be used here, but the code for the above image is:
//An interface that defines the method that must be implemented by any renderer.
interface Render {
public function render();
}
/**
* Class DynamicExtender
*/
class DynamicExtender implements Render {
var $parentInstance = null;
/**
* Construct a class with it's parent class chosen dynamically.
*
* #param $parentClassName The parent class to extend.
*/
public function __construct($parentClassName) {
$parentClassName = "Proxied".$parentClassName;
//Check that the requested parent class implements the interface 'Render'
//to prevent surprises later.
if (is_subclass_of($parentClassName, 'Render') == false) {
throw new Exception("Requested parent class $parentClassName does not implement Render, so cannot extend it.");
}
$this->parentInstance = new $parentClassName($this);
}
/**
* Magic __call method is triggered whenever the child class tries to call a method that doesn't
* exist in the child class. This is the case whenever the child class tries to call a method of
* the parent class. We then redirect the method call to the parentInstance.
*
* #param $name
* #param array $arguments
* #return mixed
* #throws PHPTemplateException
*/
public function __call($name, array $arguments) {
if ($this->parentInstance == null) {
throw new Exception("parentInstance is null in Proxied class in renderInternal.");
}
return call_user_func_array([$this->parentInstance, $name], $arguments);
}
/**
* Render method needs to be defined to satisfy the 'implements Render' but it
* also just delegates the function to the parentInstance.
* #throws Exception
*/
function render() {
$this->parentInstance->render();
}
}
/**
* Class PageLayout
*
* Implements render with a full HTML layout.
*/
class PageLayout implements Render {
//renders the whole page.
public function render() {
$this->renderHeader();
$this->renderMainContent();
$this->renderFooter();
}
//Start HTML page
function renderHeader() {
echo "<html><head></head><body>";
echo "<h2>Welcome to a test server!</h2>";
echo "<span id='mainContent'>";
}
//Renders the main page content. This method should be overridden for each page
function renderMainContent(){
echo "Main content goes here.";
}
//End the HTML page, including Javascript
function renderFooter(){
echo "</span>";
echo "<div style='margin-top: 20px'>Dynamic Extension Danack#basereality.com</div>";
echo "</body>";
echo "<script type='text/javascript' src='jquery-1.9.1.js' ></script>";
echo "<script type='text/javascript' src='content.js' ></script>";
echo "</html>";
}
//Just to prove we're extending dynamically.
function getLayoutType() {
return get_class($this);
}
}
/**
* Class ProxiedPageLayout
*
* Implements render for rendering some content surrounded by the opening and closing HTML
* tags, along with the Javascript required for a page.
*/
class ProxiedPageLayout extends PageLayout {
/**
* The child instance which has extended this class.
*/
var $childInstance = null;
/**
* Construct a ProxiedPageLayout. The child class must be passed in so that any methods
* implemented by the child class can override the same method in this class.
* #param $childInstance
*/
function __construct($childInstance){
$this->childInstance = $childInstance;
}
/**
* Check if method exists in child class or just call the version in PageLayout
*/
function renderHeader() {
if (method_exists ($this->childInstance, 'renderHeader') == true) {
return $this->childInstance->renderHeader();
}
parent::renderHeader();
}
/**
* Check if method exists in child class or just call the version in PageLayout
*/
function renderMainContent(){
if (method_exists ($this->childInstance, 'renderMainContent') == true) {
return $this->childInstance->renderMainContent();
}
parent::renderMainContent();
}
/**
* Check if method exists in child class or just call the version in PageLayout
*/
function renderFooter(){
if (method_exists ($this->childInstance, 'renderFooter') == true) {
return $this->childInstance->renderFooter();
}
parent::renderFooter();
}
}
/**
* Class AjaxLayout
*
* Implements render for just rendering a panel to replace the existing content.
*/
class AjaxLayout implements Render {
//Render the Ajax request.
public function render() {
$this->renderMainContent();
}
//Renders the main page content. This method should be overridden for each page
function renderMainContent(){
echo "Main content goes here.";
}
//Just to prove we're extending dynamically.
function getLayoutType() {
return get_class($this);
}
}
/**
* Class ProxiedAjaxLayout
*
* Proxied version of AjaxLayout. All public functions must be overridden with a version that tests
* whether the method exists in the child class.
*/
class ProxiedAjaxLayout extends AjaxLayout {
/**
* The child instance which has extended this class.
*/
var $childInstance = null;
/**
* Construct a ProxiedAjaxLayout. The child class must be passed in so that any methods
* implemented by the child class can override the same method in this class.
* #param $childInstance
*/
function __construct($childInstance){
$this->childInstance = $childInstance;
}
/**
* Check if method exists in child class or just call the version in AjaxLayout
*/
function renderMainContent() {
if (method_exists ($this->childInstance, 'renderMainContent') == true) {
return $this->childInstance->renderMainContent();
}
parent::renderMainContent();
}
}
/**
* Class ImageDisplay
*
* Renders some images on a page or Ajax request.
*/
class ImageDisplay extends DynamicExtender {
private $images = array(
"6E6F0115.jpg",
"6E6F0294.jpg",
"6E6F0327.jpg",
"6E6F0416.jpg",
"6E6F0926.jpg",
"6E6F1061.jpg",
"6E6F1151.jpg",
"IMG_4353_4_5_6_7_8.jpg",
"IMG_4509.jpg",
"IMG_4785.jpg",
"IMG_4888.jpg",
"MK3L5774.jpg",
"MK3L5858.jpg",
"MK3L5899.jpg",
"MK3L5913.jpg",
"MK3L7764.jpg",
"MK3L8562.jpg",
);
//Renders the images on a page, along with a refresh button
function renderMainContent() {
$totalImages = count($this->images);
$imagesToShow = 4;
$startImage = rand(0, $totalImages - $imagesToShow);
//Code inspection will not be available for 'getLayoutType' as it
//doesn't exist statically in the class hierarchy
echo "Parent class is of type: ".$this->getLayoutType()."<br/>";
for($x=0 ; $x<$imagesToShow ; $x++) {
echo "<img src='images/".$this->images[$startImage + $x]."'/>";
}
echo "<br/> <br/>";
echo "<span onclick='loadImagesDynamic();' style='border: 2px solid #000000; padding: 4px:'>Click to refresh images</span>";
}
}
$parentClassName = 'PageLayout';
if (isset($_REQUEST['panel']) && $_REQUEST['panel']) {
//YAY! Dynamically set the parent class.
$parentClassName = 'AjaxLayout';
}
$page = new ImageDisplay($parentClassName);
$page->render();
I don't think it's possible to dynamically extend a class (however if I'm wrong I'd love to see how it's done). Have you thought about using the Composite pattern (http://en.wikipedia.org/wiki/Composite_pattern, http://devzone.zend.com/article/7)? You could dynamically composite another class (even multiple classes - this is often used as a work around to multiple inheritance) to 'inject' the methods/properties of your parent class into the child class.
Couldn't you just use an eval?
<?php
function dynamic_class_name() {
if(time() % 60)
return "Class_A";
if(time() % 60 == 0)
return "Class_B";
}
eval(
"class MyRealClass extends " . dynamic_class_name() . " {" .
# some code string here, possibly read from a file
. "}"
);
?>
I have solved my same type of problem. The first parameter defines the original class name and the second parameter defines the new class name of class_alias function. Then we can use this function in if and else condition.
if(1==1){
class_alias('A', 'C');
}
else{
class_alias('B', 'C');
}
class Apple extends C{
...
}
Apple class extends to virtual class "C" which can be defined as class "A" Or "B" depend on if and else condition.
For More information you can check this link https://www.php.net/manual/en/function.class-alias.php
Get All declared_classes
Position, where the class will be declare.
class myClass {
public $parentVar;
function __construct() {
$all_classes = get_declared_classes(); // all classes
$parent = $parent[count($parent) -2]; //-2 is the position
$this->parentVar = new $parent();
}
}
I have an idea so simple, you can try
class A {}
class B {}
$dynamicClassName = "A";
eval("class DynamicParent extends $dynamicClassName {}");
class C extends DynamicParent{
// extends success
// Testing
function __construct(){
echo get_parent_class('DynamicParent'); exit; //A :)
}
}
I had to do this with a processor class that extends one of two abstract classes.
The working solution looks like this:
if (class_exists('MODX\Revolution\Processors\Processor')) {
abstract class DynamicProcessorParent extends
MODX\Revolution\Processors\Processor {}
} else {
abstract class DynamicProcessorParent extends modProcessor {}
}
class NfSendEmailProcessor extends DynamicProcessorParent {
/* Concrete class */
}
If the abstract parent classes contain abstract methods, they don't need to be implemented in either of the dynamic parent classes.
If you're working on a large project, you probably don't want to use DynamicParent as the class name unless the classes are namespaced . You'll need something more specific to avoid collisions .