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.
Related
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();
}
}
I am using Laravel 5.5.40 along with the Zizaco\Entrust Pacakge
In my routes/web.php file i have the following route setup.
Route::group(['prefix' => 'order'], function() {
Route::get('', 'OrderController#getMe');
});
It is supposed to call the getMe() method inside the OrderController.php but it instead redirects to www.mydomain.co.uk/home
namespace App\Http\Controllers;
class OrderController extends Controller
{
public function getMe() {
return "You got me!";
}
}
As a test, I added a __construct function to the OrderController.php to see if the class was even been loaded.
public function __construct() {
dd("Testing");
}
When accessing www.mydomain.co.uk/order i now get
"Testing"
I can't seem to work out why it is not running the getMe() method. Could anyone possibly shine some light on this please?
I have also tried changing the route to use ClientController#list which works fine.
Contents of ClientController.php
namespace App\Http\Controllers;
use App\Client;
class ClientController extends Controller
{
public function __construct() {
//
}
// Display all the clients
public function list() {
$tabContent = [
'display_type' => 'list',
'data' => Client::orderBy('name', 'asc')->get(),
'view_params' => [
'columns' => [
'name' => 'Client Name',
'address_line_1' => 'Address Line 1',
'town' => 'Town',
'county' => 'County',
'post_code' => 'Post Code'
],
'links' => 'client',
'controls' => True
]
];
return view('tables.list', ['data' => $tabContent]);
}
}
It has become apparent that if the controller does not have the constructor function in it, it will automatically redirect to the root of the URI with no error.
public function __construct() {
//
}
I am getting null when using $sm=$this->getServiceLocator() as a result $sm->get("XXXXXXXXXXX") throwing a Fatal error: Call to a member function get() on null.
What i am doing is that, while receiving user data in controller i am calling another controller validatorController inside my requested controller which is signupController and in validatorController i am using $sm=$this->getServiceLocator() which gives the above error
Here is my work
Error comes when i use $check=$this->_getUserTable()->isUnique($email); in ValidatorController.php but not in SignupController.php
Module.php
<?php
namespace User;
use Zend\Db\TableGateway\TableGateway;
use Zend\Db\ResultSet\ResultSet;
use User\Controller\ValidatorController;
use User\Model\User;
use User\Model\UserTable;
class Module {
public function getConfig() {
return include __DIR__."/config/module.config.php";
}
public function getAutoloaderConfig() {
return array(
"Zend\loader\StandardAutoloader"=>array(
"namespaces"=>array(
__NAMESPACE__=>__DIR__."/src/".__NAMESPACE__
)
)
);
}
public function getServiceConfig() {
return array(
"factories"=>array(
'User\ValidatorController' => function ($sm) {
$validatorController = new ValidatorController();
return $validatorController;
},
"User\Model\UserTable"=>function($sm) {
$tableGateway=$sm->get("UserTableGateway");
$table=new UserTable($tableGateway);
return $table;
},
"UserTableGateway"=>function($sm) {
$dbAdapter=$sm->get("Zend\Db\Adapter\Adapter");
$resultSetPrototype=new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new User());
return new TableGateway("users",$dbAdapter,null,$resultSetPrototype);
}
)
);
}
}
module.config.php
<?php
return array(
"controllers"=>array(
"invokables"=>array(
"User\Controller\User"=>"User\Controller\UserController",
'User\Controller\Signup' => 'User\Controller\SignupController',
'User\Controller\Validator' => 'User\Controller\ValidatorController'
)
),
// The following section is new and should be added to your file
"router"=>array(
"routes"=>array(
"user"=>array(
"type"=>"segment",
"options"=>array(
"route" => "/user[/:action][/:id]",
"constraints" => array(
"id" => "[0-9]+",
),
"defaults"=>array(
"controller"=>"User\Controller\User"
)
)
),
'signup' => array(
'type' => 'segment',
'options' => array(
'route' => '/signup',
'defaults' => array(
'controller' => 'User\Controller\Signup',
)
)
),
)
),
'view_manager' => array(//Add this config
'strategies' => array(
'ViewJsonStrategy',
),
),
);
SignupController.php
<?php
namespace User\Controller;
use Zend\Mvc\Controller\AbstractRestfulController;
use Zend\View\Model\JsonModel;
class SignupController extends AbstractRestfulController{
private $_userTable;
public function create($data) {
/*
* The above error is not coming here
* $check=$this->_getUserTable()->isUnique($data['email']);
*
* But inside the below controller
*/
// Calling a validatorContoller
$validator=$this->getServiceLocator()->get('User\ValidatorController');
$response=$validator->validateEmail($data['email']);
return new JsonModel($response);
}
public function _getUserTable() {
if(!$this->_userTable) {
$sm=$this->getServiceLocator();
$this->_userTable=$sm->get("User\Model\UserTable");
}
return $this->_userTable;
}
}
ValidatorController.php
<?php
namespace User\Controller;
use Zend\Mvc\Controller\AbstractRestfulController;
use Zend\Validator\EmailAddress;
class ValidatorController extends AbstractRestfulController {
private $_userTable;
public function validateEmail($email) {
$validator = new EmailAddress();
if($validator->isValid($email)) {
// check if it is a unique entry in user table
// ***(THE SOURCE OF ERROR IS HERE)***
$check=$this->_getUserTable()->isUnique($email);
return $check;
}
}
public function _getUserTable() {
if(!$this->_userTable) {
$sm=$this->getServiceLocator();
$this->_userTable=$sm->get("User\Model\UserTable");
}
return $this->_userTable;
}
}
NOTE
Error comes when i use $check=$this->_getUserTable()->isUnique($email); in ValidatorController.php but not in SignupController.php
Thankyou
getServiceLocator() is deprecated in ZendFramework 2. You must inject _userTable in your ValidatorController from your Module.php like this :
class Module {
...
public function getServiceConfig() {
return array(
"factories"=>array(
'User\ValidatorController' => function ($sm) {
$userTable = $sm->get("User\Model\UserTable");
$validatorController = new ValidatorController();
$validatorController->setUserTable($userTable);
return $validatorController;
},
...
}
Then add a setUserTable() method in your ValidController and modify the getUserTable() method :
class ValidController {
public function setUserTable($suerTable) {
$this->_suerTable = $userTable
}
public function _getUserTable() {
return $this->_userTable;
}
}
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.
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',
),
),