Variables in Trait - php

I have created a trait in Laravel.
In myconstruct I am calling a setting('value') - This is provided by the qcod/laravel-app-settings package.
But inside my methods when I reference $this->token or $this->org_id it returns NULL
I know the values are set, as they're showing in the config and are also set correctly in the Database.
My PHP code is :
<?php
namespace App\Traits;
use Illuminate\Support\Facades\Log;
trait PropertyBaseTrait
{
private $org_id;
private $token;
private $is_set;
public function __construct()
{
$this->org_id = setting('propertybase_org');
$this->token = setting('propertybase_token');
}
public function base_url($method)
{
return 'https://pb-integrations-api-staging.herokuapp.com/api/v1/'.$method.'/'.$this->org_id.'';
}
public function post_lead($data)
{
$lead_data = array(
'first_name' => '',
'last_name' => '',
'email' => '',
'phone1' => '',
'phone2' => '',
'phone3' => '',
'address' => '',
'city' => '',
'state' => '',
'zip_code' => '',
'country_name' => '',
'landing_page' => '',
'search_term' => '',
'referral_source' => ''
);
$object_type = 'lead';
$action_type = 'create';
dd($this->token);
$endpoint = $this->base_url('messages');
$this->post_data( $endpoint, $object_type, $action_type, json_encode($data));
}

The problem is that you have construct in your trait and maybe in your class where you are using this trait.
possible scenario:
class MyClass {
use MyTraitWithConstructor;
public function __construct(){
...
}
}
In this case trait constructor doesn't work.
What You can do?
You can rename trait construcor like this:
class MyClass {
use PropertyBaseTrait {
PropertyBaseTrait::__construct as private __prConstruct;
}
public function __construct(){
$this->__prConstruct();
...
}
}

Avoid writing constructor in traits. That's what I can say.
Instead, you can make them as normal method, then just call it in your class constructor.
Trait
trait Bar
{
public function init()
{
$this->org_id = setting('propertybase_org');
$this->token = setting('propertybase_token');
}
}
Class
class Foo
{
use Bar;
public function __construct()
{
$this->init();
}
}

Related

WordPress: Error while importing Trait inside Class

I'm using WordPress rest api, and I have created a custom theme, and I want to code using OOP. And I'm having issues importing a Trait inside a Class.
here is the code:
MyController class
<?php
namespace Controllers;
use Controllers\RespondsWithHttpStatus;
class MyController {
use RespondsWithHttpStatus;
public function __construct() {}
public function hello() {
return "hello world";
}
}
RespondsWithHttpStatus trait
<?php
namespace Controllers;
trait RespondsWithHttpStatus
{
protected function success($message, $data = [], $status = 200)
{
return array([
'success' => true,
'data' => $data,
'message' => $message,
'timestamp' => current_time( 'timestamp', 1)
], $status);
}
protected function failure($message, $status = 422)
{
return array([
'success' => false,
'message' => $message,
'timestamp' => current_time( 'timestamp', 1)
], $status);
}
}
functions.php
<?php
require_once('Controllers/MyController.php';
add_action('rest_api_init', 'greet');
function greet() {
register_rest_route('greet/v1', 'greet', array(
'methods' => WP_REST_SERVER::READABLE,
'callback' => 'greeting'
));
}
function greeting() {
$myController = new MyController();
return $myController->hello();
}
What is causing the problem is "use RespondsWithHttpStatus" field in MyController Class, I have tried to use namespaces and use keyword, but without luck.
Using require_once('RespondsWithHttpStatus.php'); in MyController.php solved the issue.

Laravel Fractal transformer, how to pass and get extra variable

I'm using Dingo API to create an API in Laravel 5.2 and have a controller returning data with
return $this->response->paginator($rows, new SymptomTransformer, ['user_id' => $user_id]);
However, I don't know how to retrieve user_id value in the SymptomTransformer! Tried many different ways and tried looking into the class but I'm relatively new to both Laravel and OOP so if anyone can point me to the right direction, it'd be greatly appreciated.
Below is my transformer class.
class SymptomTransformer extends TransformerAbstract
{
public function transform(Symptom $row)
{
// need to get user_id here
return [
'id' => $row->id,
'name' => $row->name,
'next_type' => $next,
'allow' => $allow
];
}
}
You can pass extra parameter to transformer constructor.
class SymptomTransformer extends TransformerAbstract
{
protected $extra;
public function __construct($extra) {
$this->extra = $exta;
}
public function transform(Symptom $row)
{
// need to get user_id here
dd($this->extra);
return [
'id' => $row->id,
'name' => $row->name,
'next_type' => $next,
'allow' => $allow
];
}
}
And call like
return $this->response->paginator($rows, new SymptomTransformer(['user_id' => $user_id]));
You can set extra param via setter.
class SymptomTransformer extends TransformerAbstract
{
public function transform(Symptom $row)
{
// need to get user_id here
dd($this->test_param);
return [
'id' => $row->id,
'name' => $row->name,
'next_type' => $next,
'allow' => $allow
];
}
public function setTestParam($test_param)
{
$this->test_param = $test_param;
}
}
And then:
$symptomTransformer = new SymptomTransformer;
$symptomTransformer->setTestParam('something');
return $this->response->paginator($rows, $symptomTransformer);
If you are using Dependency Injection, then you need to pass params afterwards.
This is my strategy:
<?php
namespace App\Traits;
trait TransformerParams {
private $params;
public function addParam() {
$args = func_get_args();
if(is_array($args[0]))
{
$this->params = $args[0];
} else {
$this->params[$args[0]] = $args[1];
}
}
}
Then you implement the trait in your transformer:
<?php
namespace App\Transformers;
use App\Traits\TransformerParams;
use App\User;
use League\Fractal\TransformerAbstract;
class UserTransformer extends TransformerAbstract
{
use TransformerParams;
public function transform(User $user)
{
return array_merge([
'id' => (int) $user->id,
'username' => $user->username,
'email' => $user->email,
'role' => $user->roles[0],
'image' => $user->image
], $this->params); // in real world, you'd not be using array_merge
}
}
So, in your Controller, just do this:
public function index(Request $request, UserTransformer $transformer)
{
$transformer->addParam('has_extra_param', ':D');
// ... rest of the code
}
Basically, the trait is a bag for extra params.

Passing variables in phpunit

I'm trying to pass an array i created in my testcase into my function i want to test. Is it possible to create a vairable in the testcase and pass or mock it to the class/function i want to test?
is it possible to use something like this:
$this->object = array(//array code here);
$this->testclass->attachVar->getAllObjects($this->objects);
Here is my code:
class myClassTest extends \PHPUnit_Framework_TestCase {
protected function setUp(){
$this->testclass = new \stdClass();
$this->testclass = $this->getMockBuilder('library\ixPlanta\plantChange', $this->object)
->disableOriginalConstructor()
->getMock();
}
public function testGetAllObjects() {
$this->object = array(
'testdb' => array(
'testdb_michel' => array(
'dbname' => 'testdb',
'projectName' => 'testdb',
'projectID' => 'bd993d2b9478582f6d3b73cda00bd2a',
'mainProject' => 'test',
'search' => false,
'webgroup' => array(),
'locked' => false
)
)
);
$this->testclass->expects($this->once())
->method('GetAllObjects')
->with('testdb', false, "CHECKED")
->injectTo('object', $this->object)
->will();
$result = $this->testclass->getAllObjects('testdb', false, "CHECKED");
$this->assertTrue($result);
}
In the function testGetAllObjects() i created an array that i want to pass to the function i want to test
public function getAllObjects($company,$selected=false,$selectText='CHECKED'){
$objList = array();
$i = 0;
foreach($this->Objects[$company] as $key => $value){
$objList[$i] = array('value'=> $key,'name' => $value['projectName'], 'objectID' => $value['projectID']);
$objList[$i]['checked'] = '';
if($selected !== false && !is_array($selected) && $selected === $value['dbname']){
$objList[$i]['checked'] = $selectText;
}elseif($selected !== false && is_array($selected) && in_array($value['dbname'], $selected)){
$objList[$i]['checked'] = $selectText;
}
++$i;
}
return $objList;
}
The variable i want to pass to getAllObjects is $this->objects
I think you misunderstood mock objects. The purpose of mock objects is, to create a dummy object for any other class you don't want to test. Mocking a method means, to prevent another class from calling its actual logic. Instead, it is not executed and the mock just returns whatever you gave it.
To test your actual class you just instantiate it and call its method:
class myClassTest extends \PHPUnit_Framework_TestCase
{
protected function setUp()
{
$this->testclass = new MyClass();
}
public function testGetAllObjects()
{
$this->testclass->object = array(
'testdb' => array(
'testdb_michel' => array(
'dbname' => 'testdb',
'projectName' => 'testdb',
'projectID' => 'bd993d2b9478582f6d3b73cda00bd2a',
'mainProject' => 'test',
'search' => false,
'webgroup' => array(),
'locked' => false
)
)
);
$result = $this->testclass->getAllObjects('testdb', false, "CHECKED");
$this->assertTrue($result);
}
}
Example of a mock:
Let's say your class contains some other object of the class Service which is injected through the constructor:
class MyClass {
protected $service;
public function __construct(Service $service) {
$this->service = $service;
}
public function myMethod($argument) {
$return = $this->service->callService($argument);
return $return;
}
}
And your Service object is something like this:
class Service{
public function callService($argument) {
if($argument === NULL) {
throw new \Exception("argument can't be NULL");
}
return true;
}
}
Now you could test MyClass with this method:
public function testMyClassMethod() {
$serviceMock = $this->getMockBuilder("Service")->getMock();
$serviceMock->expects($this->any())
->method("callService")
->will($this->returnValue(true));
$myClass = new MyClass($serviceMock);
$this->assertTrue($myClass->myMethod(NULL));
}
myMethod will still return true, although Service would normally throw an Exception if $argument is NULL. But because we mocked the method, it is never actually called and the mock object will return whatever we provided in ->will($this->returnValue()).

PHP magic method __invoke, empty instance variables

I'm facing a problem when calling __invoke() on an object. Is __invoke() method agnostic to instance variables? I need to call __invoke() directly on my templates due to some ZF2 injection to call $this->getView()->render(...) (otherwise getView() returns null) and I would like to have instance variables setted there. Any workaround?
See my code:
namespace Person\Person\View\Helper;
use Zend\View\Helper\AbstractHelper;
class PersonShowWidget extends AbstractHelper
{
protected $model = null;
public function __construct(array $options = null)
{
$this->parseOptions($options);
}
public function __invoke()
{
var_dump($this->model); //returns null
return $this->getView()->render('person/show/show_widget', array(
'title' => 'Cliente',
'model' => $this->model,
)
);
}
public function setOptions(array $options = null)
{
$this->parseOptions($options);
}
protected function parseOptions(array $options = null)
{
if (!is_null($options) && is_array($options)) {
if (isset($options['model'])) {
$model = $options['model'];
if (isset($model['id'])) {
$this->model['id'] = $model['id'];
} else {
throw new \Exception;
}
if (isset($model['form'])) {
$this->model['form'] = $model['form'];
} else {
throw new \Exception;
}
}
}
var_dump($this->model); //returns valid data
}
}
I do have called the constructor with some options or the setOptions method before calling __invoke().
Thanks,
You have to initialize the view helper with a factory. In this way you can make sure the constructor is called before the __invoke method is called. And no..the __invoke() method is not agnostic to instance variables.
In the Module.php
public function getViewHelperConfig()
{
return array(
'factories' => array(
'personShowWidget' => function ($helpers) {
$array = array();
$helper = new Person\Person\View\Helper\PersonShowWidget($array);
return $helper;
},
)
);
}
Or in the module.config.php
'view_helpers' => array
(
'factories' => array(
'personShowWidget' => function ($helpers) {
$array = array();
$helper = new Person\Person\View\Helper\PersonShowWidget($array);
return $helper;
},
)
)
Performance-wise you'd better make a Factory class instead of a callable.
More info: http://framework.zend.com/manual/2.0/en/modules/zend.module-manager.module-manager.html
Edit:
It seems like you using the ViewHelper wrongly. You don't have to create the instance by yourself. Just use the ViewHelper in the view. So why not just give the $options as parameter to the __invoke method?
public function __invoke(array $options = null)
{
$this->setOptions($options);
return $this->getView()->render('person/show/show_widget', array(
'title' => 'Cliente',
'model' => $this->model,
)
);
}
In the Controller pass the options array to the view:
return array(
'options' => $options,
);
And call the ViewHelper in the view:
<?php echo $this->personShowWidget($this->options); ?>
Remember: In this way you don't need a Factory to init the ViewHelper. Just add it to the invokables.
module.config.php example:
'view_helpers' => array(
'invokables' => array(
'personShowWidget' => 'Person\Person\View\Helper\PersonShowWidget',
),
),

zendframework 2 form populating MultiCheckbox values from a database

i am using zendframework 2 and doctrine 2. i want to populate the values of my MultiCheckbox from values in my database .
i got the technique from: https://github.com/doctrine/DoctrineModule/blob/master/docs/form-element.md
namespace Users\Form;
use Zend\Form\Form;
use DoctrineModule\Persistence\ObjectManagerAwareInterface;
use Doctrine\Common\Persistence\ObjectManager;
class addForm extends form implements ObjectManagerAwareInterface
{
protected $objectManager;
public function setObjectManager(ObjectManager $objectManager)
{
$this->objectManager = $objectManager;
}
public function getObjectManager()
{
return $this->objectManager;
}
public function __construct($name = null)
{
parent::__construct('add');
$this->setAttribute('method', 'post');
$this->setAttribute('enctype','multipart/formdata');
$this->add(array(
'type' => 'DoctrineModule\Form\Element\ObjectMultiCheckbox',
'name' => 'option',
'options' => array(
'label' => 'Options VĂ©hicule',
'object_manager' => $this->getObjectManager(),
'target_class' => 'Users\Entity\optionsvehicule',
'property' => 'property'
, )));
the error message i received:
No object manager was set.
I have tried and found similar error. After some search I found solution posted on https://github.com/doctrine/DoctrineModule/issues/175. Which works.
For implement you need to do some changes like that
In Module.php add method getFormElementConfig :
public function getFormElementConfig()
{
return array(
'invokables' => array(
'addForm' => 'Users\Form\addForm',
),
'initializers' => array(
'ObjectManagerInitializer' => function ($element, $formElements) {
if ($element instanceof ObjectManagerAwareInterface) {
$services = $formElements->getServiceLocator();
$entityManager = $services->get('Doctrine\ORM\EntityManager');
$element->setObjectManager($entityManager);
}
},
),
);
}
In Your Form Class addForm.php, replace constructor with init method :
namespace Users\Form;
use Zend\Form\Form;
use DoctrineModule\Persistence\ObjectManagerAwareInterface;
use Doctrine\Common\Persistence\ObjectManager;
class addForm extends form implements ObjectManagerAwareInterface
{
protected $objectManager;
public function setObjectManager(ObjectManager $objectManager)
{
$this->objectManager = $objectManager;
}
public function getObjectManager()
{
return $this->objectManager;
}
//public function __construct($name = null)
public function init()
{
$this->setAttribute('method', 'post');
$this->setAttribute('enctype','multipart/formdata');
$this->add(array(
'type' => 'DoctrineModule\Form\Element\ObjectMultiCheckbox',
'name' => 'option',
'options' => array(
'label' => 'Options VĂ©hicule',
'object_manager' => $this->getObjectManager(),
'target_class' => 'Users\Entity\optionsvehicule',
'property' => 'property'
, )));
In Your Controller Class, Call form obejct through Service Locator :
//$form = new addForm();
$forms = $this->getServiceLocator()->get('FormElementManager');
$form = $forms->get('addForm');
The $objectManager property is undefined.
This is because you call the $this->getObjectManager() method immediately within the __construct() and before you set the variable.
The form depends on the object manager; so you could just add it as a constructor argument which would ensure it is set before the class is used.
Also, the constructor should only really be used for setting up the object's initial properties and state, use init() for modifying form elements.
class addForm extends Form
{
protected $objectManager;
public function __construct(ObjectManager $objectManager)
{
parent::__construct('add-form');
$this->objectManager = $objectManager;
}
// The form element manager will call `init()`
// on the form so we can add the elements in this method
public function init() {
//....
$this->setAttribute('method', 'post');
$this->setAttribute('enctype','multipart/formdata');
// $this->add(....
// more elements added here
}
}
Last thing is to register a factory that actually does the injection
class Module {
public function getFormElementConfig() {
return array(
'factories' => array(
'ModuleName\Form\FooForm' => function($formElementManager) {
$serviceManager = $formElementManager->getServiceLocator();
$objectManager = $serviceManager->get('ObjectManager');
$form = new Form\FooForm($objectManager);
return $form;
},
),
);
}
}

Categories