New project using Symfony 4 with MongoDB / service not found - mongodb

I'm trying to create a new Symfony4 project with MongoDB.
First I created a Symfony4 project using this documentation:
https://symfony.com/doc/current/setup.html
Then I included MongoDB using this documentation:
http://symfony.com/doc/current/bundles/DoctrineMongoDBBundle/index.html
I tried to follow the instructions as exactly as possible (for example I didn't need to add anything to app/AppKernel.php, but MongoDB was automatically added to config/bundles.php).
Now I think everything should work, but my Symfony app doesn't find the MongoDB Service:
You have requested a non-existent service "doctrine_mongodb".
Did you mean one of these: "http_kernel", "request_stack", "router"?
in ServiceLocator.php (line 48)
Controller:
namespace App\Controller;
use App\Document\Chapter;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
class DefaultController extends AbstractController {
public function createAction() {
$test = new Chapter();
$test->setHeadline('Test');
$dm = $this->get('doctrine_mongodb')->getManager();
$dm->persist($test);
$dm->flush();
return new Response('Created product id '.$test->getId());
}
}
However, If I execute this on the console:
php bin/console debug:container
I get a list of services including these:
doctrine_mongodb Doctrine\Bundle\MongoDBBundle\ManagerRegistry
doctrine_mongodb.odm.default_connection Doctrine\MongoDB\Connection
doctrine_mongodb.odm.default_document_manager Doctrine\ODM\MongoDB\DocumentManager
doctrine_mongodb.odm.document_manager alias for "doctrine_mongodb.odm.default_document_manager"
So the service seems to be there, but Symfony can't load it from my app.
Any idea how I could solve this?
Is it possible that the Mongo-DB Server connection doesn't work and for some reason it isn't logged and the service just won't load?

You could use autowiring
use Doctrine\ODM\MongoDB\DocumentManager as DocumentManager;
and
public function createProduct(DocumentManager $dm)

Try extending from "Controller" instead "AbstractController".
class DefaultController extends Controller

Related

Custom mail driver in Laravel 8

I'm using a custom mail driver with Laravel 8. It's good to work with direct mailing. But after using it should queue, an issue was found.
"Target class [mail.manager] does not exist."
I have already registered at config/app.php for customMailServiceProvider. The problem is only for when using shouldqueue at Notifications with mail. Any ideas or any suggestions? I was following the instruction for the following article.
https://www.delenamalan.co.za/2020/laravel-custom-mail-driver.html#create-a-custom-mail-transport-class
Add This code line at app/bootstrap.php
$app->alias('mail.manager', Illuminate\Mail\MailManager::class);
This is worked for me. Laravel Queue don't know the facades name "mail.manager".
Don't forget to run compose dump after code update.
In Providers/CustomMailServiceProvider.php change from:
class CustomMailServiceProvider extends ServiceProvider
{
to
class CustomMailServiceProvider extends MailServiceProvider
{

Eloquent error: A facade root has not been set

I have been using Eloquent as a standalone package in Slim Framework 2 successfully.
But now that I want to make use of Illuminate\Support\Facades\DB since I need to show some statistics by getting the info from 2 tables and using a Left Join and a Counter from the database like this:
use Illuminate\Support\Facades\DB;
$projectsbyarea = DB::table('projects AS p')
->select(DB::raw('DISTINCT a.area, COUNT(a.area) AS Quantity'))
->leftJoin('areas AS a','p.area_id','=','a.id')
->where('p.status','in_process')
->where('a.area','<>','NULL')
->orderBy('p.area_id');
I get the following error:
Type: RuntimeException
Message: A facade root has not been set.
File: ...\vendor\illuminate\support\Facades\Facade.php
Line: 206
How can I solve it?
So far I have found out, in this link that I need to create a new app container and then bind it to the Facade. But I haven't found out how to make it work.
This is how I started the rest of my Eloquent and working fine:
use Illuminate\Database\Capsule\Manager as Capsule;
$capsule = new Capsule();
$capsule->addConnection([
'my' => $app->config->get('settings'),
/* more settings ...*/
]);
/*booting Eloquent*/
$capsule->bootEloquent();
How do I fix this?
Fixed
As #user5972059 said, I had to add $capsule->setAsGlobal();//This is important to make work the DB (Capsule) just above $capsule->bootEloquent();
Then, the query is executed like this:
use Illuminate\Database\Capsule\Manager as Capsule;
$projectsbyarea = Capsule::table('projects AS p')
->select(DB::raw('DISTINCT a.area, COUNT(a.area) AS Quantity'))
->leftJoin('areas AS a','p.area_id','=','a.id')
->where('p.status','in_process')
->where('a.area','<>','NULL')
->orderBy('p.area_id')
->get();
You have to change your code to:
$Capsule = new Capsule;
$Capsule->addConnection(config::get('database'));
$Capsule->setAsGlobal(); //this is important
$Capsule->bootEloquent();
And at the beginning of your class file you have to import:
use Illuminate\Database\Capsule\Manager as DB;
I have just solved this problem by uncommenting $app->withFacades(); in bootstrap/app.php
Had the same issue with laravel 8. I replaced
use PHPUnit\Framework\TestCase;
with:
use Tests\TestCase;
Try uncommenting in app.php $app->withFacades();
Do not forget to call parent::setUp(); before.
fails
public function setUp(): void {
Config::set('something', true);
}
works
public function setUp(): void {
parent::setUp();
Config::set('something', true);
}
One random problem using phpUnit tests for laravel is that the laravel facades have not been initialized when testing.
Instead of using the standard PHPUnit TestCase class
class MyTestClass extends PHPUnit\Framework\TestCase
one can use
class UserTest extends Illuminate\Foundation\Testing\TestCase
and this problem is solved.
I got this error after running:
$ php artisan config:cache
The solution for me was to delete the /bootstrap/cache/config.php file. I'm running Laravel 5.5.
The seems to arise in multiple situation, and not just about facades.
I received the following message while running tests using PHPUnit v.9.5.4, PHP v.8.0.3 and Lumen v. 8.2.2:
PHP Fatal error: Uncaught RuntimeException: A facade root has not
been set. in path_to_project/vendor/illuminate/support/Facades/Facade.php:258
And that happened although I had apparently already configured my app.php to enable facades ($app->withFacades();), still I received this error message whenever I tried to run tests using Illuminate\Support\Facades\DB. Unfortunately, none of the other answers helped me.
This error was actually been thrown due to my configs in phpunit.xml, which didn't point to my app.php file, where I actually enabled facades.
I just had to change
<phpunit (...OTHER_PARAMS_HERE) bootstrap="vendor/autoload.php">
to
<phpunit (...OTHER_PARAMS_HERE) bootstrap="bootstrap/app.php">
Hope it helps.
wrong way
public function register()
{
$this->app->bind('Activity', function($app)
{
new Activity;
});
}
right way 👍
public function register()
{
$this->app->bind('Activity', function($app)
{
return new Activity;
});
}
---------------------------------- don't forget return
Upgrade version for php, I encountered this error while calling the interface.
$ php artisan config:cache
Deleting the /bootstrap/cache/config.php file is a very effective way.
In my project, I managed to fix this issue by using Laravel Dependency Injection when instantiating the object. Previously I had it like this:
$class = new MyClass(
new Client(),
env('client_id', 'test'),
Config::get('myapp.client_secret')
);
The same error message happened when I used Laravel env() and Config().
I introduced the Client and env in the AppServiceProvider like this:
$this->app->bind(
MyClass::class,
function () {
return new MyClass(
new Client(),
env('client_id', 'test')),
Config::get('myapp.client_secret')
);
}
and then instantiated the class like this:
$class = app(MyClass::class);
See more from https://laravel.com/docs/5.8/container .
In my case, for a while a ran a PHP project in PHP version 8, and that time I used some PHP 8 features like param definition and method's multiple return type declarations supported by only PHP 8 and above. When I downgraded from PHP 8 to PHP 7.4 I faced this issue. After removing the return types and param hinting the problems are gone.
Tested on Laravel 8.78
tests/bootstrap.php
<?php
use Illuminate\Foundation\Bootstrap\RegisterFacades;
use Illuminate\Foundation\Bootstrap\LoadConfiguration;
require_once __DIR__ . '/../vendor/autoload.php';
$app = require_once __DIR__ . '/../bootstrap/app.php';
(new LoadConfiguration())->bootstrap($app);// <------- Required for next line
(new RegisterFacades())->bootstrap($app);// <------- Add this line
Here is yet another instance of this error, happened to me after upgrading Laravel 8 to 9.
I had feature tests with a #dataProvider to supply data to those tests. Some of the data supplied by the data provider methods came from an application service. It was being initialised like this:
/**
* #dataProvider myDataProvider
*/
public function testSomeStuff(...)
{
...
}
public function myDataProvider()
{
$myService = app(Service::class); // This is trouble
return [
['test1_data' => $myService::SOME_CONSTANT],
[...],
...
];
}
This worked under Laravel 8, but not in Laravel 9. All other solutions listed in this SO thread were checked and were correctly set up.
The problem is that the application is not being inititialised until after the data provider method is run. It was presumably initialised before this stage in the Laravel 8 install. So app(Service::class) was failing due to it using facades internally.
One workaround could be to force the application to initialise earlier, in the data provider function: $this->createApplication(). I would not recommend this due to potential side effects of the test parts running in the wrong order, though it does appear to work when I tried it.
Best solution is to avoid accessing any part of the application functionality in the data provider methods. In my case it was easy to replace $myService::SOME_CONSTANT with MyService::SOME_CONSTANT after making sure those constants were public.
Hopefully this will help somebody suddenly hitting this problem running feature tests after a Laravel 9 upgrade.
If you recently upgrade Laravel on Homestead & VirtualBox environment or do not find any reason that causing please be sure your Vagrant is up to date.
Referance
I had Taylor lock this thread. The past several replies have restated the solution, which is to Upgrade to Virtualbox 6.x, the thread is locked to prevent other issues that are not related from being dogpiled on here.
#melvin's answer above works correctly.
In case someone is wondering about it, the mistake people do is to choose Yes when VSCode asks them if they are making a Unit Test. Remember, Unit Tests should really be unit tests, independent of other application features (models, factories, routes; basically anything that would require the Laravel app to be fired up). In most scenarios, people really actually want to make Feature Tests and therefore should answer No to the above question. A feature test inherits from Tests\TestCase class (which takes care of firing up Laravel app before running the test) unlike unit tests that inherit from the class PHPUnit\Framework\TestCase which use just PHPUnit and are therefore much faster.
credit with thanks to #Aken Roberts's answer here.
From Laravel Documentation: Generally, most of your tests should be feature tests. These types of tests provide the most confidence that your system as a whole is functioning as intended.

Yii2 mongodb Query class not found

I am trying MongoDB integration with Yii2. I tried following the instructions at https://github.com/yiisoft/yii2-mongodb but I can't seem to get it to work:
public function actionSearch($sku) {
$query = new Query;
// compose the query
$query->select()
->from('products')
->where(['skus.sku' => $sku]);
$product = $query->all();
return $this->render('product', $product);
}
My use declarations are as follows:
namespace app\controllers;
use Yii;
use yii\mongodb\Query;
use yii\filters\AccessControl;
use yii\web\Controller;
use yii\filters\VerbFilter;
use app\models\LoginForm;
The above results in:
Class 'yii\mongodb\Query' not found
Issue was reported to yii2 issue tracker and resolved there:
Application's composer.json (basic/composer.json) did not contain the "yiisoft/yii2-mongodb": "*" line in the require section. Adding it and running composer update helped resolve the issue.

Apply default mapping to mock Mongo domains in Grails unit test

I've started using the new mocking support in grails-datastore-gorm-mongodb. My app defaults domain mappings to use references when persisting relationships to mongodb. I need to find a way to get the mocked mongo to do the same thing. How do I apply the same default mapping in a unit test?
In Config.groovy, it looks like this:
// configure mongo to use dbrefs:
grails.mongo.default.mapping = {
'*'(reference: true)
}
Here's a sample of code that I currently use:
import spock.lang.*
import grails.test.mixin.mongodb.MongoDbTestMixin
import com.github.fakemongo.Fongo
#Mixin([MongoDbTestMixin])
class MySpec extends Specification {
def setup() {
mongoDomain(new Fongo("test").mongo, [ MyDomain ])
new MyDomain(name: 'domain').save(validate: false, flush: true)
}
}
How do I apply that config to this test code?
I'm using Grails 2.3.9 and mongodb 3.0.1 plugin.
Looks like MongoDbTestMixin offers a few flavors of the mongoDomain method:
mongoDomain(Mongo mongo, Collection<Class> persistentClasses) - Sets up a GORM for MongoDB domain for the given Mongo instance and domain classes
mongoDomain(Map config, Collection<Class> persistentClasses) - Sets up a GORM for MongoDB domain for the given configuration and domain classes
The 2nd option allows to pass a configuration map which allows to configure mongo to use dbrefs (otherwise an empty configuration is used, see MongoDbDataStoreSpringInitializer ). However this method does not allow you to pass the Fongo instance.
You can try to:
Ask the Grails team to add a method which combines both options (pull request?)
Extend MongoDbTestMixin or create your own mixin

Accessing the DI container from anywhere

I've implemented the Symfony2 Dependency Injection container in my Zend Framework project and it works fine in the MVC layer of my application. I've initialized the DIC in my bootstrap and can access it anywhere by calling:
Zend_Controller_Front::getInstance()->getParam('bootstrap')->getDic()
The problem is that there are some parts of my application that do not utilize the Zend Framework application/MVC layer. My CLI tools for example. I could perfectly initialize a new DIC there but that would just be some copy paste work from the Bootstrap file which is asking for trouble down the road (DRY principles, etc)
Is it a better solution to make my DIC available in the Zend_Registry or as a singleton called by a static method DIC::getInstance() for example?
I know Registry and singletons are considered bad things but the DIC is such a high level part of the application that I will probably never run into the problems that make it a bad thing.
Is this a good solution or are there better ways of accomplishing a globally accessible DIC?
I achieved this in the past using Pimple (created by Fabien Potencier, owner of Symfony).
Pimple is a small Dependency Injection Container for PHP 5.3 that consists of just one file and one class (about 50 lines of code).
Here is how I coupled it with my ZF1 application:
Create a new Pimple container into your application's bootstrap
Declare all your services with proper dependencies
Access the DIC through your controllers or CLI tools
Access the services through the DIC
If your services are well declared (injecting dependencies through their constructors) you shouldn't have to access the DIC outside your controllers or CLI tools.
Use a base controller class to easily access the DIC through $this->container:
abstract class MyApp_Controller_Action extends Zend_Controller_Action
{
protected $container;
public function init()
{
$this->container = Zend_Controller_Front::getInstance()
->getParam('bootstrap')->getDic();
}
}
In order to use your DIC into your CLI tools:
Extend Zend_Application to create your CLI application
Override run() to prevent the MVC stack to bootstrap
When creating your CLI tool inject the DIC through its constructor
Use a base command class to easily access the DIC through $this->container:
abstract class MyApp_Command
{
protected $container;
public function __construct($container)
{
$this->container = $container;
}
}
To have access to your bootstrap ressources in your CLI file you can go and do a partial bootstrapping of your application
Instead of doing this (public/index.php) and bootstraping your whole application :
$application = new Zend_Application(
APPLICATION_ENV,
APPLICATION_PATH . '/configs/application.ini'
);
$application->bootstrap()
->run();
You can do this and only bootstrap the required resouces :
$app = new Zend_Application(
APPLICATION_ENV,
APPLICATION_PATH . '/configs/application.ini'
);
// Selectively bootstrap resources:
$app->bootstrap('db');
$app->bootstrap('log');
$app->bootstrap('autoload');
$app->bootstrap('config');
$app->bootstrap('di');
You have to make sure that you initialize them in the right order (you might need to have your DB loaded before the logging component if you have a DB writter for your logs for example).
From there, you can call parts of your bootstrap (for the DI component, you can call the $app->getBootstrap()->getContainer(). You have access to all methods available in your bootstrap.