How to load/access a custom class in the custom class in Symfony 2 not using service container?
If i try to use the custom logger as shown below i am getting the error:
Catchable Fatal Error: Argument 1 passed to MeetingBundle\Components\LogWriter::__construct() must implement interface Symfony\Component\HttpKernel\Log\LoggerInterface, none given, called in C:\Bitnami\wampstack-5.6.20-0\apache2\htdocs\sym\just2\src\MeetingBundle\Components\Serializer\Diff\EventDiff.php on line 23 and defined
Stack Trace:
in src\MeetingBundle\Components\LogWriter.php at line 12 -
private $logger;
public function __construct( LoggerInterface $logger ) // here they show the error
{
$this->logger = $logger;
}
src\MeetingBundle\Components\LogWriter.php
<?php
namespace MeetingBundle\Components;
use Symfony\Component\HttpKernel\Log\LoggerInterface;
class LogWriter
{
private $logger;
public function __construct( LoggerInterface $logger )
{
$this->logger = $logger;
}
public function log($msg)
{
$this->logger->log($msg);
}
}
src\MeetingBundle\Components\Serializer\Diff\Diff.php
<?php
namespace MeetingBundle\Components\Serializer\Diff;
//use MeetingBundle\Components\LogWriter;
class Diff
{
private $diffCluesArr;
private $name;
private $logWriter;
public function __construct ($logger) {
$this->name= "";
$this->diffCluesArr = [];
$this->logWriter = $logger;
//$this->logWriter = new $logWriter; //changed here
}
public function array_diff_str_o ( $arr1, $arr2, $str ) {
$this->logWriter("<br> In Diff function array_diff_str_o ");
//...
src\MeetingBundle\Components\Serializer\Diff\EventDiff.php
<?php
namespace MeetingBundle\Components\Serializer\Diff;
use MeetingBundle\Components\Serializer\Diff\Diff;
use MeetingBundle\Components\LogWriter;
/**
* Event normalizer
*/
class EventDiff extends Diff
{
private $diffCluesArr;
private $name;
private $logw;
// does not work
// public function __construct (LogWriter $logger) {
// $this->logw= $logger;
// parent::__construct($this->logw);
public function __construct () {
$this->logw = new LogWriter();
parent::__construct($this->logw);
$this->logw("<br> In constructor of EventDiff");
$this->name= "event";
$this->diffCluesArr = array(
//1 means compare normally
//2 means compare the values of the keys
'id' => 1,
// ..
app\config\services.yml
services:
meeting.logw:
class: MeetingBundle\Components\LogWriter
arguments: ["#logger"]
meeting.diff.diff:
class: 'MeetingBundle\Components\Serializer\Diff\Diff'
arguments: ["#meeting.logw"]
meeting.diff.event:
class: 'MeetingBundle\Components\Serializer\Diff\EventDiff'
parent: meeting.logw
#the same error: parent: meeting.diff.diff
src\MeetingBundle\Controller\EventMapController.php
//..
$diffentiator = $this->get('meeting.diff.event');
$diffentiator->array_diff_str_o( $arrEventOld, $arrEventNew, $msg );
//..
//**** THE OLD VERSION OF THE QUESTION
If i try to use the custom logger as shown below i am getting the error:
Catchable Fatal Error: Argument 1 passed to MeetingBundle\Components\Serializer\Diff\Diff::__construct() must be an instance of MeetingBundle\Components\Serializer\Diff\LoggerInterface, none given, called in C:\Bitnami\wampstack-5.6.20-0\apache2\htdocs\sym\just2\src\MeetingBundle\Components\Serializer\Diff\EventDiff.php on line 16 and defined
Where is the mistake? The code is as follow:
just2\src\MeetingBundle\Components\LogWriter.php
<?php
namespace MeetingBundle\Components;
use Symfony\Component\HttpKernel\Log\LoggerInterface;
class LogWriter
{
private $logger;
public function __construct(LoggerInterface $logger) // the place of error
{
$this->logger = $logger;
}
public function log($msg)
{
$this->logger->log($msg);
}
}
just2\src\MeetingBundle\Components\Serializer\Diff\Diff.php
<?php
namespace MeetingBundle\Components\Serializer\Diff;
use MeetingBundle\Components\LogWriter;
class Diff
{
private $logWriter;
public function __construct (LoggerInterface $logger) {
// the first mistake
$this->logWriter = $logger;
}
public function array_diff_str_o ( $arr1, $arr2, $str ) {
$this->logWriter("<br> In Diff function array_diff_str_o ");
//..
}
// src\MeetingBundle\Components\Serializer\Diff\EventDiff.php
<?php
namespace MeetingBundle\Components\Serializer\Diff;
use MeetingBundle\Components\Serializer\Diff\Diff;
/** Provides clue how to calculate the differences between entities instances */
class EventDiff extends Diff
{
private $diffCluesArr;
private $name;
public function __construct () {
parent::__construct();
$this->logWriter("<br> In constructor of EventDiff");
$this->name= "event";
$this->diffCluesArr = array(
//1 means compare normally
//2 means compare the values of the keys
'id' => 1,
//...
just2\src\MeetingBundle\Controller\EventMapController.php
/** * #Route("/edit/{id}", name="event_jsMap_edit")
* #Method("GET|POST")
* #Template("MeetingBundle:Event:ev_jsMap_edit.html.twig")
*/
public function editAction($id, Request $request)
{
...
$diffentiator = $this->get('meeting.diff.event');
$diffentiator->array_diff_str_o( $arrEventOld, $arrEventNew, $msg );
...
I also made logwrite to be a service, but maybe it is not necessary and i do not want it to be a service. I would like to use it as a individual class not as a part of a service container:
app\config\services.yml
services:
events.logger:
class: MeetingBundle\Components\LogWriter
arguments: ["#logger"]
meeting.diff.event:
class: 'MeetingBundle\Components\Serializer\Diff\EventDiff'
#class Diff is not a service. Class EventDiff extends from Diff.
The problem is most likely in the way you instantiate Diff in EventDiff class as the error message suggests. LogWriter seems allright.
Do you define EventDiff as a service as well with correct dependencies?
Edit: In EventDiff you're calling parent::__construct(); without any parameter. However the parent Diff class takes one parameter. You probably want to inject a service to EventDiff that'll be passed to its parent in the constructor.
You could Manage Common Dependencies with Parent Services. Try defining the service defining the parent attribute in the following manner:
services:
events.logger:
class: MeetingBundle\Components\LogWriter
arguments: ["#logger"]
meeting.diff.event:
class: 'MeetingBundle\Components\Serializer\Diff\EventDiff'
parent: events.logger
Hope this help
Related
I am trying to inject one service into another to call function from it but it throws an error:
Type error: Argument 1 passed to App\Base\Service\Shop\ShopService::__construct() must be an instance of App\Base\Service\AccountService, instance of ContainerSgqv3vy\appDevDebugProjectContainer given
And I think I implement everything correctly:
use App\Base\Service\AccountService;
use App\Base\Service\BaseService;
class ShopService extends BaseService
{
/**
* #param AccountService $accountService
*/
public function __construct(AccountService $accountService)
{
parent::__construct();
$this->accountService = $accountService;
}
And calling in my function from it:
this->accountService->getMyFunction();
And my instantiated class :
class BaseService
{
/** #var ContainerInterface */
var $container;
var $em;
public function __construct(ContainerInterface $container, EntityManagerInterface $em)
{
$this->container = $container;
$this->em = $em;
}
service.yml
app.shop:
class: App\Base\Service\ShopService
arguments: ["#service_container", "#doctrine.orm.default_entity_manager"]
public: true
When you extend a class that has constructor arguments, you should keep those arguments and add any extra argument after.
Example:
class BaseClass
{
public function __construct(Foo $foo, Bar $bar) {
// ....
}
}
To instantiate this class, you would need to pass the container and the entity managaer:
$base = new BaseClass($fooInstance, $barInstance);
If you want to extend this class, it will most likely still need those dependencies + our new dependency:
class ChildClass extends BaseClass
{
public function __construct(Foo $foo, Bar $bar, Duck $duck)
{
// The parent (BaseClass) requires Foo and Bar,
// or it will throw an error
parent::__construct($foo, $bar);
$this->duck = $duck;
}
}
To instantiate our new ChildClass, we would need to pass three arguments:
$child = new ChildClass($fooInstance, $barInstance, $duckInstance);
Then, when you define our ChildClass in the service.yml, you need to have define all three dependencies:
app.childclass:
class: ChildClass
arguments: ["Foo", "Bar", "Duck"]
...
Since I'm not using Symfony myself, you must excuse for not knowing the exact syntax of service.yml, but the concept is the same.
I need to add Mailable type to my mocked ActivationMail. Maybe you have better idea to mock my ActivationMail class?
Tested class:
class MailService
{
public function sendActivationEmail(User $user): void
{
$this->sendEmail(new ActivationMail($user));
}
//content
protected function sendEmail(Mailable $mailable): void
{
//content
}
}
ActivationMail:
class ActivationMail extends Mailable{}
Do you have idea how can I test it?
My test:
public function test_sendActivationEmail()
{
$user = Mockery::mock(User::class);
$mailable = Mockery::mock(Mailable::class);
Mockery::mock('overload:App\Mail\ActivationMail');
$mailService = new MailService();
$mailService->sendActivationEmail($user);
}
And my error:
TypeError: Argument 1 passed to App\Services\MailService::sendEmail()
must be an instance of Illuminate\Mail\Mailable, instance of
App\Mail\ActivationMail given
Here is my Test Class;
<?php
namespace stats\Test;
use stats\Baseball;
class BaseballTest extends \PHPUnit_Framework_TestCase
{
public function setUp() {
$this->instance = new Baseball();
}
public function tearDown() {
unset($this->instance);
}
public function testOps() {
$obp = .363;
$slg = .469;
$ops = $this->instance->calc_ops($obp, $slg); //line 23
$expectedops = $obp + $slg;
$this->assertEquals($expectedops, $ops);
}
}
And this is my Baseball Class;
<?php
namespace stats;
class Baseball
{
private function calc_ops($slg,$obp)
{
return $slg + $obp;
}
}
And I keep getting this error when I run my tests;
Fatal error: Call to private method stats\Baseball::calc_ops() from context 'stats\Test\BaseballTest' in /media/sf_sandbox/phpunit/stats/Test/BaseballTest.php on line 23
This is only a tutorial I am following.. But it's not working so it's frustrating because I am following it exactly.
You can't test private method, you can use a workaround and invoke it via reflection as described in this article.
This is a working example based on the article:
class BaseballTest extends \PHPUnit_Framework_TestCase
{
public function setUp() {
$this->instance = new Baseball();
}
public function tearDown() {
unset($this->instance);
}
public function testOps() {
$obp = .363;
$slg = .469;
// $ops = $this->instance->calc_ops($obp, $slg); //line 23
$ops = $this->invokeMethod($this->instance, 'calc_ops', array($obp, $slg));
$expectedops = $obp + $slg;
$this->assertEquals($expectedops, $ops);
}
/**
* Call protected/private method of a class.
*
* #param object &$object Instantiated object that we will run method on.
* #param string $methodName Method name to call
* #param array $parameters Array of parameters to pass into method.
*
* #return mixed Method return.
*/
public function invokeMethod(&$object, $methodName, array $parameters = array())
{
$reflection = new \ReflectionClass(get_class($object));
$method = $reflection->getMethod($methodName);
$method->setAccessible(true);
return $method->invokeArgs($object, $parameters);
}
Public – The method is publicly available and can be accessed by all subclasses.
Protected – the method / function / property is available to the parent class and all inheriting classes or we call them subclasses or child classes.
Private – the method is private and only available to the parent class / base class.
You can only test private methods within the class and call that public method that using the private method.
class Baseball
{
public function testMethod()
{
$a = 1;
$b = 2;
return $this->calc_ops($a, $b);
}
private function calc_ops($slg,$obp)
{
return $slg + $obp;
}
}
My Error:
ContextErrorException: Catchable Fatal Error: Argument 1 passed to
Agc\ManagerBundle\Lib\grafica::__construct() must implement interface
Symfony\Component\DependencyInjection\ContainerInterface, none given,
called in
C:\wamp\www\galileo\src\Agc\BackendBundle\Controller\DefaultController.php
on line 20 and defined in
C:\wamp\www\galileo\src\Agc\ManagerBundle\Lib\grafica.php line 10
My class grafica:
<?php
namespace Agc\ManagerBundle\Lib;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* #Route(service="srv_grafica")
*/
class grafica
{
private $container, $conn, $bdnmgi;
public function __construct(ContainerInterface $container)
{
$this->container = $container;
$this->conn = $this->getConn();
$this->bdnmgi = $this->getBd();
}
public function getConn(){
return $this->container->get('database_connection');
}
public function getBd(){
return $this->container->get('security.context')->getToken()->getUser()->getAdministracion()->getNombreEsquemamgi();
}
\ManagerBundle\Resources\config\services.yml
services:
srv_grafica:
class: Agc\ManagerBundle\Lib\grafica
arguments:
- '#service_container'
My DefaultController:
class DefaultController extends Controller
{
public function dashboardAction(Request $peticion)
{
$em = $this->getDoctrine()->getManager('customer_1');
$user= $this->get('security.context')->getToken()->getUser();
$esquema = $user->getAdministracion()->getNombreEsquemamgi();
var_dump($esquema);
$grafica = new grafica();
You need to pass the container to your service, below an example how to do it in your services.yml
services:
srv_grafica:
class: Agc\ManagerBundle\Lib\grafica
arguments:
- '#service_container'
That's wrong:
$grafica = new grafica();
Should be:
$grafica = $this->get('srv_grafica');
My Error:
> ContextErrorException: Catchable Fatal Error: Argument 1 passed to
> Agc\ManagerBundle\Lib\grafica::__construct() must implement interface
> Symfony\Component\DependencyInjection\ContainerInterface, none given,
> called in
> C:\wamp\www\galileo\src\Agc\BackendBundle\Controller\DefaultController.php
> on line 20 and defined in
> C:\wamp\www\galileo\src\Agc\ManagerBundle\Lib\grafica.php line 10
My class grafica:
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* #Route(service="srv_grafica")
*/
class grafica
{
private $container, $conn, $bdnmgi;
public function __construct(ContainerInterface $container)
{
$this->container = $container;
$this->conn = $this->getConn();
$this->bdnmgi = $this->getBd();
}
public function getConn(){
return $this->container->get('database_connection');
}
public function getBd(){
return $this->container->get('security.context')->getToken()->getUser()->getAdministracion()->getNombreEsquemamgi();
}
}
\ManagerBundle\Resources\config\services.yml
services:
srv_grafica:
class: Agc\ManagerBundle\Lib\grafica
arguments:
- '#service_container'
My DefaultController:
class DefaultController extends Controller
{
public function dashboardAction(Request $peticion)
{
$em = $this->getDoctrine()->getManager('customer_1');
$user= $this->get('security.context')->getToken()->getUser();
$esquema = $user->getAdministracion()->getNombreEsquemamgi();
var_dump($esquema);
$grafica = new grafica();
}
}
You are calling
$grafica = new grafica();
And this class requires ContainerInterface argument in constructor. To fix this you need to change this line to:
$grafica = new grafica($this->container);
Note, that your code is not written in Symfony way. To do this properly you should define your grafica class as a service and you should not inject whole container, just inject classes you need