I am storing a string in database that I want to access from various places in my application. I figure out that the best solution will be create a function that is taking that string from database and register it as a service.
Function:
public function shopUrlAction()
{
return new Response($this->getDoctrine()->getRepository('AppBundle:Settings')->find(1)->getName());
}
service.yml
services:
app.default_controller:
class: AppBundle\Controller\DefaultController
output in other controller:
$return['base_url'] = $this->forward('app.default_controller:shopUrlAction');
Unfortunately I am constantly getting
CRITICAL - Uncaught PHP Exception
Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException:
"You have requested a non-existent service "app.default_controller"."
at /app/bootstrap.php.cache line
2099 Context:
{"exception":"Object(Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException)"}
I've cleared cache.
As I see from your question you have service.yml instead of services.yml (in plural form).
You should include your service.yml in main config.yml in imports section or use standard path to it (AppBundle/Resources/config/services.yml)
Related
We have memcache on our Symfony 3.4 app:
cache:
app: cache.adapter.memcached
default_memcached_provider: "%app.memcached.dsn%"
However, we've been asked to use several cache servers, so just passing one DSN is no good.
Looking here (https://symfony.com/blog/new-in-symfony-3-3-memcached-cache-adapter), I see you can create it in code like this:
$client = MemcachedAdapter::createConnection(array(
// format => memcached://[user:pass#][ip|host|socket[:port]][?weight=int]
// 'weight' ranges from 0 to 100 and it's used to prioritize servers
'memcached://my.server.com:11211'
'memcached://rmf:abcdef#localhost'
'memcached://127.0.0.1?weight=50'
'memcached://username:the-password#/var/run/memcached.sock'
'memcached:///var/run/memcached.sock?weight=20'
));
However, that isn't autowired.
I believe we need to either make a provider class, or somehow get it to make calls to addServer($dsn), once instantiated. I also saw the following on random posts:
memcache:
class: Memcached
calls:
- [ addServer, [ %app.memcached.dsn.1% ]]
- [ addServer, [ %app.memcached.dsn.2% ]]
However it isn't really helping or I have missed something out.
Can anyone help? How do I create this provider class?
You can copy above code snippet as a service configuration to your services.yaml, which probably roughly looks like this:
# app/config/services.yaml
services:
app.memcached_client:
class: Memcached
factory: 'Symfony\Component\Cache\Adapter\MemcachedAdapter::createConnection'
arguments: [['memcached://my.server.com:11211', 'memcached://rmf:abcdef#localhost']]
app.memcached_adapter:
class: Symfony\Component\Cache\Adapter\MemcachedAdapter
arguments:
- '#app.memcached_client'
Then in your configuration you should be able to reference the adapter using the client created by the factory, e.g. something like:
# app/config/config.yaml
framework:
cache:
app: app.memcached_adapter
You might also be able to overwrite the default alias cache.adapter.memcached instead of having your own adapter.
Your approach using Memcached::addServer might work as well, but just like with MemcachedAdapter::createConnection this will return the Client, which needs to be passed to the cache adapter. That's why there is a second service app.memcached_adapter, which is used in the cache configuration.
Please be aware that I have not tested this, so this is rather a rough outline than a fully working solution,
For one of my projects running Symfony 3.4 the configuration was simpler:
Create a service that will be used as a client:
app.memcached_client:
class: Memcached
factory: ['AppBundle\Services\Memcached', 'createConnection']
arguments: ['memcached://%memcache_ip%:%memcache_port%']
The AppBundle\Services\Memcached can have all the custom logic I need like so:
class Memcached
{
public static function createConnection($dns)
{
$options = [
'persistent_id' => 'some id'
];
// Some more custom logic. Maybe adding some custom options
// For example for AWS Elasticache
if (defined('Memcached::OPT_CLIENT_MODE') && defined('Memcached::DYNAMIC_CLIENT_MODE')) {
$options['CLIENT_MODE'] = \Memcached::DYNAMIC_CLIENT_MODE;
}
return \Symfony\Component\Cache\Adapter\MemcachedAdapter::createConnection($dns, $options);
}
}
And then I used that service in my config.yml:
framework:
cache:
default_memcached_provider: app.memcached_client
I am working on my first Symfony based WebApp project. I have configured Symfony to not only write log messages to the different log files but also to send critical error messages immediately as e-mail. This works fine. However I would like to add some additional information to the default log messages to make it easier to find the actual error source.
Example:
The Twig file of one pages loads the localized text from a .yml file. The texts contains an %about_link%placeholder that should be replaced by the route/URL to the About page. I forgot to this replacement, so the link did not point to an URL but to %about_link% instead. This leads to an NotFoundHttpException since no rout to %about_link% can be found...
No big deal. But to find the actual page/controller that contains this error was a bit tricky. The default log message shows the following:
[2015-12-14 17:19:36] request.ERROR: Uncaught PHP Exception Symfony\Component\HttpKernel\Exception\NotFoundHttpException: "No route found for "GET /%25about_link%25"" at /long/path/to/symfony/.../RouterListener.php line 176 []
So the exception was thrown in RouterListener.php when trying to find a route to %about_link%. Fine, this does not give me any hint on which page this bad link is located.
Of course the call to the bad route does not have to be located on any page at all. The user could have entered the bad link directly. Symfony would have to store/remember the last page to give any hint about the possible source. So, is it possible to include this information at all?
Additionally I would like to add information about the Host the problem was reported on. I am running two instances of the WebApp: www.my_web_app.xy and betatest.my_web_app.xy and it would be a great help, if the log message would show if it comes from www or from betatest.
Adding this information to log messages I create on myself is no problem, but how can I add this information to messages generated by Symfony or third party code? I would have to intercept the log message somehow before it reaches the log handler. Is this possible?
If you want to add extra information to log entries, you can do this with a processor. With a processor you can modify the record array, before it's parsed by a formatter. The extra part is shown at the end of the log entry.
<?php
namespace AppBundle\Monolog;
use Symfony\Component\HttpFoundation\RequestStack;
class WebProcessor
{
private $requestStack;
public function __construct(RequestStack $requestStack)
{
$this->requestStack = $requestStack;
}
public function processRecord(array $record)
{
$request = $this->requestStack->getCurrentRequest();
if ($request) {
$record['extra']['host'] = $request->getHost();
$record['extra']['url'] = $request->getRequestUri();
// ...
}
return $record;
}
}
Now add it to your services.yml to register it for all log entries:
app.monolog.processor.web:
class: AppBundle\Monolog\WebProcessor
arguments: ["#request_stack"]
tags:
- { name: monolog.processor, method: processRecord }
Don't reinvent the wheel! There is no need to write your own WebProcessor, since Monolog already has it.
The only thing you have to do is add it to your services and tag it with monolog.processor:
# app/config/services.yml
services:
Monolog\Processor\WebProcessor:
tags: ['monolog.processor']
Monolog has even more built-in processors you can use. I decided to add multiple processors in my application:
# app/config/services/monolog.yml (I included services/*.yml in config.yml)
services:
_defaults:
tags: ['monolog.processor']
Monolog\Processor\WebProcessor: ~
Monolog\Processor\GitProcessor: ~
Monolog\Processor\MemoryUsageProcessor: ~
Monolog\Processor\MemoryPeakUsageProcessor: ~
Monolog\Processor\IntrospectionProcessor: ~
You can use a custom formatter to change the output written to the monolog log files. You can find more information about this subject here: http://symfony.com/doc/current/cookbook/logging/monolog.html#changing-the-formatter
Short version: you can create a custom formatter class that implements Monolog\Formatter\FormatterInterface and you can enable it in your config.yml file this way:
# app/config/config.yml
services:
my_formatter:
class: Monolog\Formatter\JsonFormatter
monolog:
handlers:
file:
type: stream
level: debug
formatter: my_formatter
I have follow all the steps related to Symfony installation, and I try the examples of the Symfony book (provided by the Symfony web site). Currently I am on Controllers chapter (5) and I try the following code:
namespace MyBundle\FrontBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class HelloController extends Controller
{
public function indexAction($name, Request $request)
{
return $this->redirect($this->generateUrl('front_buy'), 301);
}
public function buyAction(Request $request)
{
return $this->render(
'Hello/buy.html.twig',
array(
'name' => 'Nikos'
)
);
}
}
but I get the following error:
INFO - Matched route "front_buy" (parameters: "_controller": "MyBundle\FrontBundle\Controller\HelloController::buyAction", "_route": "front_buy")
CRITICAL - Uncaught PHP Exception InvalidArgumentException: "Unable to find template "Hello/buy.html.twig"." at /var/www/projects/symfony/vendor/symfony/symfony/src/Symfony/Bridge/Twig/TwigEngine.php line 128
Context: {"exception":"Object(InvalidArgumentException)"}
I know is not something fancy, but I don't know how to fix the problem.
My view file is under the following path : ./src/MyBundle/FrontBundle/Resources/views/Hello/buy.html.twig.
You need to render it with the following syntax:
$this->render('AcmeBlogBundle:Blog:index.html.twig')
or with this syntax
$this->render('#BlogBundle/Blog/index.html.twig')
An Example:
$this->render('#FrontBundle/Hello/buy.html.twig)
More information can be found on the documentation, also refering to symfonys best practices templates should be stored in app/Ressources/views
in "app/config/config.yml" be sure to have this:
framework:
# ...
templating:
engines: ['twig']
In my case, the problem was really related to the specific version of Symfony.
My project used to be run with Symfony 2.8.19. I tried to migrate it to another Linux
evironment (uning symfony2.8.42) and then I got the very same error with the same code (very wierd).
I tried the solutions mentioned before and none worked like using :
$this->render('#BlogBundle/Blog/index.html.twig')
or
$this->render('AcmeBlogBundle:Blog:index.html.twig').
After several tries, I found the problem. In fact, in my old env, I had :
return $this->render('XxxxxBundle:Default:zzzz.html.twig';
But the problem was with Capitalized Default because the real path was with an uncapitalized default
so changing it to the following fixed the problem in my new env:
return $this->render('XxxxxBundle:default:zzzz.html.twig';
I looked up some solutions, but none of the found fit my problem.
In one controller i create an instance of another controller
//Controller1
$mailController = new MailController();
$mailController->newCommentMail($entity, $em);
In the MailController i want to generate an URL and send an email
$url = $this->generateUrl('path', array('turnId' => $data->getPoi()->getId(), 'poiId' => $data->getPoi()->getTurn()->getId()));
$this->get('mailer')->send($mail);
This two lines are throwing the following error:
Error: Call to a member function get() on a non-object
But my IDE indentifies that $this is an instance of a controller.
Is there a problem with generating an instance of a Controller like that or what am i doing wrong?
You can define your controller as service, then get it in another controller.
In your services.yml define needed controller as a service:
services:
your_service_name:
class: YourCompany\YourBundle\Controller\YourController
Then in any controller you'll be able to get this service via container:
$yourController = $this->get('your_service_name');
There is some useful information about Controllers as Services in documentation
Note from OP
This answer is totally right, i just want to add something so this Answer works to 100% fine!
After i changed the Controller to a Service the service container was missing, refering to this Question here.
To set the container, and with that the fully funcionality of SF2, you need to add one line to the service.yml
services:
mail_controller:
class: YourCompany\YourBundle\Controller\YourController
calls:
- [ setContainer, [ #service_container ]]
$this->container->get('mailer');
works?
faced this issue...but adding this in the controller service solved it for me
calls:
- [setContainer, ["#service_container"]]
I want to create a custom route loader as instructed in http://symfony.com/doc/current/cookbook/routing/custom_route_loader.html.
What I have to do is read the read the routes from an xml file (not in "symfony xml" format) and create the according route collection.However I want to do that using the '#' directive.as in:
xmlRoutes:
resource: '#FooBarBundle/Resources/routes.xml'
But in order to resolve the path to routes.xml I need the 'file_locator' service from the container.is it possible to access services in a custom router class.if not, how can I make a symfony\Component\Config\FileLocator to resolve that path?
Yes you could access the file_locator as it's a service. What you need to do is make your custom_route_loader a service itself (I dind't read the cookbook you linked but I'm pretty sure that they would advice to define it as a service) and inject the file_locator service into it.
So basically you'll do something like
#config.yml
[...]
services:
yourbundlename.custom_route_loader:
class: Path\To\Your\Bundle\CustomRouteLoader
arguments: [ #file_locator ]
And into you CustmRouteLoaderClass
#Path\To\Your\Bundle\CustomRouteLoader
class CustomRouteLoader
{
public function __construct(Symfony\Component\HttpKernel\Config\FileLocator $file_locator) {
$this->file_locator = $file_locator;
[...]
}
[...]
}