wel i have simple problem
i'm trying to load this class in to my own class: https://github.com/picqer/moneybird-php-client/blob/master/src/Picqer/Financials/Moneybird/Moneybird.php
logicaly is to call it in __construct:
\Picqer\Financials\Moneybird\Moneybird $moneybird
but the problem is that it requires \Picqer\Financials\Moneybird\Connection to be established beforehand
so how can i use it in my code:
class OnepageControllerSuccessAction implements \Magento\Framework\Event\ObserverInterface
{
protected $_order;
protected $_connection;
protected $_invoiceFactory;
protected $_moneybird;
public function __construct(
\Magento\Sales\Api\Data\OrderInterface $order,
\Picqer\Financials\Moneybird\Connection $connection,
\Picqer\Financials\Moneybird\Moneybird $moneybird,
\Wemessage\Moneybird\Model\InvoiceFactory $invoiceFactory
){
$this->_order = $order;
$this->_connection = $connection;
$this->_invoiceFactory = $invoiceFactory;
$this->_moneybird = $moneybird;
}
...
public function execute(
\Magento\Framework\Event\Observer $observer
) {
$orderids = $observer->getEvent()->getOrderIds();
foreach($orderids as $orderid){
$order = $this->_order->load($orderid);
$this->_connection->setRedirectUrl('');
...
// connection has been established and now we need to pass it to the moneybird
$moneybird = $this->_moneybird($this->_connection);
which results in fault: PHP Fatal error: Uncaught Error: Function name must be a string...
wel one way to fix it, is to add method setConnection in that class and call it, but the problem that it's being downloaded from repository by composer so if i want to use my module in another installation i will have to do same steps.
any other workaround ?
added construct of moneybird file:
/**
* Moneybird constructor.
* #param \Picqer\Financials\Moneybird\Connection $connection
*/
public function __construct(Connection $connection)
{
$this->connection = $connection;
}
so it will not lead to confusions and unnecessary questions.
Related
How do I load a database container using PHP DI?
This is one of the variations I have tried up until now.
Settings.php
<?php
use MyApp\Core\Database;
use MyApp\Models\SystemUser;
return [
'Database' => new Database(),
'SystemUser' => new SystemUser()
];
init.php
$containerBuilder = new \DI\ContainerBuilder();
$containerBuilder->addDefinitions('Settings.php');
$container = $containerBuilder->build();
SystemUserDetails.php
<?php
namespace MyApp\Models\SystemUser;
use MyApp\Core\Database;
use MyApp\Core\Config;
use MyApp\Helpers\Session;
/**
*
* System User Details Class
*
*/
class SystemUserDetails
{
/*=================================
= Variables =
=================================*/
private $db;
/*===============================
= Methods =
================================*/
/**
*
* Construct
*
*/
public function __construct(Database $db)
{
# Get database instance
// $this->db = Database::getInstance();
$this->db = $db;
}
/**
Too few arguments to function MyApp\Models\SystemUser\SystemUserDetails::__construct(), 0 passed in /www/myapp/models/SystemUser.php on line 54 and exactly 1 expected
File: /www/myapp/models/SystemUser/SystemUserDetails.php
Shouldn't the database get loaded automatically?
Trace:
Currrently, My main index.php file extends init.php which is the file where it create the container (pasted code part in the post).
Then I call the App class, which fetches the URL(mysite.com/login/user_login) and instantiate a new controller class and run the mentioned method, in this case, it's the first page - MyApp/Contollers/Login.php.
The user_login method fetches the credentials, validate them, and if they are valid, uses the SystemUser object to login.
SystemUser class:
namespace MyApp\Models;
class SystemUser
{
public $id;
# #obj SystemUser profile information (fullname, email, last_login, profile picture, etc')
protected $systemUserDetatils;
public function __construct($systemUserId = NULL)
{
# Create systemUserDedatils obj
$this->systemUserDetatils = new \MyApp\Models\SystemUser\SystemUserDetails();
# If system_user passed
if ( $systemUserId ) {
# Set system user ID
$this->id = $systemUserId;
# Get SysUser data
$this->systemUserDetatils->get($this);
} else {
# Check for sysUser id in the session:
$systemUserId = $this->systemUserDetatils->getUserFromSession();
# Get user data from session
if ( $systemUserId ) {
# Set system user ID
$this->id = $systemUserId;
# Get SysUser data
$this->systemUserDetatils->get($this);
}
}
}
}
PHP-DI is working correctly.
In your SystemUser class you are doing:
$this->systemUserDetatils = new \MyApp\Models\SystemUser\SystemUserDetails();
The constructor for SystemUserDetails requires a Database object, which you are not passing.
By calling new directly, you are not using PHP-DI. By doing this you are hiding the dependency, which is exactly what you are supposedly trying to avoid if you want to use a dependency injection system.
If SystemUser depends ("needs") SystemUserDetails, the dependency should be explicit (e.g. declared in its constructor).
Furthermore: You do not need a definitions file for a system like this. And the definitions file you show in your question doesn't follow the best practices recommended by PHP-DI.
Your design is far from perfect, and I'm not sure of your end-goals, but if you did something like this, it could work:
<?php
// src/Database.php
class Database {
public function getDb() : string {
return 'veryDb';
}
}
<?php
// src/SystemUserDetails.php
class SystemUserDetails {
protected $db;
public function __construct(Database $db)
{
$this->db = $db;
}
public function getDetails() {
return "Got details using " . $this->db->getDb() . '.';
}
}
<?php
// src/SystemUser.php
class SystemUser {
protected $details;
public function __construct(SystemUserDetails $details, $userId=null) {
$this->details = $details;
}
public function getUser() {
return "Found User. " .$this->details->getDetails();
}
}
<?php
//init.php
require_once('vendor/autoload.php');
// build the container. notice I do not use a definition file.
$containerBuilder = new \DI\ContainerBuilder();
$container = $containerBuilder->build();
// get SystemUser instance from the container.
$userInstance = $container->get('SystemUser');
echo $userInstance->getUser(), "\n";
Which results in:
Found User. Got details using veryDb.
I want to connect to different database according to URL. I try to set request attribute and get that attribute in *Factory.php.
I edit autoload/pipeline.php:
<?php
$app->pipe(UrlHelperMiddleware::class);
$app->pipe(\App\Action\Choose::class);
$app->pipeDispatchMiddleware();
in Choose.php I implement process() like this:
<?php
public function process(ServerRequestInterface $request, DelegateInterface $delegate)
{
/** #var RouteResult $route */
$route = $request->getAttribute(RouteResult::class);
if ($route->getMatchedRouteName() == 'FirstRoute' or $route->getMatchedRouteName() == 'SecondRoute') {
$request = $request->withAttribute('DB_NAME', $route->getMatchedParams()['param']);
}
return $delegate->process($request);
}
The main problem is in *Factory.php I don't access to request.
Any try to access to Interop\Http\ServerMiddleware\MiddlewareInterface or Psr\Http\Message\ServerRequestInterface in *Factory.php raises same error.
Is there any way pass parameter from pipeline middleware to factory class?
If you use zend-servicemanager you can try this (just a theory, not tested):
Create 2 database factories in your config:
'db.connection.a' => DbFactoryA::class,
'db.connection.b' => DbFactoryB::class,
Then depending on the route, in Choose you load the connection you need and pass it to the container as the default connection.
$db = $container->get('db.connection.a');
$container->setService('db.connection.default', $db);
And now in all following middleware you can grab the default connection.
UPDATE:
As mentioned in the comments, this requires the container to be injected which is considered bad practice. How about you wrap the two in a common connection class and set the required from Choose:
class Connection
{
private $connection;
/**
* #var ConnectionInterface
*/
private $db_a;
/**
* #var ConnectionInterface
*/
private $db_b;
public function __construct(ConnectionInterface $a, ConnectionInterface $b)
{
$this->db_a = $a;
$this->db_b = $b;
}
public function setConnection($connection)
{
if ($connection === 'a') {
$this->connection = $this->db_a;
return;
}
$this->connection = $this->db_b;
}
public function getConnection()
{
return $this->connection;
}
}
Or you can inject only the config and create the database connection that's really needed. Store it in a property for caching (like the container does).
I am currently working in laravel 5.3. we are following this approach : controller ->service ->repository -> modal . but i do not what are we passing in the construct methods in each class.
in the below codes the flow goes like this: paycontroller -> Merchant service ->MerchantRepository->modal
the first one is paycontroller:
class PayController extends Controller
{
private $merchantService;
private $paymentService;
private $pay_request_field = array(
'orderID', 'hashKey','currencyCode','amount'
);
/**
* Create a new controller instance.
*
* #return void
*/
// public function __construct()
// {
// $this->middleware('auth');
// }
public function __construct(MerchantService $merchantService, PaymentService $paymentService){
$this->merchantService = $merchantService;
$this->paymentService = $paymentService;
}
is the constructor receiving a variable of the MerchantService and Payment service? if so where is the value coming from? im confused here
next is the MerchantService:
class MerchantService
{
private $merchantRepository;
private $merchantConfigRepository;
private $merchantPaymentRepository;
private $merchant;
private $merchantConfig;
private $merchantPayment;
public function __construct(MerchantRepository $merchantRepository, MerchantConfigRepository $merchantConfigRepository, MerchantPaymentRepository $merchantPaymentRepository){
$this->merchantRepository = $merchantRepository;
$this->merchantConfigRepository = $merchantConfigRepository;
$this->merchantPaymentRepository = $merchantPaymentRepository;
}
public function getMerchantById($id){
$this->merchant = $this->merchantRepository->getMerchantById($id);
$this->merchantConfig = $this->merchantConfigRepository->getMerchantConfig($this->merchant->mid);
return $this->merchant->toArray();
then the MerchantRepository:
class MerchantRepository
{
private $merchant;
public function __construct(Merchant $merchant){
$this->merchant = $merchant;
}
public function getMerchantByHash($hashKey="",$status='action'){
return $this->merchant->where([["hashKey","=",trim($hashKey)],["status","=",$status]])->firstOrFail();
}
public function getMerchantById($mid="",$status='action'){
return $this->merchant->where([["mid","=",trim($mid)],["status","=",$status]])->firstOrFail();
}
}
Then finally the Modal:
class Merchant extends Model
{
protected $connection = 'mysql1';
//Table Name
protected $table = 'merchants';
//Primary Key
protected $primaryKey = 'mid';
}
so whats my overall question is, what is going on in this whole process, and the constructors( parameters) where are they coming from.
Thanks in advance
In this example you are initializing the User and Database using the new keyword
Like:
$database = new Database('host', 'user', 'pass', 'dbname');
$user = new User($database);
And using the new keyword you need to manually resolve the dependency of the class you are initializing.
I have just pasted a line from here:
http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.new
An object will always be created unless the object has a constructor
defined that throws an exception on error. Classes should be defined
before instantiation (and in some cases this is a requirement)
Here for this block of code:
public function __construct(MerchantService $merchantService, PaymentService $paymentService){
$this->merchantService = $merchantService;
$this->paymentService = $paymentService;
}
You are adding it to the constructor of your Controller and you are lucky that all the dirty works are done for you by Laravel. i.e. dependency of the Controller will be automatically resolved for you by Laravel.
Laravel 5 has great dependency injection and you don't need to worry about from where the dependency is resolved.
Just have a look at this dependency Injection
http://slashnode.com/dependency-injection/
I hope you understood the differences.
class User
{
private $database = null;
public function __construct(Database $database) {
$this->database = $database;
}
public function getUsers() {
return $this->database->getAll('users');
}
}
$database = new Database('host', 'user', 'pass', 'dbname');
$user = new User($database);
$user->getUsers();
so in the above example, we are actually initiating a database object and passing it to the class's constructor. so my question is wwhere is this value of $merchant service being initiated and coming from ?
public function __construct(MerchantService $merchantService, PaymentService $paymentService){
$this->merchantService = $merchantService;
$this->paymentService = $paymentService;
}
in the above example of class, we can actually see that the $database is actually initiated outside the class...so i just dont understand where is the $merchantservice being initiated...
I have designed following class
<?php
class DB {
private static $objInstance;
/*
* Class Constructor - Create a new database connection if one doesn't exist
* Set to private so no-one can create a new instance via ' = new DB();'
*/
private function __construct() {}
/*
* Like the constructor, we make __clone private so nobody can clone the instance
*/
private function __clone() {}
/*
* Returns DB instance or create initial connection
* #param
* #return $objInstance;
*/
public static function getInstance( ) {
if(!self::$objInstance){
$ini_array = parse_ini_file("db.ini");
$dbInfo['server'] = $ini_array['server'];
$dbInfo['database'] = $ini_array['database'];
$dbInfo['username'] = $ini_array['username'];
$dbInfo['password'] = $ini_array['password'];
$dsn = 'mysql:host='.$dbInfo['server'].';dbname='.$dbInfo['database'].'';
self::$objInstance = new PDO(DB_DSN, $dbInfo['username'], $dbInfo['password']);
self::$objInstance->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
return self::$objInstance;
} # end method
/*
* Passes on any static calls to this class onto the singleton PDO instance
* #param $chrMethod, $arrArguments
* #return $mix
*/
final public static function __callStatic( $chrMethod, $arrArguments ) {
$objInstance = self::getInstance();
return call_user_func_array(array($objInstance, $chrMethod), $arrArguments);
} # end method
}
?>
My problem is when I want to perform a query I get following error:
Fatal error: Call to undefined method DB::query()
foreach(DB::query("SELECT * FROM content_type_video") as $row){
print_r($row);
}
Any ideas why and how to fix this?
$db = DB::getInstance();
foreach($db->query("SELECT * FROM content_type_video") as $row){
print_r($row);
}
The functionality you want to make use of is not available in your PHP version - you need to upgrade to at least PHP 5.3 for __callStatic.
However I suggest you to stop using singletons anyway and stop using static function calls everywhere in your code.
I'm trying to create a simple class based on my database PDO class that I can say "get this id" and it will print the info. I'm trying to do this in "qu" but get the following error: "Call to undefined method qu::get()".
There's probably a mixture of problems so any help here would be awesome. Thanks a lot!!
class db {
protected static $conn;
private function __construct(){}
public static function connect() {
if (!isset(self::$conn)) {
self::$conn = new PDO('mysql:host=localhost;dbname=database', DB_USER, DB_PASSWORD);
}
return self::$conn;
}
}
class qu {
private $db;
function quconn (&$db){
$this->db = &$db;
}
private static function getq($id){
$sql="SELECT * FROM table WHERE id=:id";
$stmt = self::quconn()->prepare($sql);
$stmt->execute(array(':id'=> $id));
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
return $result;
}
}
//$data = db::connect()->query("SELECT * FROM table")->fetchAll(); // this works
$data = qu::getq("22"); //can i use something like this? this causes the error
print_r($data);
function getq of class qu should be marked with public access modifier.
Otherwise the following row will fail as getq is a private function
$data = qu::getq("22");
Second and issue in this code
function quconn (&$db){
$this->db = &$db;
}
As you enter function quconn from a static content $this is unavailable.
Use self::$db instead.
For class qu follow the same structure of class db wich is a singleton mnagament class.
I also suggest to clarify yourself differences between $this and self, static contest etc..
Php offiacial documentation offers al lot about
Also i don't think you need passing-by-reference method:
try to rewrite the quconn function as follows:
function quconn ($db){
self::$db = $db;
}
By the way i don't thing the class qu is well "engineered"
Even if you correct the passing-by-reference-problem this instruction won't work:
$stmt = self::quconn()->prepare($sql);
You are invoking the prepare function on the result of the invocation to quconn, which doesn't return anything...
I suggest:
$stmt = db::connect()->prepare($sql);
this get the PDP instance and call the prapare method....