How to call a function from one module to another Magento 2 - magento2

I try to call a function from a module A to a module B
here is the module A code
namespace A\Epayment\Model;
class Etransactions
{
public function customPayment{
return "test";
}
and module b code
namespace B\Payment\Controller\Index;
class Payment extends \Magento\Framework\App\Action\Action
{
protected $_pageFactory;
protected $_transaction;
public function __construct(
\Magento\Framework\App\Action\Context $context,
\Magento\Framework\View\Result\PageFactory $pageFactory,
\ETransactions\Epayment\Model\Etransactions $transaction
)
{
$this->_pageFactory = $pageFactory;
$this->_transaction = $transaction;
parent::__construct($context);
}
public function execute()
{
echo "Hello World".PHP_EOL;
$foo="a";
echo $foo;
echo $this->_transaction->customPayment();
//echo $this->customPayment();
echo $foo;
exit;
}
}
this code return the "hello world", the first $foo, not the second and doesn't display any error
can someone explain me where is my error ?
EDIT: i didn't change anything but it works fine now.
thanks for the answers anyway

The object you want create the path your are injecting is incorrect.
public function __construct(
\Magento\Framework\App\Action\Context $context,
\Magento\Framework\View\Result\PageFactory $pageFactory,
\A\Epayment\Model\Etransactions $transaction // changes are here
)
{
$this->_pageFactory = $pageFactory;
$this->_transaction = $transaction;
parent::__construct($context);
}
Kindly use exception handling.
try{
$this->_transaction->customPayment();
}catch(Exception $e){
//log your exception here.
}

In Magento, Helper classes are available to use anywhere (Block, Controller, Model, Observer, View). So you should create a method in helper class and call it anywhere by the following way.
Declar the helper class and method: ModuleA\Epayment\Helper\Data.
<?php
namespace ModuleA\Epayment\Helper;
class Data extends \Magento\Framework\App\Helper\AbstractHelper
{
public function yourHelperMethod()
{
# code...
}
}
Call the method:
$helper = $this->_objectManager->create(ModuleA\Epayment\Helper\Data::class);
$helper->yourHelperMethod();
Note: If the object manager is not injected in your class. Please follow the steps below:
1) declare private property:
private $_objectManager;
2) inject in the constructor to initialize:
public function __construct(
\Magento\Framework\ObjectManagerInterface $objectmanager
) {
$this->_objectManager = $objectmanager;
}
3) use in some method:
public function someMethod() {
$helper = $this->_objectManager->create(ModuleA\Epayment\Helper\Data::class);
$helper->yourHelperMethod();
}

Related

Get Breadcrumb Path in Custom controller Magento 2

I am trying to get breadcrumb path in my controller by using this helper
public function __construct(\Magento\Catalog\Helper\Data $catalogData, ) {
$this->catalogData = $catalogData;
}
$path = $this->catalogData->getBreadcrumbPath();
When I print $path it's giving me an empty array. But when I get this helper function in any product phtml file like this
$helper = $this->helper('\Magento\Catalog\Helper\Data');
$values = $helper->getBreadcrumbPath();
it's giving me the full path in phtml. How can I access this function in my controller as well?
You will get breadcrumbpath in your custom controller by doing this:
namespace Vendor\ModuleName\Controller\Index;
Class ControllerClass extends \Magento\Framework\App\Action\Action{
protected $catalogData;
protected $_pageFactory;
public function __construct(
\Magento\Framework\App\Action\Context $context,
\Magento\Catalog\Helper\Data $catalogData,
\Magento\Framework\View\Result\PageFactory $pageFactory)
{
$this->catalogData = $catalogData;
$this->_pageFactory = $pageFactory;
return parent::__construct($context);
}
public function execute()
{
$path = $this->catalogData->getBreadcrumbPath();
print_r($path);
return $this->_pageFactory->create();
}
}

ZF3: ServiceNotFoundException while creating a class with Abstract Factory registered in ServiceManager

