首页 > 解决方案 > 使用 Doctrine-Fixture 加载数据时,requestStack getCurrentRequest 在服务中为空

问题描述

所以,这是我在 stackoverflow 上的第一篇文章,如果我错过了一些强制性信息,请见谅。

让我解释一下我面临的问题。

在尝试使用 Doctrine-fixture command: 加载数据php bin/console doctrine:fixture:load -e test时,我收到以下错误:

In DebtService.php line 152: 
Call to a member function getSession() on null

那么,这是如何发生的,我有一个 pre persist 事件侦听器,它调用我的 DebtService 以检查是否可以使用付款来偿还债务。

我在用 :

    Symfony: ~3.4.*
    Doctrine-Fixture-bundle: 3.0 

这是我用来加载数据的类

class LoadBasicData extends Fixture implements FixtureInterface
{

    private $container;


    public function load(ObjectManager $manager)
    {
        new Session(new MockFileSessionStorage());

        $entities = array(
                Client::class,
                Landlord::class,
                Contact::class,
                Month::class,
                Year::class,
                Honorary::class,
                Room::class,
                Pension::class,
                Warranty::class,
                Flat::class,
                Contract::class,
                Debt::class,
                PiggyBank::class,
                Transfer::class,
                Material::class,
                Budget::class,
                Cleaning::class,
                Expense::class,
                ClientPayment::class, // Class That makes the error pop up
                //Payment::class

        );

        foreach($entities as $entity){
            $object = new $entity();

            $className =explode('\\', get_class($object));
            $objName=end($className);

            if(method_exists($object, "test")) {
                $object = $object->test(); // Returns the object with mocked values

                if(method_exists($object, "setDate")){
                    $object->setDate(new \Datetime("now"));
                }
                if(method_exists($object, "setRoom")){
                    $object->setRoom($this->getReference("Room"));
                }
                if(method_exists($object, "addRoom")){
                    $object->addRoom($this->getReference("Room"));
                }
                if(method_exists($object, "setClient")){
                    $object->setClient($this->getReference("Client"));
                }
                if(method_exists($object, "setHonorary")){
                    $object->setHonorary($this->getReference("Honorary"));
                }
                if(method_exists($object, "setAdministrationHonorary")){
                    $object->setAdministrationHonorary($this->getReference("Honorary"));
                }
                if(method_exists($object, "setLandlord")){
                    $object->setLandlord($this->getReference("Landlord"));
                }
                if(method_exists($object, "setWarranty")){
                    $object->setWarranty($this->getReference("Warranty"));
                }
                if(method_exists($object, "setMonth")){
                    $object->setMonth($this->getReference("Month"));
                }
                if(method_exists($object, "setYear")){
                    $object->setYear($this->getReference("Year"));
                }
                if(method_exists($object, "addMaterial")){
                    $object->addMaterial($this->getReference("Material"));
                }
                if(method_exists($object, "addClientPayment")){
                    $object->addClientPayment($this->getReference("ClientPayment"));
                }
                if(method_exists($object, "setPension") && $objName != "Room"){
                    $object->setPension($this->getReference("Pension"));
                }

                $this->addReference($objName, $object);

                $manager->persist($object);
                $manager->flush();
            }
        }
    }

}

我的听众:

class PrePersistListener {

    protected $mailService;
    protected $requestStack;
    protected $translator;
    protected $debtService;

    public function __construct(MailConstructorService $mailService, RequestStack $requestStack,TranslatorInterface $translator,DebtService $debtService){
        $this->mailService = $mailService;
        $this->requestStack = $requestStack;
        $this->translator = $translator;
        $this->debtService = $debtService;
    }

    public function prePersist(LifecycleEventArgs $args) {
        $entity = $args->getObject ();
        $em = $args->getObjectManager ();

        if ( $entity instanceof Expense) {
            $this->expense($entity, $em);
        }else if ($entity instanceof Transfer){
            $this->transfer($entity, $em);
        }else if ($entity instanceof Cleaning){
            $this->cleaning($entity, $em);
        }else if($entity instanceof ClientPayment){
            $this->clientPayment($entity, $em);
        }else if ($entity instanceof Debt){
            $this->debt($entity,$em);
        }else{
            return;
        }




    }

    private function clientPayment(ClientPayment $clientPayment,$em){

        $contract = $em->getRepository ( 'CoreBundle:Contract' )->findContractByClient ( $clientPayment->getClient () );

        $clientPayment->getRentAmount()>0?$this->debtService->generateDeptFromLatePayment($clientPayment, $contract,$em):null;
        $clientPayment->getRentAmount()>0?$this->debtService->generateRentDebtFromContract($clientPayment,$contract,$em):null;
        $this->debtService->generateHonoraryDebtFromContract($clientPayment,$contract,$em);
        $this->debtService->generateWarrantyDebtFromContract($clientPayment,$contract,$em);


        if($contract->getRoom() != null){
            $pensionCleaning = $contract->getRoom()->getPension()->getCleaningPerClient();
            if($pensionCleaning > 0 && $clientPayment->getRentAmount() > 0){

                $payments = $em->getRepository ( 'CoreBundle:ClientPayment' )->findByMonthAndYearAndClientAndRentAmount ( $clientPayment->getMonth(), $clientPayment->getYear(),
                        $clientPayment->getClient());

                if($payments == null){
                    $clientPayment->setRentAmount($clientPayment->getRentAmount() - $pensionCleaning);
                    $clientPayment->setCleaningAmount($pensionCleaning);
                }
            }
        }


    }   
    //... The rest of the functions
}

