phpzend-framework3servicemanager

Can I call a service inside a service in zf3?


I am really new into frameworks and into ZF3, but I need to make a API, with the following logic. I receive parameters, I store them in an bd and if the call is action is to be made at this point(call Manager), I send it to the (provider caller). I was able to the first part, and the second, but now, I don't know how to do the last one... I have the following code:

IndexController.php

use Application\Service\CallManager;
use Application\Service\TropoCaller;
use Application\Service\NexmoCaller;



class IndexController extends AbstractActionController
{
 /**
 * Entity manager.
 * @var Doctrine\ORM\EntityManager 
 */
private $entityManager;

/**
 * Call manager.
 * @var Application\Service\CallManager 
 */
private $callManager;

/**
 * Call manager.
 * @var Application\Service\NexmoCaller
 */
private $NexmoCaller;

/**
 * Call manager.
 * @var Application\Service\TropoCaller
 */
private $TropoCaller;

/**
 * Constructor is used for injecting dependencies into the controller.
 */
public function __construct($entityManager, $callManager, $NexmoCaller, $TropoCaller) 
{
    $this->entityManager = $entityManager;
    $this->callManager = $callManager;

    $this->NexmoCaller = $NexmoCaller;
    $this->TropoCaller = $TropoCaller;
}

public function contactUSAction()
{
    $form= new ButtoncallForm();

    // Check whether this post is a POST request.
    if ($this->getRequest()->isPost()) {

        // Get POST data.
        $data = $this->params()->fromPost();

        // Fill form with data.
        $form->setData($data);
        if ($form->isValid()) {

            // Get validated form data.
            $data = $form->getData();

            // Use post manager service to add new call to the database             
            $this->callManager->CallManager($data);



            return $this->redirect()->toRoute('application', 
                    ['action'=>'thankYou']);
        }
    }

 return new ViewModel([

        'form' => $form,
        ]);
 }

public function thankYouAction() 
{
    return new ViewModel();
}

}

IndexControllerFactory.php

   <?php
namespace Application\Controller\Factory;
use Interop\Container\ContainerInterface;
use Zend\ServiceManager\Factory\FactoryInterface;
use Application\Service\CallManager;
use Application\Service\TropoCaller;
use Application\Service\NexmoCaller;
use Application\Controller\IndexController;
/**
 * This is the factory for IndexController. Its purpose is to instantiate the
 * controller.
 */
class IndexControllerFactory implements FactoryInterface
{
    public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
    {
        $entityManager = $container->get('doctrine.entitymanager.orm_default');
        $callManager = $container->get(CallManager::class);
        $NexmoCaller = $container->get(NexmoCaller::class);
        $TropoCaller = $container->get(TropoCaller::class);

        // Instantiate the controller and inject dependencies
        return new IndexController($entityManager, $callManager, $NexmoCaller, $TropoCaller);
    }
}

My CallManager.php

<?php

namespace Application\Service;

use Zend\ServiceManager\ServiceManager;
use Zend\ServiceManager\ServiceManagerAwareInterface;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Application\Entity\CallRequested;
use Doctrine\ORM\EntityManager;
use Stomp\Client;
use Stomp\StatefulStomp;
use Stomp\Network\Connection;
use Stomp\Transport\Message;
use Application\Service\NexmoCaller;
use Application\Service\TropoCaller;

class CallManager
{
   /**
   * Doctrine entity manager.
   * @var Doctrine\ORM\EntityManager
   */
    private $entityManager;

   /**
   * @var Application\Service\NexmoCaller
   */
    private $NexmoCaller;

    /**
    * @var Application\Service\TropoCaller
    */
    private $TropoCaller;
  // Constructor method is used to inject dependencies to the controller.
  public function __construct($entityManager) 
  {
    $this->entityManager = $entityManager;


  }

    public function CallManager($data) 
    {
    $callRequested= new CallRequested;
    $callRequested-> setClientContact($data['clientContact']);
    $callRequested-> setProvider($data['provider']);
    $callRequested-> setCallCenter($data['callCenterContact']);
    $whenCall= $data['schedule'];
    $language= $data['language'];
    $date = new \DateTime();
    $callRequested-> setRequestTime($date);


    $provider=$data['provider'];
    $tropo='Tropo';
    //var_dump($data);


    $this->entityManager->persist($callRequested);
    $this->entityManager->flush();

    $id=$callRequested->getID();
    //var_dump($callRequested->getID());
    $data=array($id,$data);
    $data=json_encode($data, true);

//confirmar onde usar esta lógica
    if($whenCall==='1')
    { echo "Vamos establecer a ligaçao \n";
        if (stripos($provider, $tropo) !== false) {


                                            $destination  = '/queue/tropozend';
                                            $messages = 1;
                                            $size = 256;

                                            $DATA = "calls";

                                            $body = $data;


                                              try {
                                               $connection = new Connection('tcp://192.168.64.3:61613');
                                                $con1 = new StatefulStomp(new Client($connection));


                                                  $con1->send($destination, new Message($body));

                                                    //echo "Message sent $body \n" ;

                                              } catch(StompException $e) {
                                                echo $e->getMessage();

                                                // TropoCall();

                                              }



    } 
    else{                                     
                                              $destination  = '/queue/nexmozend';
                                              $messages = 1;
                                              $size = 256;

                                              $DATA = "calls";

                                              $body = $data;

                                              try {
                                               $connection = new Connection('tcp://192.168.64.3:61613');
                                                $con1 = new StatefulStomp(new Client($connection));


                                                  $con1->send($destination, new Message($body));

                                                    //echo "Message sent $body \n" ;


                                                    } catch(StompException $e) {
                                                echo $e->getMessage();
                                                    }

                                                    }
                                                   // NexmoCall();

     }
     else {echo "Vamos agendar a sua chamada \n"; 
 }


}
}

