Call method from (custom) controller class in Magento - magento

I'm working with the M2e extension for Magento. Now I want to call a method of the class Ess_M2ePro_Adminhtml_ListingController in the file app/code/community/Ess/M2ePro/controllers/Adminhtml/ListingController.php.
But I don't know, how. I can't create an object or model to get access to the class to use the methods. Maybe it's not a good idea to call this controller methods directly, but in my case (remove a associated magento product to an ebay listing) it's required to call this methods.
In general these actions are called from the magento backend. I've also tried to create an admin_html session, but at the moment I don't have any further ideas.
Here's an example, how it looks like. I'm working with regular PHP-code, nothing special:
class Ess_M2ePro_Adminhtml_ListingController extends Ess_M2ePro_Controller_Adminhtml_MainController
{
//#############################################
protected function _initAction()
{
/** removed **/
}
protected function _isAllowed()
{
return Mage::getSingleton('admin/session')->isAllowed('m2epro/listings/listing');
}
//#############################################
public function indexAction()
{
/** removed **/
}
//#############################################
public function searchAction()
{
/** removed **/
}
public function searchGridAction()
{
/** removed **/
}
public function lockListingNowAction()
{
$listingId = (int)$this->getRequest()->getParam('id');
$component = $this->getRequest()->getParam('component');
$lockItemParams = array(
'id' => $listingId,
'component' => $component
);
$lockItem = Mage::getModel('M2ePro/Listing_LockItem',$lockItemParams);
if (!$lockItem->isExist()) {
$lockItem->create();
}
exit();
}
}
And I'm looking for something like this:
$test = Mage::getModel('M2ePro/Ess_M2ePro_Adminhtml_ListingController')->lockListingNowAction();

You shouldn't call methods from an other controller. Specially in your case, when you have exit at the end of the method.
You can use the _forward method if you are in a controller:
$this->_forward($action = 'lockListingNowAction', $controller = 'adminhtml_listing', $module = 'M2ePro', $params = array('id'=>$id)) //controller name may be different
But the cleanest way is to have the code you need in a helper and call the code from that helper in both controllers.

Related

Magento 2 orderFactory not found in vendor directory