I got problem with the Abstract Factories example.
I get ServiceNotFoundException while creating a class with Abstract Factory registered in the ServiceManager.
First I download zend-servicemanager with composer
composer require zendframework/zend-servicemanager
Then I run the ServiceManager example in the single file (for simplicity).
<?php
require_once 'vendor/autoload.php';
use Interop\Container\ContainerInterface;
use Zend\ServiceManager\ServiceManager;
use Zend\ServiceManager\Factory\InvokableFactory;
use Zend\ServiceManager\Factory\FactoryInterface;
use Zend\ServiceManager\Factory\AbstractFactoryInterface;
Class that should be obtained with ServiceManager.
class A
{
public $text;
public function __construct()
{
$this->text = "Default text";
}
}
I use MyAbstractFactory from documentation.
class MyAbstractFactory implements AbstractFactoryInterface
{
public function canCreate(ContainerInterface $container, $requestedName)
{
return in_array('Traversable', class_implements($requestedName), true);
}
public function __invoke(ContainerInterface $container,
$requestedName,
array $options = null)
{
return $requestedName();
}
}
I create ServiceManager with registered Abstract Factory.
$serviceManager = new ServiceManager([
// Neither works
//'abstract_factories' => array('MyAbstractFactory')
'abstract_factories' => array( new MyAbstractFactory() )
//'abstract_factories' => array( MyAbstractFactory::class )
/*
'abstract_factories' => [
MyAbstractFactory::class => new MyAbstractFactory()
]
*/
]);
Finally I try to obtain the instance of class A.
$a = $serviceManager->get(A::class);
var_dump($a);
I get
Fatal error: Uncaught Zend\ServiceManager\Exception\ServiceNotFoundException: Unable to resolve service "A" to a factory; are you certain you provided it during configuration?
with the stack trace
.\vendor\zendframework\zend-servicemanager\src\ServiceManager.php(763): Zend\ServiceManager\ServiceManager->getFactory('A') #1
.\vendor\zendframework\zend-servicemanager\src\ServiceManager.php(200): Zend\ServiceManager\ServiceManager->doCreate('A') #2
.\script.php(53): Zend\ServiceManager\ServiceManager->get('A') #3
My formulation of the problem was wrong. #rkeet's comment made it clear.
As my objective was the working example of the Abstract Factory registration within ServiceManager, I post the single-file script where canCreate() is simplified just to check if the class exists.
<?php
// composer require zendframework/zend-servicemanager
require_once 'vendor/autoload.php';
use Interop\Container\ContainerInterface;
use Zend\ServiceManager\ServiceManager;
use Zend\ServiceManager\Factory\AbstractFactoryInterface;
class A
{
public $text;
public function __construct()
{
$this->text = "Default text";
}
}
class MyAbstractFactory implements AbstractFactoryInterface
{
public function canCreate(ContainerInterface $container, $requestedName)
{
return class_exists($requestedName);
}
public function __invoke(ContainerInterface $container,
$requestedName,
array $options = null)
{
return new $requestedName();
}
}
$serviceManager = new ServiceManager([
//'abstract_factories' => array('MyAbstractFactory') // works
//'abstract_factories' => array( new MyAbstractFactory() ) // works
'abstract_factories' => array( MyAbstractFactory::class ) // also works
]);
try {
$a = $serviceManager->get(A::class);
var_dump($a);
echo "<br/>\n";
$b = $serviceManager->get(B::class);
var_dump($b);
} catch (Exception $e) {
echo $e->getMessage() . "<br/>\n";
echo "{$e->getFile()} ({$e->getLine()})";
}
?>
As #rkeet pointed, if someone needs the original example working, class A should implement Traversable.

Symfony3: Service not able to get arguments