I created the NexmoCaller and TropoCaller, but don't know how to called them. Here is one example of the logic: class NexmoCaller

{
    // public function __construct($NexmoCaller) 
  //   {
  //       $this->NexmoCaller = $NexmoCaller;
  //   }


    public function NexmoCall()
    {

            $service= new NexmoCaller();
            $serviceManager->set(NexmoCaller::class, $service); 

$key = file_get_contents('scripts/application.key');

$basic  = new \Nexmo\Client\Credentials\Basic($keyNexmo, $secret);
$keypair = new \Nexmo\Client\Credentials\Keypair($key, $application_id);
$client = new \Nexmo\Client(new \Nexmo\Client\Credentials\Container($basic, $keypair));

$jwt = generate_jwt($application_id, $key);


header('Content-Type: application/json', 'Authorization: Bearer'.$jwt); 

$destination  = '/queue/nexmozend';


      $connection = new Connection('tcp://192.168.64.3:61613');
      $stomp = new StatefulStomp(new Client($connection));
      $stomp->subscribe($destination);


      echo "Waiting for messages...\n";
        while(true) {
                     $frame = $stomp->read();
                     $body = $frame->getBody();
                     //echo($frame);
                     echo "message received $body \n";
                     //echo $stomp->read()->body, PHP_EOL;
                    //print_r($frame = $stomp->read());
                    //print_r($stomp->read()->body);
                    break;
                    }


//codificar o json como é necessário       
$json = json_decode($body, true);
var_dump($json);

}

}

My config.module.php

'controllers' => [
        'factories' => [
            Controller\IndexController::class => Controller\Factory\IndexControllerFactory::class,

        ],
    ],
    'service_manager' => [
        'factories' => [
                    Service\CallManager::class => Service\Factory\CallManagerFactory::class,
                    Service\NexmoCaller::class => InvokableFactory::class,
                    Service\TropoCaller::class => InvokableFactory::class,
        ],            
    ],

I have tried several aproaches but none of them creates the manager or calls it... Plus, I haven't found any case of using a service inside a service, so i am not even sure it is possible... One of the solutions I've tried was: -constructing in my call manager:

   /**
   * Doctrine entity manager.
   * @var Doctrine\ORM\EntityManager
   */
    private $entityManager;

   /**
   * @var Application\Service\NexmoCaller
   */
    private $NexmoCaller;

    /**
    * @var Application\Service\TropoCaller
    */
    private $TropoCaller;
     public function __construct($entityManager, $NexmoCaller, 
       $TropoCaller) 
      {
        $this->entityManager = $entityManager;
        $this->NexmoCaller = $NexmoCaller;
        $this->TropoCaller = $TropoCaller;

       }

And I get this error:

Too few arguments to function Application\Service\CallManager::__construct(), 1 passed in /opt/lampp/htdocs/buttoncall/skeleton-application/module/Application/src/Service/Factory/CallManagerFactory.php on line 15 and exactly 3 expected

Or simply by calling:

 $this->NexmoCaller->NexmoCaller();

And get this: Call to a member function NexmoCaller() on null

I used answer gaven, in my Factory:

<?php
namespace Application\Service\Factory;
use Interop\Container\ContainerInterface;
use Zend\ServiceManager\Factory\FactoryInterface;
use Application\Service\CallManager;
use Application\Service\NexmoCaller;
use Application\Service\TropoCaller;

class CallManagerFactory implements FactoryInterface
{
    public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
    {
        $entityManager = $container->get('doctrine.entitymanager.orm_default');
         $nexmoCaller = $container->get(NexmoCaller::class);
        $tropoCaller = $container->get(TropoCaller::class);

        return new $requestedName(
            $entityManager, 
            $nexmoCaller, 
            $tropoCaller
    );


    }
}

And get this: Call to a member function NexmoCaller() on null

What should I do?


Solution

  • From what I understand you are trying to use the NexmoCaller and TropoCaller inside of the CallManager but you haven't injected them.

    You are on the right path creating the constructor:

    public function __construct($entityManager, $NexmoCaller, $TropoCaller) 
    {
        $this->entityManager = $entityManager;
        $this->NexmoCaller = $NexmoCaller;
        $this->TropoCaller = $TropoCaller;
    }
    

    But while you are expecting 3 parameter the error tells us that the CallManagerFactory is only sending 1.

    To solve this modify the CallManagerFactory so it looks something like this:

    public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
    {
        $entityManager = $container->get('doctrine.entitymanager.orm_default');
        $nexmoCaller = $container->get(NexmoCaller::class);
        $tropoCaller = $container->get(TropoCaller::class);
    
        return new $requestedName(
            $entityManager, 
            $nexmoCaller, 
            $tropoCaller
        );
    }