I am using Magento 2.3.4 inside a docker container for a payment gateway extension. First things first, here is the affected code:
<?php
namespace Magento\PGM\Block;
use Magento\AdminNotification\Model\Inbox;
use Magento\Checkout\Model\Session;
use Magento\Framework\App\ObjectManager;
use Magento\Framework\App\Response\Http;
use Magento\Framework\View\Element\Template;
use Magento\Framework\View\Element\Template\Context;
use Magento\Sales\Api\Data\OrderAddressInterface;
use Magento\Sales\Model\Order\Payment\Transaction;
use Magento\Sales\Model\Order\Payment\Transaction\Builder as TransactionBuilder;
use Magento\Sales\Model\OrderFactory;
use Magento\Store\Model\ScopeInterface;
use Magento\PGM\Logger\Logger;
class Main extends Template
{
protected $_objectmanager;
protected $checkoutSession;
protected $urlBuilder;
protected $response;
protected $config;
protected $messageManager;
protected $transactionBuilder;
protected $inbox;
private $logger;
private $orderFactory;
public function __construct(Context $context, Session $checkoutSession, OrderFactory $orderFactory = null, Logger $logger, Http $response, TransactionBuilder $tb, Inbox $inbox)
{
$this->checkoutSession = $checkoutSession;
$this->orderFactory = $orderFactory ?: ObjectManager::getInstance()->get(OrderFactory::class);
$this->response = $response;
$this->config = $context->getScopeConfig();
$this->transactionBuilder = $tb;
$this->logger = $logger;
$this->inbox = $inbox;
$this->urlBuilder = ObjectManager::getInstance()
->get('Magento\Framework\UrlInterface');
parent::__construct($context);
}
public function getParentId()
{
return $this->getData(OrderAddressInterface::PARENT_ID);
}
protected function _prepareLayout()
{
$method_data = array();
$order = $this->orderFactory->create()->load($this->getParentId());
if ($order) {
$payment = $order->getPayment();
// The error is thrown here (" Call to a member function setTransactionId() on null")
$payment->setTransactionId("-1");
...
$payment->save();
$order->save();
...
}
private function setApiData($order, $testmode, $instance)
{
...
}
}
I am getting this error:
Call to a member function setTransactionId() on null
I think that this is just a symptom though. The order object is not created, my IDE marks the $order->getPayment() method as not found at all.
The code itself should not be the problem, but the folder 'Sales\Model' does not contain an orderFactory.php file. Is the file missing or deprecated? Several modules use this file and create orders like this, for example the Paypal PGM, and use the OrderFactory.php file.
As i know The Factory class name is the name of Model class and append with the Factory word. So for our example, we will have TopicFactory class. You must not create this class. Magento will create it for you. Whenever Magento’s object manager encounters a class name that ends in the word ‘Factory’, it will automatically generate the Factory class in the var/generation folder if the class does not already exist. You will see the factory class in
ROOT/generated/code/<vendor_name>/<module_name>/Model/OrderFactory.php
So the first step you should go to the folder Generation to see the class is there or NOT.
If it's not there, i think you're are facing permission issue , magento cant generate (can't create file or folder) the Factory Class in Generation folder.
Hi orderFactory does not have payment in DB, so you cannot use this to get payment. You can try this:
use Magento\Sales\Model\ResourceModel\Order\Payment\Transaction\CollectionFactory;
protected $transactions;
public function __constructor(CollectionFactory $transactions)
{
$this->transactions = $transactions;
}
In your method:
$transactions = $this->transactions->create()->addOrderIdFilter($orderId);
...
$transactions->setTransactionId("-1");`

Laravel Model Controller Dependency injection

I have the following problem. I hope my approach is not completely wrong, feel free to advice.
I have a Model class Chat.php
protected $skip;
protected $take;
protected $agreements;
protected $chat;
public function getSkip()
{
return $this->skip;
}
public function setSkip($skip)
{
$this->skip = $skip;
}
public function getTake()
{
return $this->take;
}
public function setTake($take)
{
$this->take = $take;
}
public function __construct(array $attributes = array())
{
parent::__construct($attributes);
$this->setTake(8);
$this->setSkip(8);
}
I set properties skip and take here.
Then, I have the DashboardController
class DashboardController extends Controller
{
private $chat;
/**
* DashboardController constructor.
* #param $chat
*/
public function __construct(Chat $chat)
{
$this->chat = $chat;
}
/**
* Display a listing of the authenticated resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
$chats = Chat::orderBy('created_at','desc')->skip($this->chat->getSkip())->take($this->chat->getTake())->get();
$agreements = AgrType::orderBy('created_at','desc')->take(10)->get();
return view('sections.dashboard', compact('chats','agreements'));
}
public function loadMore()
{
$this->chat->setSkip($this->chat->getSkip() - 1 );
$this->chat->setTake($this->chat->getTake() - 1);
return redirect('/dashboard');
}
My approach is as follows:
After a user clicks on button, route /loadmore get him to this controller and triggers loadMore function.
LoadMore function then gets values through accessors and sets values with mutator.
Index method then simply reads this values.
So the meaning is: I show chat window (rather maybe comments window cause this si not really a chat), index method is called.
Index method reads the values and displays comments according to query. -> this one is OK
Now, what does NOT work:
When I click button, loadMore function gets called, sets the values which index method then reads and reloads according to them.
What did I try: I tried loadMore method to display its own values (changed) and return them, but then I have a new route for reloaded chat and it is not what I want.
What do I miss? Is my approach OK? (I know javascript is maybe better for this, but I want a Laravel way, get and post.)
Thanks in advance.
Your controller functions get executed within in completely separate requests.
All return redirect('/dashboard'); does in loadMore() send your browser to the dashboard route. Your browser then makes a new request to index() on which your controller gets instantiated again, its __construct() function run again and a new empty Chat model gets instantiated.
I recommend you put the take and skip parameters into your url like this:
$router->get('/dashboard/{skip}/{take}', 'DashboardController#index');
And change your index() function to this:
public function index($skip, $take)
That way it will work, however the even better way of doing it would be to use Laravel's paginate() function: https://laravel.com/docs/5.6/pagination
public function index()
{
$chats = Chat::orderBy('created_at','desc')->paginate();
$agreements = AgrType::orderBy('created_at','desc')->take(10)->get();
return view('sections.dashboard', compact('chats','agreements'));
}

Laravel, Singleton - how to send data to all controllers?

I'm doing shopping site. I made Cart Model, which is Singleton. My shopping cart exists in session always ( no matter or User is login or not ). Now I have to invoke every time in every Controllers and actions getInstance to check or there's key "cart".
Is there a possibility to do this automaticly for all views?
Here is code of my Singleton:
class Cart
{
private $cartModel;
private static $instance;
private function __construct()
{
$this->cartModel = new CartModel();
$cart = Session::get('cart');
if ($cart == null) {
Session::put('cart', array());
}
}
private function __clone()
{
}
public static function getInstance()
{
if (self::$instance === null) {
self::$instance = new Cart();
}
return self::$instance;
}
public function get(){
return Session::get('cart');
}
}
And here for example how it looks in Controllers and actions:
class StoreController extends Controller
{
public function mainSite()
{
$cart=Cart::getInstance()->get();
return View('zoo');
}
public function showCategory($categoryName)
{
$cart=Cart::getInstance()->get();
$category = new Category();
$categoryId = (int)$category->getCategoryId($categoryName);
$subCategories = Subcategory::where('category_id', $categoryId)->get();
return View('zoo-category', ['subCategories' => $subCategories, 'categoryName' => $categoryName]);
}
public function showSubcategory()
{
$cart=Cart::getInstance()->get();
}
I have to do this all the time: $cart=Cart::getInstance()->get();
Is there a possibility to do this only one time?
You can take advantage of Laravel's dependency injection. Bind your class to the IoC container and you can either access it through the IoC container or you can have Laravel automatically inject this into your controllers in several different ways.
Read more here: https://laravel.com/docs/5.4/container
Add it to base controller's constructor so that it gets called on every controller method.
// app/Http/Controllers/Controller.php
protected $cart;
public function __construct()
{
$this-> cart = Cart::getInstance()->get();
}
But i honestly see no point in your singleton class. All it does is set the cart with an empty array when it's not defined. Also $this->cartModel = new CartModel(); is this ever used?

Laravel 4: Reference controller object inside filter

I have a controller in Laravel 4, with a custom variable declared within it.
class SampleController extends BaseController{
public $customVariable;
}
Two questions: Is there any way I can call within a route filter:
The controller object where the filter is running at.
The custom variable from that specific controller ($customVariable).
Thanks in advance!
as per this post:
http://forums.laravel.io/viewtopic.php?pid=47380#p47380
You can only pass parameters to filters as strings.
//routes.php
Route::get('/', ['before' => 'auth.level:1', function()
{
return View::make('hello');
}]);
and
//filters.php
Route::filter('auth.level', function($level)
{
//$level is 1
});
In controllers, it would look more like this
public function __construct(){
$this->filter('before', 'someFilter:param1,param2');
}
EDIT:
Should this not suffice to your needs, you can allways define the filter inside the controller's constructor. If you need access to the current controller ($this) and it's custom fields and you have many different classes you want to have that in, you can put the filter in BaseController's constructor and extend it in all classes you need.
class SomeFancyController extends BaseController {
protected $customVariable
/**
* Instantiate a new SomeFancyController instance.
*/
public function __construct()
{
$ctrl = $this;
$this->beforeFilter(function() use ($ctrl)
{
//
// do something with $ctrl
// do something with $ctrl->customVariable;
});
}
}
EDIT 2 :
As per your new question I realised the above example had a small error - as I forgot the closure has local scope. So it's correct now I guess.
If you declare it as static in your controller, you can call it statically from outside the controller
Controller:
class SampleController extends BaseController
{
public static $customVariable = 'test';
}
Outside your controller
echo SampleController::$customVariable
use:
public function __construct()
{
$this->beforeFilter('auth', ['controller' => $this]);
}

Magento: use various methods in 1 model

I'm having a problem using methods in my module's model class.
I have a public function which triggers 2 protected methods. The problem is that only the first 1 returns a value.
Here is my class:
<?php
class Osdave_Points_Model_Mysql4_Points_Collection extends Mage_Core_Model_Mysql4_Collection_Abstract
{
const POINTS_CONFIRMED = 2;
const POINTS_REDEEMED = 4;
protected $_customer;
public function _construct()
{
parent::_construct();
$this->_init('points/points');
$this->_customer = Mage::getSingleton('customer/session')->getCustomer();
}
public function getCustomerAvailablePoints()
{
$confirmed = $this->_getCustomerConfirmedPoints();
$redeemed = $this->_getCustomerRedeeemedPoints();
$balance = ($confirmed - $redeemed);
return $balance;
}
protected function _getCustomerConfirmedPoints()
{
$availablePoints = $this->addFieldToFilter('customer_id', $this->_customer->getId())
->addFieldToFilter('points_status', self::POINTS_CONFIRMED)
->addFieldToSelect('points_pending')
->addExpressionFieldToSelect('available_points', 'SUM({{points_pending}})', 'points_pending');
return $availablePoints->getFirstItem()->getAvailablePoints();
}
protected function _getCustomerRedeeemedPoints()
{
$redeemedPoints = $this->addFieldToFilter('customer_id', $this->_customer->getId())
->addFieldToFilter('points_status', self::POINTS_REDEEMED)
->addFieldToSelect('points_pending')
->addExpressionFieldToSelect('redeemed_points', 'SUM({{points_pending}})', 'points_pending');
return $redeemedPoints->getFirstItem()->getRedeemedPoints();
}
}
Now, if, in _getCustomerRedeeemedPoints(), I replace $this by Mage::getResourceModel('points/points_collection') it works fine. But as I already am insdide the class, I don't understand why I have to instance it through Mage: as far as I understand, $this is only available once.
So, am I doing something wrong?
thanks in advance.
I'm guessing this has to do with adding filters to the $this object for different purposes. Try adding this to the top of your methods:
$this->getSelect()->reset();
If that doesn't work, try echoing your queries before your getFirstItem calls and see if they behave as expected:
Mage::log($this->getSelect()."");
Hope that helps!
Thanks,
Joe

Resources