I am trying to plug APCu into the Symfony 3.3 test project.
I am getting an error, when I add ApcuAdapter to AppKernel.php.
Here is the list of what I have done:
in ./app/AppKernel.php i have added a "new" line to $bundles in public function registerBundles():
public function registerBundles()
{
$bundles = [
... ,
new Symfony\Component\Cache\Adapter\ApcuAdapter()
];
...
return $bundles;
}
Opened the project's site. It shows an error:
Attempted to call an undefined method named "getName" of class "Symfony\Component\Cache\Adapter\ApcuAdapter".
(./ means the root folder of the project)
Please, tell me why does this error happen and how to plug this adapter into the symfony framework. Thank you.
me have found the solution somewhere on the framework's website.
somehow, we should use not the Adapter, but the Simple instead.
seems very un-logical to me.
so, the Service now works and looks this way:
<?php
namespace AppBundle\Service;
use Symfony\Component\Cache\Simple\ApcuCache;
class ApcuTester
{
public function __construct
(
)
{
}
public function testMe()
{
$cache = new ApcuCache();
$TestVar_dv = 0;
$TestVar_vn = 'TestVar';
$TestVar = NULL;
//$cache-> deleteItem($TestVar_vn); // dbg
// Read
if ( $cache->hasItem($TestVar_vn) )
{
$TestVar = $cache->get($TestVar_vn);
}
else
{
$cache->set($TestVar_vn, $TestVar_dv);
$TestVar = $TestVar_dv;
}
// Modify
$TestVar++;
// Save
$cache->set($TestVar_vn, $TestVar);
// Return
return $TestVar;
}
}
And the Controller which executes this Service looks as this:
<?php
namespace AppBundle\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use AppBundle\Service\MessageGenerator;
use AppBundle\Service\ApcuTester;
class LuckyController extends Controller
{
/**
* #Route("/lucky/number", name="lucky")
*/
public function numberAction
(
Request $request,
MessageGenerator $messageGenerator,
ApcuTester $apcuTester
)
{
$lucky_number = mt_rand(0, 100);
$message = $messageGenerator->getHappyMessage();
$testvar = $apcuTester->testMe();
$tpl = 'default/lucky_number.html.twig';
$tpl_vars =
[
'lucky_number' => $lucky_number,
'message' => $message,
'testvar' => $testvar
];
return $this->render($tpl, $tpl_vars);
}
}
If i wrote the same thing in pure PHP i would have done it an hour earlier :) Oh these crazy frameworks...
Related
I'm trying to make a custom maker with the Symfony make bundle.
The maker command looks like this:
<?php
namespace App\Maker;
use Doctrine\Common\Annotations\Annotation;
use Symfony\Bundle\MakerBundle\ConsoleStyle;
use Symfony\Bundle\MakerBundle\DependencyBuilder;
use Symfony\Bundle\MakerBundle\Generator;
use Symfony\Bundle\MakerBundle\InputConfiguration;
use Symfony\Bundle\MakerBundle\Maker\AbstractMaker;
use Symfony\Bundle\MakerBundle\Str;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
final class MakeCustomEntity extends AbstractMaker
{
public static function getCommandName(): string
{
return 'make:custom-entity';
}
public static function getCommandDescription(): string
{
return 'Creates a new entity';
}
public function configureCommand(Command $command, InputConfiguration $inputConf)
{
$command
->addArgument('entity-class', InputArgument::OPTIONAL, sprintf('Choose a name for your entity class (e.g. <fg=yellow>%s</>)', Str::asClassName(Str::getRandomTerm())));
}
public function generate(InputInterface $input, ConsoleStyle $io, Generator $generator)
{
}
public function configureDependencies(DependencyBuilder $dependencies)
{
$dependencies->addClassDependency(
Annotation::class,
'doctrine/annotations'
);
}
}
So far so good, the custom maker shows up when listing all commands.
However I would like to write a test for this maker (inspired from the tests I have found on the bundles github):
<?php
namespace Tests\Maker;
use App\Maker\MakeCustomEntity;
use Symfony\Bundle\MakerBundle\Test\MakerTestCase;
use Symfony\Bundle\MakerBundle\Test\MakerTestDetails;
class MakeCustomEntityTest extends MakerTestCase
{
public function getTestDetails()
{
yield 'entity_full_custom_namespace' => [
MakerTestDetails::createTest(
$this->getMakerInstance(MakeCustomEntity::class),
[
// entity class name
'\App\Domain\Entity\Test\Test',
]
)
->assert(function (string $output, string $directory) {
$this->assertStringContainsString('created: src/Domain/Entity/Test/Test.php', $output);
}),
];
}
}
When I try to run this test I get the following warning and test doesn't fail even though it should:
The data provider specified for Tests\Maker\MakeCustomEntityTest::testExecute is invalid.
You have requested a non-existent service "maker.maker.make_custom_entity". Did you mean one of these: "maker.maker.make_authenticator",...
Is this the correct way to testing custom makers? What should I do to avoid this?
Just created a new project with symfony2 and installed FOSRestBundle.
Controller example:
<?php
namespace ApiBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use FOS\RestBundle\Controller\FOSRestController;
class TestController extends FOSRestController
{
public function TestAction()
{
$data = array ('1', '2', '3', 'four'); // get data, in this case list of users.
$view = $this->view($data, 200)
->setTemplate("ApiBundle:Test:test.html.twig")
->setTemplateVar('test')
;
return $this->handleView($view);
}
}
Got error message:
You have requested a non-existent service "fos_rest.view_handler".
Does anyone have an idea about this?
In your AppKernel, be sure you have the following:
// app/config/AppKernel.php
public function registerBundles()
{
$bundles = array(
// ...
new FOS\RestBundle\FOSRestBundle(),
);
}
You surely forgotten this step.
When I try to create a doctrine crud for an entity I get an 'Unknown entity namespace alias' exception.
I have the following project structure
With a series of bundles (in the Bundles directory) using the Entities in the src\Project\Entity directory.
As you can see my entity namespace is
namespace Project\Entity;
I have a feeling it might be to do with the auto_mapping, but I have been playing with this for 4-5 hours and am getting nowhere.
Any suggestions?
Solution:
Create a command which extends the base doctrine crud command
extends \Sensio\Bundle\GeneratorBundle\Command\GenerateDoctrineCrudCommand
Modifying
$entityClass = $this->getContainer()->get('doctrine')->getAliasNamespace('Project').'\\'.$entity;
to the namespace of the entity. By default it assumes the entity is in the Bundle where you want the CRUD to be created.
By setting
$this->setName('project:generate:crud');
in the Configre() function you can call the function from your command line
Example:
<?php
namespace Project\Bundle\UtilityBundle\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ConfirmationQuestion;
use Sensio\Bundle\GeneratorBundle\Command\Validators;
class GenerateDoctrineCrudCommand extends \Sensio\Bundle\GeneratorBundle\Command\GenerateDoctrineCrudCommand
{
protected function configure()
{
parent::configure();
$this->setName('project:generate:crud');
$this->setDescription('CRUD generator that supports entities outside a bundle');
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$questionHelper = $this->getQuestionHelper();
if ($input->isInteractive()) {
$question = new ConfirmationQuestion($questionHelper->getQuestion('Do you confirm generation', 'yes', '?'), true);
if (!$questionHelper->ask($input, $output, $question)) {
$output->writeln('<error>Command aborted</error>');
return 1;
}
}
// Note: this expects an argument like InterpracCorporateFrontendBundle:Notification
list($bundle, $entity) = explode(':', $input->getOption('entity'));
$format = Validators::validateFormat($input->getOption('format'));
$prefix = $this->getRoutePrefix($input, $entity);
$withWrite = $input->getOption('with-write');
$forceOverwrite = $input->getOption('overwrite');
$questionHelper->writeSection($output, 'CRUD generation');
$entityClass = $this->getContainer()->get('doctrine')->getAliasNamespace('Project').'\\'.$entity;
$metadata = $this->getEntityMetadata($entityClass);
$bundle = $this->getContainer()->get('kernel')->getBundle($bundle);
$generator = $this->getGenerator($bundle);
$generator->generate($bundle, $entity, $metadata[0], $format, $prefix, $withWrite, $forceOverwrite);
$output->writeln('Generating the CRUD code: <info>OK</info>');
$errors = array();
$runner = $questionHelper->getRunner($output, $errors);
// form
if ($withWrite) {
$output->write('Generating the Form code: ');
if ($this->generateForm($bundle, $entity, $metadata)) {
$output->writeln('<info>OK</info>');
} else {
$output->writeln('<warning>Already exists, skipping</warning>');
}
}
// routing
if ('annotation' != $format) {
$runner($this->updateRouting($questionHelper, $input, $output, $bundle, $format, $entity, $prefix));
}
$questionHelper->writeGeneratorSummary($output, $errors);
}
}
The problem is that you are keeping your entities outside bundles. Since this is not standard behaviour, you have to extend or create another GenerateDoctrineCrudCommand to be able to pass namespace alias.
I have created a View Helper to display latest Adverts from a Database Table. Since I have different Types of Adverts, I would like to be able to pass a variable from inside my View where I call the View Helper to show specific Adverts.
I am sorry that I can not explain it in a better way, but I am still a total beginner in ZF2. I will add the Sourcecode and hopefully this will make it more clear. Please note that I have the Sourcecode from a Book which displayed Pizza's randomly and changed it till it worked to show my adverts. I might still have Code in it which is not actually needed, so please do not wonder... Okay here the code:
1. the view: index.html
<?php foreach ($this->latestAdvert() as $value){ ?>
<li><?php echo $value->getAdvertTitle();?></li>
<?php }?>
2. the view Helper: Advert\View\Helper\LatestAdvert.php
namespace Advert\View\Helper;
use Zend\View\Helper\AbstractHelper;
class LatestAdvert extends AbstractHelper
{
protected $random = null;
public function __construct($random)
{
$this->setLatestAdvert($random);
}
public function setLatestAdvert($random)
{
$this->random = $random;
}
public function getLatestAdvert()
{
return $this->random;
}
public function __invoke()
{
$latestAdverts = $this->getLatestAdvert();
return $latestAdverts;
}
}
3. the Factory: Advert\View\Helper\LatestAdvertFactory.php
namespace Advert\View\Helper;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
class LatestAdvertFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $serviceLocator)
{
$locator = $serviceLocator->getServiceLocator();
$service = $locator->get('Advert\Service');
$random = $service->fetchSingleByRandom();
$helper = new LatestAdvert($random);
return $helper;
}
}
4. the Service: Advert\Service\LatestAdvertService .php
namespace Advert\Service;
use Advert\Entity\Advert as AdvertEntity;
use Doctrine\ORM\EntityManager;
use Zend\ServiceManager\ServiceManager;
use Zend\ServiceManager\ServiceManagerAwareInterface;
use Zend\Debug\Debug;
class LatestAdvertService implements ServiceManagerAwareInterface
{
/**
* Service manager.
* #var Zend\ServiceManager\ServiceManager
*/
private $serviceManager = null;
/**
* Sets service manager.
* #param Zend\ServiceManager\ServiceManager $serviceManager Service manager.
*/
public function setServiceManager(ServiceManager $serviceManager)
{
$this->serviceManager = $serviceManager;
}
/**
* Returns service manager.
* #return type
*/
public function getServiceLocator()
{
return $this->serviceManager;
}
public function fetchSingleByRandom()
{
// Get Doctrine entity manager.
$entityManager = $this->getServiceLocator()
->get('doctrine.entitymanager.orm_default');
$advertType = 'wanted'; // This should be removed
$random = $entityManager->getRepository('Advert\Entity\Advert')
->findAdvertsByDate($advertType);
return $random;
}
}
5. Module: Advert\Module.php
public function getServiceConfig()
{
return array(
'invokables' => array(
'Advert\Service' => 'Advert\Service\LatestAdvertService',
),
);
}
public function getViewHelperConfig()
{
return array(
'factories' => array(
'latestAdvert' => 'Advert\View\Helper\LatestAdvertFactory',
),
);
}
As you can see in #4 I have a Variable called $advertType. I want to set the variable when I call the view Helper in my index.html, f.e. $this->latestAdvert('wanted'), but how can I pass this variable through all my files? I just can not find a solution for it. Does anyone got a tip for me how to achieve it? Thank you very much in advance.
!UPDATE!
As SenseException pointed out below, that injecting a service locator into a service is a bad practice and instead I should either inject repository or entity manager into the service, I have now worked out the first working solution for the entity manager.
For that I have updated 2 Files: module.php and LatestAdvertService.php
#5 module.php
public function getServiceConfig()
{
return array(
'factories' => array(
'Advert\Service' => function ($sl) {
$entityManager = $sl->get('doctrine.entitymanager.orm_default');
$myService = new Service\LatestAdvertService();
$myService->setEntityManager($entityManager);
//or you can set repository
//$repository = $entityManager->getRepository('Advert\Entity\Advert');
//$myService->setRepository($repository);
return $myService;
},
4. the Service: Advert\Service\LatestAdvertService .php
namespace Advert\Service;
use Advert\Entity\Advert as AdvertEntity;
use Doctrine\ORM\EntityManager;
class LatestAdvertService
{
public function setEntityManager(EntityManager $entityManager)
{
$this->entityManager = $entityManager;
}
public function setRepository(Repository $repository) {
$this->repository = $repository;
}
public function fetchSingleByAdvertType($advertType)
{
$random = $this->entityManager->getRepository('Advert\Entity\Advert')->findAdvertsByDate($advertType);
// $random = $this->repository->findAdvertsByDate($advertType);
return $random;
}
}
I have tried to inject the repository but get the following error message:
Argument 1 passed to Advert\Service\LatestAdvertService::setRepository() must be an instance of Advert\Service\AdvertRepository, instance of Advert\Repository\AdvertRepository given, called in
I will continue to find a solution for the repository injection and update when successful.
How about this solution:
namespace Advert\View\Helper;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
class LatestAdvertFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $serviceLocator)
{
$locator = $serviceLocator->getServiceLocator();
$service = $locator->get('Advert\Service');
$helper = new LatestAdvert($service);
return $helper;
}
}
And of course the helper class:
namespace Advert\View\Helper;
use Zend\View\Helper\AbstractHelper;
class LatestAdvert extends AbstractHelper
{
protected $service;
public function __construct($service)
{
$this->service = $service;
}
public function __invoke($advertType)
{
$latestAdverts = $this->service->fetchSingleByAdvertType($advertType);
return $latestAdverts;
}
}
And for the service:
public function fetchSingleByAdvertType($advertType)
{
$entityManager = $this->getServiceLocator()
->get('doctrine.entitymanager.orm_default');
$random = $entityManager->getRepository('Advert\Entity\Advert')
->findAdvertsByDate($advertType);
return $random;
}
I tried to keep your code as close to your original as possible but please hear some suggestions about the service locator. It is a bad practice to inject a service locator into a service like you did in LatestAdvertService. Since you only need a repository for your service, just inject that one into it. If you need the entity manager in your service, inject it instead. Your unittests will thank you.
I have installed this package https://github.com/Intervention/image with composer. I have added
'IntImage' => 'Intervention\Image\Facades\Image'
to config/app under aliases
I get the following error and cant figure out what I am doing incorrectly I am sure it has something to do with namespacing /autoloading but app/acme is in the psr-o section of composer.json
'Argument 1 passed to
Acme\Services\Images\InterventionImageEditor::__construct() must be an
instance of IntImage, none given, called in
/var/www/app/ACme/Providers/ImageEditorServiceProvider.php on line 14
and defined' in
/var/www/app/Acme/Services/Images/InterventionImageEditor.php:11
I have the following directory structure
app
acme
Providers
ImageEditorServiceProvider.php
Services
Images
ImageEditorInterface.php
InterventionImageEditor.php
and the content of the files
ImageEditorServiceProvider.php
<?php namespace Acme\Providers;
use Illuminate\Support\ServiceProvider;
use Acme\Services\Images\InterventionImageEditor;
/**
*
*/
class ImageEditorServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind('Acme\Services\Images\ImageEditorInterface', function () {
return new InterventionImageEditor();
});
}
}
ImageEditorInterface.php
<?php namespace Acme\Services\Images;
interface ImageEditorInterface
{
public function hello();
}
InterventionImageEditor.php
<?php namespace Acme\Services\Images;
use IntImage;
/**
*
*/
class InterventionImageEditor implements ImageEditorInterface
{
protected $imageeditor;
public function __construct(IntImage $imageeditor)
{
$this->imageeditor = $imageeditor;
}
public function hello()
{
$hello = 'hello';
return $hello;
}
}
Can I
Use IntImage;
in this way because it is a facade or am I missing something?
edit to include solution;
changing the service provider to the following resolved the problem
<?php namespace Acme\Providers;
use Illuminate\Support\ServiceProvider;
use Acme\Services\Images\InterventionImageEditor;
use IntImage;
/**
*
*/
class ImageEditorServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind('Acme\Services\Images\ImageEditorInterface', function () {
$intimage = new IntImage;
return new InterventionImageEditor($intimage);
});
}
}
The error is coming from ImageEditorServiceProder.php:
$this->app->bind('Acme\Services\Images\ImageEditorInterface', function () {
return new InterventionImageEditor();
});
Here you are instantiating the InterventionImageEditor without any parameters. You InterventionImageEditor requires one parameter of type IntImage.
If there are places where you won't have IntImage when instantiating InterventionImageEditor then you need to update your InterventionImageEditor::__construct so that it accepts null(possibly).
function __construct(IntImage $imageeditor = null)
{
if (is_null($imageeditor)) {
// Construct a default imageeditor
// $imageeditor = new ...;
}
$this->imageeditor = $imageeditor;
}
i am not sure you can using IntImage because this file is Facades.
if you want to extending the intervention class. you should add Intervention\Image\Image to your ImageEditorServiceProvider.
use Intervention\Image\Image;
class ImageEditorServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind('Acme\Services\Images\ImageEditorInterface', function () {
return new InterventionImageEditor(new Image);
});
}
}