I am trying to do a service which returns some records from DB. The problem is that I can't get to the EntityManager in my controller.
Service return an empty result. When I change it to return random string it works fine. But in this way it is not working as it should be.
use BeSimple\SoapBundle\ServiceDefinition\Annotation as Soap;
use Symfony\Component\DependencyInjection\ContainerAware;
class DefaultController extends ContainerAware
{
/**
* #Soap\Method("getPolicy")
* #Soap\Result(phpType = "GL\WebServiceBundle\Entity\Policy[]")
*/
public function getPolicy()
{
$em = $this->container->get('doctrine')->getEntityManager();
$policies = $em->getRepository('GLPolicyBundle:Policy')->findBySentDate(null);
return var_dump($policies);
return $policies;
}
}
What I am doing wrong?
Related
I'm currently building a web application, and went for Symfony 4 along with API Platform.
I built a custom data provider in order to pull data from a XML file, for an entity. Since it's all one-way operations, I only enabled GET operations for both items and collections.
I am trying to tie the entity served by this custom data provider to a Doctrine entity, but I'm getting an error saying that the entity is not a valid one or mapped super class.
How do I create a relationship between these two? Is it even possible?
Thanks!
This is a snippet from the aforementioned entity:
<?php
//src/Entity/Sst.php
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use ApiPlatform\Core\Annotation\ApiProperty;
/**
* #ApiResource(
* collectionOperations={"get"={"method"="GET"}},
* itemOperations={"get"={"method"="GET"}}
* )
*/
class Sst
{
public $code_urssaf;
/**
* #ApiProperty(identifier=true)
*/
public $code_sst;
// ...and a few others
public function getCodeUrssaf(): ?string
{
return $this->code_urssaf;
}
public function setCodeUrssaf(string $code_urssaf): self
{
$this->code_urssaf = $code_urssaf;
return $this;
}
public function getCodeSst(): ?string
{
return $this->code_sst;
}
public function setCodeSst(string $code_sst): self
{
$this->code_sst = $code_sst;
return $this;
}
// and so on; this is generated then tuned with Symfony's MakerBundle.
Here's a bit from the collection data provider, with imports omitted (but everything works when querying the API directly):
final class SstCollectionDataProvider implements CollectionDataProviderInterface, RestrictedDataProviderInterface
{
public function __construct(FilesystemInterface $extdataStorage, SerializerInterface $serializer)
{
$this->serializer = $serializer;
$this->storage = $extdataStorage;
}
public function supports(string $resourceClass, string $operationName = null, array $context = [] ): bool
{
return Sst::class === $resourceClass;
}
public function getCollection(string $resourceClass, string $operationName = null): \Generator
{
$sstfile = $this->storage->read('SST_29072019.xml');
$sstlist = $this->serializer->deserialize($sstfile, SstCollection::class, 'xml', array('object_to_populate' => $sstlist = new SstCollection()));
foreach($sstlist as $sstObject)
{
yield $sstObject;
}
}
}
The Doctrine entity has this, mirroring other relationships:
/**
* #var Sst[]
*
* #ORM\ManyToOne(targetEntity="App\Entity\Sst")
*/
private $sst;
I expect to be able to tie the custom entity to the Doctrine one, but I cannot even start the Symfony app, I'm getting:
In MappingException.php line 346:
Class "App\Entity\Sst" is not a valid entity or mapped super class.
I want to split my codebase to simple one purpose specific classes like:
class AddKeyword
{
/**
* #var KeywordRepository
*/
private $keywordRepository;
public function __construct(KeywordRepository $keywordRepository)
{
$this->keywordRepository = $keywordRepository;
}
public function __invoke(string $name): Keyword
{
$entity = $this->keywordRepository->findOneByName($name);
if ($entity)
return $entity;
$entity = Keyword::create(KeywordId::create(), $name);
$this->keywordRepository->save($entity);
return $entity;
}
}
But for using that class I have to resolve DI. How to do it?
Thank you in advance.
Not sure about what you want to achieve but if you want add/get keyword everywhere in your code base you have 2 choices:
Use autowiring
Declare your class as service and get it from the container.
Symfony encourage DI by autowiring.
namespace App\Controller;
use App\AddKeyword;
class DefaultController
{
public function __construct(Addkeyword $keyword) {
$keyword('keyword');
}
}
I'm trying to write an API in Symfony 4. I've hit a problem with my controller methods when trying to use DependencyInjection for a service API class I created. I've tried several different ways to write the code and can not figure it out.
https://symfony.com/doc/current/components/dependency_injection.html
I can make a getNext() (instead of get() below) method and the code will function as expected, but if I try to use a get() method I will get an error. These are the basic classes involved. Most of the code has been removed.
class AppointmentController extends AbstractController
{
/**
* #Route("/appointment/getNext", name="appointment/getNext")
*
*/
public function get(string $id = null, CernerFhir $fhirApi)
{
$request = Request::createFromGlobals();
...more code...
}
}
class CernerFhir
{
public function __construct(LoggerInterface $logger, ParameterBagInterface $params)
{
$this->logger = $logger;
$this->params = $params;
}
}
}
Warning: Declaration of App\Controller\AppointmentController::get(?string $id, App\Service\CernerFhir $fhirApi) should be compatible with Symfony\Bundle\FrameworkBundle\Controller\AbstractController::get(string $id)
AbstractController uses an interface that defines a get() method with a specific number of parameter and return type. If you wan't to overwrite it's get method (which i do no recommend), you have to write it so that it's compatible with it's definition in the interface.
http://php.net/manual/en/language.oop5.interfaces.php
i need some help i want to write a unit test about a controler method , i have searched for examples and tested a lot of method's but none of them has worked:
Here is my controller:
class ComputerController extends Controller
{
/**
* #Route("/list-computers.html", name="back_computer_list")
* #return RedirectResponse|Response
*/
function listComputerAction()
{
$ad = $this->get("ldap_service");
$computers = $ad->getAllComputer();
return $this->render('BackBundle:Computer:list.html.twig', array(
"computers" => $computers,
));
}
I have tried to test it with mock like this:
class ComputerController extends Controller
{
/**
* #var EngineInterface
*/
private $templating;
public function setTemplating($templating)
{
$this->templating = $templating;
}
and i have created a test method:
class ComputerControllerTest extends TestCase {
public function testlistComputerAction(){
$templating = $this->getMockBuilder('BackBundle\Controller\ComputerController')->getMock();
$computers = [1,2];
$templating->expects($this->once())
->method('render')
->with('BackBundle:Computer:list.html.twig', array(
"computers" => $computers))
->will($this->returnValue( $computers));
$controller = new ComputerController();
$controller->setTemplating($templating);
$this->assertEquals('success', $controller->listComputerAction());
}
When i start executing phpunit , i have this warning"Trying to configure method "render" which cannot be configured because it does not exist, has not been specified, is final, or is static"
I would be thankful if someone has an idea about this
I tried to Test a method in ldapService : Here is the method's of the service that i want to test
/**
* #return bool|resource
*/
public function getLdapBind()
{
if (!$this->ldapBind) {
if ($this->getLdapConnect()) {
$this->ldapBind = #ldap_bind($this->ldapConnect, $this->ldapUser, $this->ldapPass);
}
}
return $this->ldapBind;
}
/**
* #param $ldapUser
* #param $password
* #return bool
*/
function isAuthorized($ldapUser, $password)
{
$result = false;
if ($this->ldapConnect) {
$result = #ldap_bind($this->ldapConnect, $ldapUser, $password);
}
return $result;
}
Here is the test (using Mock):
<?php
namespace BackBundle\Tests\Service;
use PHPUnit\Framework\TestCase;
use BackBundle\Service\LdapService;
use PHPUnit_Framework_MockObject_InvocationMocker;
class LdapServiceTest extends TestCase {
public function testgetLdapConnect()
{
// $LdapService = new LdapService();
$ldapMock = $this->getMockBuilder( 'LdapService')->setMethods(['getLdapBind'])->disableOriginalConstructor()->getMock();
$ldapMock->expects($this->once())
// ->method()
->with(array('ldap_bind', 'mike', 'password'))
->will($this->returnValue(true));
$ldapMock->isAuthorized('mike', 'password');
}
}
But i have a warning that i can't resolve : "Method name matcher is not defined, cannot define parameter matcher without one"
If someone , has an idea about that please
Honestly, there is nothing useful to test in that three-line controller. #1 is the service container, and #3 is the Twig subsystem. Line #2 can be unit tested on it's own.
With more complex controllers, I have found that making them a service where all the dependencies are passed in, either by constructor, or into the action itself does make slightly more complex controllers quite easy, but very few need that anyway.
All of my query in Entity Repository needs to be filtered by user.
Now I want to know how can I access the currently logged in user in Entity Repository directly.
What I did today is to get the currently logged in user in my controller, through the use of $this->getUser() and then pass it to Entity Repository and this is not efficient.
You need to inject security.token_storage service into another one to get the current user, but as of Repository classes belong to Doctrine project, not Symfony, it is not recommended to do this.. May be there is a way to achieve it by creating custom entityManager class as described here, but I don't think it would a good solution..
Instead of customizing an entityManager better create a service which calls repository classes' methods, inject desired services into it.. Let Repository classes do their job.
Implementation would be something like this:
RepositoryClass:
class MyRepository extends EntityRepository
{
public function fetchSomeDataByUser(UserInterface $user)
{
// query
}
}
Service:
class MyService
{
private $tokenStorage;
public function _construct(TokenStorageInterface $tokenStorage)
{
$this->tokenStorage = $tokenStorage;
// other services
}
public function getSomeDataByUser()
{
$user = $this->tokenStorage->getToken()->getUser();
return $this->entityManager->getRepository(MyREPOSITORY)->fetchSomeDataByUser($user);
}
}
Usage:
public function someAction()
{
$dataByUser = $this->get(MYSERVICE)->getSomeDataByUser();
}
If you use JMSDiExtraBundle it can be done by adding setter injection:
use Doctrine\ORM\EntityRepository;
use JMS\DiExtraBundle\Annotation as DI;
class YourRepository extends EntityRepository
{
/** #var User current user entity */
protected $user;
/**
* #DI\InjectParams({
* "token_storage" = #DI\Inject("security.token_storage")
* })
*/
public function setSimplaManager(TokenStorageInterface $tokenStorage)
{
$token = $tokenStorage->getToken();
if (!is_object($user = $token->getUser())) {
// e.g. anonymous authentication
return;
}
$this->user = $user;
}
}