我的服务.yml

services:
  AD\CoreBundle\Service\DebtService:
    arguments: ["@doctrine.orm.default_entity_manager", "@translator","@request_stack", "@logger"]

  core_bundle.debt:
    alias: AD\CoreBundle\Service\DebtService
    public: true
    autowire: true

  AD\CoreBundle\EventListener\PrePersistListener:
        arguments: ["@core_bundle.mail","@request_stack","@translator", "@core_bundle.debt"]
        tags:
            - { name: doctrine.event_listener, event: prePersist }

  loadBasicData:
    class: AD\CoreBundle\DataFixtures\ORM\LoadBasicData
    tags: ['doctrine.fixture.orm']

#And much more

最后,我的 DebtService.php 的一部分:

class DebtService {
    public $em;
    public $translator;
    protected $logger;

    public function __construct(EntityManagerInterface $entityManager, TranslatorInterface $translator,RequestStack $requestStack,LoggerInterface $logger) {
        $this->em = $entityManager;
        $this->translator = $translator;
        $this->requestStack = $requestStack;
        $this->logger = $logger;


    }

    public function generateDeptFromLatePayment(ClientPayment $clientPayment,Contract $contract,$em){
        $contractDateStr = $contract->getDuePaymentDate()."-".$clientPayment->getMonth()->getNumber()."-".$clientPayment->getYear()->getNumber();
        $request = $this->requestStack->getCurrentRequest();

        dump($this->requestStack);
        dump($this->requestStack->getCurrentRequest());

        $latePaymentDebt = $em->getRepository('CoreBundle:Debt')->findOneBy(array(
                "client" => $contract->getClient(),
                "isLatePayment" => true,
                "month" => $clientPayment->getMonth(),
                "year" => $clientPayment->getYear()
        ));


        $timestamp = $contract->getArrivalDate()->getTimestamp();
        $arrivalMonth = date('m',$timestamp);
        $arrivalYear = date('Y',$timestamp);



        if(($arrivalMonth != $clientPayment->getMonth()->getNumber() && $arrivalYear == $clientPayment->getYear()->getNumber()) || $clientPayment->getYear()->getNumber() != $arrivalYear){
            $pd = $clientPayment->getDate ()->getTimestamp();
            $cd = strtotime( $contractDateStr);

            if($pd > $cd){


                $contractDate = new DateTime($contractDateStr);
                $diff = $clientPayment->getDate ()->diff($contractDate)->format("%a");
                // IF more not the same day of before
                if($diff > 0){
                    if($latePaymentDebt != null){ // If he already has a debt for late payment
                        if($clientPayment->getPenaltyAmount() > 0)
                            $diff = $latePaymentDebt->getAmount() -$clientPayment->getPenaltyAmount() ;
                            if($diff > 0){ // Si todavia falta pa pagar
                                $latePaymentDebt->setAmount($diff);

                                if($contract->getFlat() == null){
                                    $latePaymentDebt->setComment("El pago estaba atrasado de ".$diff." Dia(s) - Pension, pero ya pago $".number_format($clientPayment->getPenaltyAmount(),0,",",".")
                                            ." de un monto total de $".number_format($latePaymentDebt->getOldAmount(),0,",","."));
                                }else{
                                    $latePaymentDebt->setComment("El pago estaba atrasado de ".$diff." Dia(s) - Propiedad, pero ya pago $".number_format($clientPayment->getPenaltyAmount(),0,",",".")
                                            ." de un monto total de $".number_format($latePaymentDebt->getOldAmount(),0,",","."));
                                }
                            }else if( $diff < 0 ){ //Si pago demas
                                $this->reduceClientDebt($diff, $clientPayment);
                            }
                            else{ // sinon on enlève la dete /!\ A ver que hacer si paga demas
                                $message = "Se ha removido una deuda al cliente: ".$clientPayment->getClient()->getName()." de un monto de $". number_format($latePaymentDebt->getAmount(),0,",",".").
                                " por culpa de :".$latePaymentDebt->getComment();
                                $request->getSession()->getFlashBag()->add("warning", $message);
                                $amount -= $latePaymentDebt->getAmount();
                                $em->remove($latePaymentDebt);
                            }



                    }else{ // IF he doen't havea debt
                        if($clientPayment->getPenaltyAmount() != 0){ //Si ya paga una parte o toda su deuda
                            $amount = 0;
                            if($contract->getFlat() == null){
                                $amount = 1000*$diff; // 1000 pesos por dia en caso de pension
                            }else{
                                $amount = 1/100*$contract->getFullMonthPrice()*$diff; // 1% per day in case of flat
                            }

                            if($amount > $clientPayment->getPenaltyAmount()){ // Si no pago suffisiente
                                $debt = new Debt();
                                $debt->setClient($clientPayment->getClient());
                                $debt->setAutomated(true);
                                $debt->setAmount($amount - $clientPayment->getPenaltyAmount());

                                if($contract->getFlat() == null){
                                    $debt->setComment("El pago estaba atrasado de ".$diff." Dia(s) - Pension, pero ya pago $".number_format($clientPayment->getPenaltyAmount(),0,",",".")
                                            ." de un monto total de $".number_format($amount,0,",","."));
                                }else{
                                    $debt->setComment("El pago estaba atrasado de ".$diff." Dia(s) - Propiedad, pero ya pago $".number_format($clientPayment->getPenaltyAmount(),0,",",".")
                                            ." de un monto total de $".number_format($amount,0,",","."));
                                }
                                $debt->setPaid(false);
                                $debt->setAdministration(null);
                                $debt->setMonth($clientPayment->getMonth());
                                $debt->setYear($clientPayment->getYear());
                                $debt->setIsLatePayment(true);
                                $em->persist($debt);


                                $message = "Se ha añadido una deuda al cliente: ".$clientPayment->getClient()->getName()." de a un monto de $". number_format($debt->getAmount(),0,",",".").
                                " por culpa de haber pagado con ".$diff." dia(s) de atraso. Pero ya pago $".number_format($clientPayment->getPenaltyAmount(),0,",",".")
                                ." de un monto total de $".number_format($amount,0,",",".");
                                $request->getSession()->getFlashBag()->add("warning", $message);


                            }else if($amount < $clientPayment->getPenaltyAmount()){ // Si pago mas de lo que debia por el atraso, se busca las otras deudas
                                $amount = $clientPayment->getPenaltyAmount() - $amount;
                                $this->reduceClientDebt($amount,$clientPayment);
                            }
                        }
                        else{ // Sino se crea una deuda del monto entero.

                            $debt = new Debt();
                            $debt->setClient($clientPayment->getClient());
                            $debt->setAutomated(true);

                            if($contract->getFlat() == null){
                                $debt->setAmount(1000*$diff); // 1000 pesos por dia en caso de pension
                                $debt->setComment("El pago estaba atrasado de ".$diff." Dia(s) - Pension");
                            }else{
                                $debt->setAmount(1/100*$contract->getFullMonthPrice()*$diff); // 1% per day in case of flat
                                $debt->setComment("El pago estaba atrasado de ".$diff." Dia(s) - Propiedad");
                            }
                            $debt->setPaid(false);
                            $debt->setAdministration(null);
                            $debt->setMonth($clientPayment->getMonth());
                            $debt->setYear($clientPayment->getYear());
                            $debt->setIsLatePayment(true);

                            // Message to the user telling him that a debt has been added
                            $message = "Se ha añadido una deuda al cliente: ".$clientPayment->getClient()->getName()." de a un monto de $". number_format($debt->getAmount(),0,",",".").
                            " por culpa de haber pagado con ".$diff." dia(s) de atraso.";
                            $request->getSession()->getFlashBag()->add("warning", $message); // Line 152 that throws the error. 

                            $em->persist($debt);
                        }
                    }
                }
            }else{
                if($clientPayment->getPenaltyAmount() != 0){

                    $this->reduceClientDebt($clientPayment->getPenaltyAmount(),$clientPayment);

                }
            }
        }else{
            if($clientPayment->getPenaltyAmount() != 0){

                $this->reduceClientDebt($clientPayment->getPenaltyAmount(),$clientPayment);

            }
        }

    }
}

我试过评论 $request->getSession(); // 它适用于测试,但我的应用程序中丢失了 flashBags。

这是我第一次在我的应用程序中实现 Test / Doctrine-Fixture。我对这件事的了解仍然有限。

谢谢你的帮助。

阿德里安

标签: phpsymfonyservicefunctional-testing

解决方案


好的,我找到了解决问题的方法。

LoadBasicData 作为一项服务,我注入了@requestStack 并创建了一个新的请求/会话。

服务.yml

services:
  loadBasicData:
    class: AD\CoreBundle\DataFixtures\ORM\LoadBasicData
    arguments: ["@request_stack"]
    tags: ['doctrine.fixture.orm']

并添加到我的构造函数中:LoadBasicData.php

    protected $requestStack;

    public function __construct(RequestStack $requestStack){
        $this->requestStack = $requestStack;
        $request = new Request();
        $request->setSession(new Session());
        $this->requestStack->push($request);
    }

推荐阅读