I have made a service to get Doctrine connection in my models (Not sure if it is a nice approach but I dont want to pass connection from controller to model constructor each time).
So lets say I want products in my controller
public function getProductsAction(Request $request) {
$product_model = new ProductModel();
return $product_model->getProducts();
}
I have Product model Which will access a helper to get "database_connection"
use AppBundle\Helper\ContainerHelper;
class ProductModel {
function getProducts() {
$helper = new ContainerHelper();
$db = $helper->getDoctrine();
$query = "SELECT * FROM customer_products;";
$statement = $db->prepare($query);
$statement->execute();
$result = $statement->fetchAll(PDO::FETCH_ASSOC);
return $result;
}
}
Now this helper is defined in src/AppBundle/Helper/ContainerHelper.php
namespace AppBundle\Helper;
use Symfony\Component\DependencyInjection\ContainerInterface as Container;
class ContainerHelper {
private $container;
public function __construct(Container $container) {
$this->container = $container;
}
public static function getDoctrine() {
$database_connection = $this->container->get('database_connection');
return $database_connection;
}
}
Lets say this service needs "service container" so in app/config/services.yml
services:
app.container_helper:
class: AppBundle\Helper\ContainerHelper
arguments: ['#service_container']
But it gives me error:
Catchable Fatal Error: Argument 1 passed to
AppBundle\Helper\ContainerHelper::__construct() must implement
interface Symfony\Component\DependencyInjection\ContainerInterface,
none given, called in \src\AppBundle\Model\ProductModel.php
on line 148 and defined
While I believe that I have implemented it correctly according to http://symfony.com/doc/current/book/service_container.html and http://anjanasilva.com/blog/injecting-services-in-symfony-2/, its certain that I have missed something or just got the whole bad idea. I need to know if it is a correct concept or what I have missed
While #pavlovich is trying to fix your existing code, I really think you are making this much more convoluted than it has to be. ProductModel itself should be a service with your database connection injected into it.
class ProductModel {
public function __construct($conn) {
$this->conn = $conn;
}
public function getProducts() {
$stmt = $this->conn->executeQuery('SELECT * FROM customer_products');
return $stmt->fetchAll();
}
services:
product_model:
class: AppBundle\...\ProductModel
arguments: ['#database_connection']
// controller.php
$productModel = $this->get('product_model'); // Pull from container
$products = $productModel->getProducts();
Rather than using helpers, I'd recommend using constructor injection and autowiring. It's more safe, future proof and easier to extend and test.
In such case, you'd have to create ProductRepository (more common and standard name for ProductModel) and pass it to controller.
1. Controller
<?php
class SomeController
{
/**
* #var ProductRepository
*/
private $productRepository;
public function __construct(ProductRepository $productRepository)
{
$this->productRepository = $productRepository;
}
public function getProductsAction()
{
return $this->productRepository->getProducts();
}
}
If you have difficulties to register controller as a service, just use Symplify\ControllerAutowire bundle.
2. ProductRepository
// src/AppBundle/Repository/ProductRepository.php
namespace AppBundle\Repository;
class ProductRepository
{
/**
* #var Doctrine\DBAL\Connection
*/
private $connection;
public function __construct(Doctrine\DBAL\Connection $connection)
{
$this->connection = $connection;
}
public function fetchAll()
{
$query = "SELECT * FROM customer_products;";
$statement = $this->connection->prepare($query);
$statement->execute();
return $statement->fetchAll(PDO::FETCH_ASSOC);
}
}
3. Service registration
# app/cofig/servies.yml
services:
product_repository:
class: AppBundle\Repository\ProductRepository
autowire: true
For more you can see similar question with answer here: Symfony 3 - Outsourcing Controller Code into Service Layer
With new version of Symfony 3.3, a new feature is added (Auto-wired Services Dependencies)
https://symfony.com/doc/current/service_container/autowiring.html
https://symfony.com/doc/current/service_container/3.3-di-changes.html
Using this feature, I solved this issue in following way:
Added a new directory /src/AppBundle/Model
Added my model classes in this directory
namespace AppBundle\Modal;
use Doctrine\ORM\EntityManagerInterface;
class ProductModal
{
private $em;
// We need to inject this variables later.
public function __construct(EntityManagerInterface $entityManager)
{
$this->em = $entityManager;
}
// We need to inject this variables later.
public function getProducts()
{
$statement = $this->em->getConnection()->prepare("SELECT * FROM product WHERE 1");
$statement->execute();
$results = $statement->fetchAll();
return $results;
}
}
Added in my app/config/services.yml
AppBundle\Modal\:
resource: '../../src/AppBundle/Modal/*'
public: true
In my controller I can use it like
$products = $this->get(ProductModal::class)->getProducts();
P.S. Dont forget to add use AppBundle\Entity\Product\Product; in controller

need to test functionality with oracle stored proc

i have code like this:
protected function _checkUserVisibility()
{
try {
if (!$params->getUsrParametr(self::ACTIVE_FIF)) { // calling oracle stored proc
throw new Unitex_Exception('ALARM');
}
}
catch (Exception $e) {
$this->logOut();
throw $e;
}
}
this func caled from another one (and so on).
a a question:
how to get worked unit test for that parts of code?
EDIT1:
firstly taked hehe http://framework.zend.com/manual/1.12/en/zend.test.phpunit.html
than improoved (hope)
test proc is:
class UserControllerTest extends Zend_Test_PHPUnit_ControllerTestCase {
..........
public function testLoginAction()
{
$request = $this->getRequest();
$request->setMethod('POST')
->setHeader('X_REQUESTED_WITH', 'XMLHttpRequest')
->setPost(array(
'user' => 'test_user',
'password' => 'test_pwd',
));
$filialId = 1;
$stmt1 = Zend_Test_DbStatement::createUpdateStatement();
$this->getAdapter()->appendStatementToStack($stmt1);
$this->getAdapter()->appendStatementToStack($stmt1);
$this->getAdapter()->appendStatementToStack($stmt1);
$this->getAdapter()->appendStatementToStack($stmt1);
$stmt1Rows = array(array('IRL_ALIAS' => 'RO_COMMON', 'ISADM' => 'N'));
$stmt1 = Zend_Test_DbStatement::createSelectStatement($stmt1Rows);
$this->getAdapter()->appendStatementToStack($stmt1);
$this->dispatch('/user/login');// <-- crash here
$this->assertController('user');
$this->assertAction('login');
$this->assertNotRedirect();
$this->_getResponseJson();
}
In your unit test definitly you don't want any database interaction. The answer for your question is use stub for db functionality.
Let say that $params is property of SomeClass contains getUsrParametr which for example gets something from database. You're testing _checkUserVisibility method so you don't care about what are happening in SomeClass. That's way you test will look something like that:
class YourClass
{
protected $params;
public function __construct(SomeClass $params)
{
$this->params = $params;
}
public function doSomething()
{
$this->_checkUserVisibility();
}
protected function _checkUserVisibility()
{
try {
if (!$this->params->getUsrParametr(self::ACTIVE_FIF)) { // calling oracle stored proc
throw new Unitex_Exception('ALARM');
}
}
catch (Exception $e) {
$this->logOut();
throw $e;
}
}
}
And the unit test of course the only method you test is the public one, but you cover protected method through testing public one.
public function testDoSomethingAlarm()
{
// set expected exception:
$this->setExpectedException('Unitex_Exception', 'ALARM');
// create the stub
$params = $this->getMock('SomeClass', array('getUsrParametr'));
// and set desired result
$params->expects($this->any())
->method('getUsrParametr')
->will($this->returnValue(false));
$yourClass = new YourClass($params);
$yourClass->doSomething();
}
And the second test which test case if getUsrParametr will returns true:
public function testDoSomethingLogout()
{
// set expected exception:
$this->setExpectedException('SomeOtherException');
// create the stub
$params = $this->getMock('SomeClass', array('getUsrParametr'));
// set throw desired exception to test logout
$params->expects($this->any())
->method('getUsrParametr')
->will($this->throwException('SomeOtherException'));
// now you want create mock instead of real object beacuse you want check if your class will call logout method:
$yourClass = $this->getMockBuilder('YourClass')
->setMethods(array('logOut'))
->setConstructorArgs(array($params))
->getMock();
// now you want ensure that logOut will be called
$yourClass->expects($this->once())
->method('logOut');
// pay attention that you've mocked only logOut method, so doSomething is real one
$yourClass->doSomething();
}
If you're using PHP 5.3.2+ with PHPUnit, you can test your private and protected methods by using reflection to set them to be public prior to running your tests, otherwise you test protected/private methods by properly testing the public methods that use the protected/private methods. Generally speaking the later of the two options is generally how you should do it, but if you want to use reflection, here's a generic example:
protected static function getMethod($name) {
$class = new ReflectionClass('MyClass');
$method = $class->getMethod($name);
$method->setAccessible(true);
return $method;
}
public function testFoo() {
$foo = self::getMethod('foo');
$obj = new MyClass();
$foo->invokeArgs($obj, array(...));
...
}

Zend frame work Custom view helper error

Hi am trying to add custom helper throughout my application
Have done following steps
index.php
$view = new Zend_View();
$view->addHelperPath('My/View/Helper', 'My_View_Helper');
Zend_Controller_Action_HelperBroker::addHelper($viewRenderer);
Helper class in My/View/Helper
class My_View_Helper_Common extends Zend_View_Helper_Abstract
{
public function example()
{
return "ok";
}
}
now calling in view index.phtml
$this->example()
am getting this error
Uncaught exception 'Zend_View_Exception' with message 'script 'error/error.phtml' not found in path (.\application\views\scripts\)' in C:\xampp\htdocs\wyfixture\library\Zend\View\Abstract.php:924
Stack trace:
#0 C:\xampp\htdocs\wyfixture\library\Zend\View\Abstract.php(827): Zend_View_Abstract->_script('error/error.pht...')
#1 C:\xampp\htdocs\wyfixture\library\Zend\Controller\Action\Helper\ViewRenderer.php(903): Zend_View_Abstract->render('error/error.pht...')
#2 C:\xampp\htdocs\wyfixture\library\Zend\Controller\Action\Helper\ViewRenderer.php(924): Zend_Controller_Action_Helper_ViewRenderer->renderScript('error/error.pht...', NULL)
#3 C:\xampp\htdocs\wyfixture\library\Zend\Controller\Action\Helper\ViewRenderer.php(963): Zend_Controller_Action_Helper_ViewRenderer->render()
#4 C:\xampp\htdocs\wyfixture\library\Zend\Controller\Action\HelperBroker.php(277): Zend_Controller_Action_Helper_ViewRenderer->postDispatch()
#5 C:\xampp\htdocs\wyfixture\library\Zend\Controller\Action.php(523):
please help me
In addition to Vikas answer.
To call more than one method in a view helper you can use code like this:
In My/View/Helper/Example.php
class My_View_Helper_Example extends Zend_View_Helper_Abstract
{
public function example()
{
return $this;
}
public function foo()
{
return 'foo';
}
public function bar()
{
return 'bar';
}
public function __toString()
{
return $this->foo();
}
}
In you views:
echo $this->example()->foo() // prints foo
echo $this->example()->bar() // prints bar
echo $this->example() // prints foo
Seems like you have two problems here:
Your 'application/views/scripts/error/error.phtml' is missing. You can restore it and you'll get more accurate exception message at once.
Your helper class should contain a method named after the helper.
So, in your case it's file My/View/Helper/Example.php with the following body
class My_View_Helper_Example extends Zend_View_Helper_Abstract {
public function example() {...}
}
Then you'll be able to call it from the view with
$this->example()