Trying to use an in-memory testing database for my unit tests. It seems that it can't even run the migrations, because the migrations table does not exist.
Here is my code:
abstract class TestCase extends BaseTestCase
{
use DatabaseMigrations;
public function setUp()
{
parent::setUp();
// use testing database
$this->setUpDatabase();
}
public function setUpDatabase()
{
$this->app['config']->set('database', [
'default' => 'testing',
'connections' => [
'testing' => [
'driver' => 'sqlite',
'database' => ':memory:',
],
],
]);
}
This gives me the error:
PDOException: SQLSTATE[HY000]: General error: 1 no such table: migrations
Not only that, but it also seems to be running migrations on my main database.
Related
I recently changed the way my application connects to my PostgreSQL database to add the read/write principle. Since then, when I launch a migration I get the following error:
In Connection.php line 463:
[PDOException (42601)]
SQLSTATE[42601]: Syntax error: 7 ERROR: zero-length delimited identifier at or near """"
LINE 1: create table "" ("id" serial primary key not null, "migratio...
^
when I delete the database.php file, my migrations work correctly.
My .env
DB_CONNECTION=pgsql
DB_HOST=192.168.1.1
DB_PORT=5432
DB_DATABASE=database
DB_USERNAME=user
DB_PASSWORD=password
DB_USERNAME_READ=user
DB_PASSWORD_READ=password
My database.php
<?php
return [
'default' => env('DB_CONNECTION', 'pgsql'),
'connections' => [
'pgsql' => [
'read' => [
'username' => env('DB_USERNAME_READ'),
'password' => env('DB_PASSWORD_READ'),
],
'write' => [
'username' => env('DB_USERNAME'),
'password' => env('DB_PASSWORD'),
],
'sticky' => true,
'driver' => 'pgsql',
'host' => env('DB_HOST'),
'database' => env('DB_DATABASE'),
],
],
];
and one of my migrations:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateGameUserTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('game_user', function (Blueprint $table) {
$table->bigInteger('game_id');
$table->bigInteger('user_id');
$table->foreign('game_id')->references('id')->on('games');
$table->foreign('user_id')->references('id')->on('users');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('game_user');
}
}
PHP 7.3.13
Lumen 6.3.3
PostegreSQL 9.6.2
Lumen doesn't come with a config/database.php file by default. You can either copy a default Laravel file, or create your own with your own settings.
If you've already added your own custom file, it looks like you need to specify the migrations table name.
Default entry for Laravel is 'migrations' => 'migrations', but of course you can name it whatever you like.
I got the same problem on a Laravel 7.x project.
My solution was to remove the cache of my application then to update my dependencies via composer:
php artisan cache:clear
composer update
I want to insert data in the schema i created in laravel migration but i couldn't find a way.
Can anyone please guide ?
public function up()
{
DB::statement('CREATE SCHEMA IF NOT EXISTS reports');
Schema::create('reports.campaign_reports', function (Blueprint $table)
{
$table->bigIncrements('id');
$table->string('campaign')->nullable();
$table->string('currency')->nullable();
});
}
This is my model:
class CampaignReport extends Model
{
// protected $connection = 'schema.reports';
protected $table = 'campaign_reports';
protected $fillable = [
'campaign',
'currency'
];
}
And this is how i am saving:
CampaignReport::create((array) $dataObject);
I am getting this error:
SQLSTATE[42P01]: Undefined table: 7 ERROR: relation "campaign_reports" does not exist LINE 1: insert into "campaign_reports" ("campaign", "currency",...
Try defining a second database connection in your database config:
/** config/database.php */
// ...
'connections' => [
'public_schema' => [
'driver' => 'pgsql',
'database' => env('DB_DATABASE'),
// ...
'schema' => 'public',
],
'reports_shema' => [
'driver' => 'pgsql',
'database' => env('DB_DATABASE'),
// ...
'schema' => 'reports',
],
],
// ...
Then, set the connection in your model (this is useful to do Eloquent/Query Builder operations):
class CampaignReport extends Model
{
protected $connection = 'reports_schema'; // <----
protected $table = 'campaign_reports';
protected $fillable = [
'campaign',
'currency'
];
// ...
}
Of course, when you make your migration that needs to be run in a different connection than the default, you have to specify it:
public function up()
{
DB::statement('CREATE SCHEMA IF NOT EXISTS reports');
Schema::connection('reports_schema')->create('campaign_reports', function (Blueprint $t)
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^
{
$t->bigIncrements('id');
$t->string('campaign')->nullable();
$t->string('currency')->nullable();
});
}
Btw, update your .env default database key to this:
DB_CONNECTION=public_schema
I have an issue with running migrations while making a test. I have migrations in different places. User migrations depend on Company migrations but each time I run tests I have an error that table 'companies' doesn't exist.
Code from test class:
protected function setUp()
{
parent::setUp();
$this->artisan('migrate', [
'--path' => ['Modules/Company/Database/Migrations',
'Modules/User/Database/Migrations'],
]);
}
protected function tearDown()
{
$this->artisan('migrate:reset', [
'--path' => ['Modules/User/Database/Migrations',
'Modules/Company/Database/Migrations'],
]);
parent::tearDown();
}
Can anyone help me, please.
Thanks!
Problem was in two places:
1) option --path was provided as an array(but no warnings are displayed);
2) command migrate:reset(it resets ALL the migrations using provided --path so the error 'Undefined index: create_company_table' happens).
Final version.
protected function setUp()
{
parent::setUp();
$this->artisan('migrate', [
'--path' => 'Modules/Company/Database/Migrations',
]);
$this->artisan('migrate', [
'--path' => 'Modules/User/Database/Migrations',
]);
}
protected function tearDown()
{
$this->artisan('migrate:rollback', [
'--path' => 'Modules/User/Database/Migrations/',
]);
$this->artisan('migrate:rollback', [
'--path' => 'Modules/Company/Database/Migrations/',
]);
parent::tearDown();
}
I am trying to get a ServiceManager instance in my controller to use a factory for Db\Adapter.
I added to module/Application/config/module.config.php:
'service_manager' => [
'factories' => [
Adapter::class => AdapterServiceFactory::class,
],
],
To config/autoload/local.php I added the following lines:
'db' => [
'driver' => 'Mysqli',
'database' => 'mydb',
'username' => 'myuser',
'password' => 'mypassword',
]
An now I want to access the ServiceManager in my module/Application/src/Controller/IndexController.php. How do I do that?
I tried $sm = $this->getPluginManager(); without success. If I run $serviceManager->get(Adapter::class) with the PluginManager it gives me an error:
Too few arguments to function Zend\Db\Adapter\Adapter::__construct(), 0 passed in (...)\vendor\zendframework\zend-servicemanager\src\Factory\InvokableFactory.php on line 30 and at least 1 expected
What can I do, to get a ServiceManager that will get my that Adapter object?
I changed the controller factory from
'controllers' => [
'factories' => [
Controller\IndexController::class => InvokableFactory::class,
],
],
to
'controllers' => [
'factories' => [
Controller\IndexController::class => function(ContainerInterface $serviceManager) {
return new Controller\IndexController($serviceManager);
},
],
],
I also added a getServiceConfig() method to the module.config.php and added a constructor to the IndexController, which receives the ServiceManager. Now I have access inside the controller.
But my question is now: is there a nicer, a more "zend like" way to achieve this?
Thanks to SO's great related topics I finally found the answer. ServiceManager in ZF3
It seems to be done by using Controller Factories, almost like I did.
I'm experienced with ZF1 and now I'm learning ZF3, I wanted to do a simple thing: set the DB configuration in the configuration file, and then get the db adapter at the controller. It took me awhile to figure it out as the official documents have millions of options for different customization. So I'm posting my answer to help anyone looking.
1- Add the db credentials in config/autoload/global.php or config/autoload/local.php, like this:
<?php
return [
'db' => [
'driver' => 'Pdo_Mysql',// can be "Mysqli" or "Pdo_Mysql" or other, refer to this link for the full list: https://docs.zendframework.com/zend-db/adapter/
'hostname' => 'localhost',// optional
'database' => 'my_test_db',
'username' => 'root',
'password' => 'root',
],
];
2- In module/YOUR_MODULE_NAME/config/module.config.php, add this under the controllers factories section:
return [
//...
'controllers' => [
'factories' => [
//...
// Add these lines
Controller\MycontrollernameController::class => function($container) {// $container is actually the service manager
return new Controller\MycontrollernameController(
$container->get(\Zend\Db\Adapter\Adapter::class)
);// this will pass the db adapter to the controller's constructor
},
//...
]
]
//...
];
3- Finally, in your controller module/YOUR_MODULE_NAME/src/Controller/MycontrollernameController, you can get and use the db adapter:
<?php
namespace Application\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Zend\Db\Adapter\Adapter;
class MycontrollernameController extends AbstractActionController
{
private $db;
public function __construct($db)
{
$this->db = $db;
}
public function indexAction()
{
$result = $this->db->query('SELECT * FROM `my_table`', Adapter::QUERY_MODE_EXECUTE);
echo $result->count();// output total result
return new ViewModel();
}
}
There is another way to achieve the same thing by creating a factory for your controller, and inside that factory pass the db adapter to the controller. For beginners trying out ZF3 at hello-world level like me, I think that's too much.
I am new to Zend Framework 3 and I am doing this tutorial:
I have a xampp, mysql setup.
I have done everything exactly like in this tutorial. Now I am at the point where you configure the database connection. Further I have set up the controller and view.
In the tutorial link above , they are using php to create a database and then in config/autoload/global.php.....the following code:
return [
'db' => [
'driver' => 'Pdo',
'dsn' => sprintf('sqlite:%s/data/zftutorial.db', realpath(getcwd())),
],
];
I have edited this to:
'db' => [
'driver' => 'Pdo_Mysql',
'dsn' => 'mysql:dbname=dbname;host=localhost;charset=utf8;username=myuser;password=mypassword',
],
When I call the url for the index view, there the following error:
Warning: Creating default object from empty value in C:\xampp\htdocs\zendtest\module\Album\src\Controller\AlbumController.php on line 15
Fatal error: Call to a member function fetchAll() on null in
C:\xampp\htdocs\zendtest\module\Album\src\Controller\AlbumController.php
on line 22
The AlbumController:
<?php
namespace Album\Controller;
use Album\Model\AlbumTable;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
class AlbumController extends AbstractActionController {
private $table;
public function __construct(AlbumTable $table)
{
$this->table = $table;
}
public function indexAction()
{
return new ViewModel([
'albums' => $this->table->fetchAll(),
]);
}
}
I think that the connection doesn't work??
can you share your "AlbumControllerFactory.php" ?
if you have not yet created the factory you should do.
1 - Create AlbumControllerFactory that implements FactoryInterface
2 - Inside __invoke function use the Container to inject AlbumTable to your controller
3 - config your mapping in module.config.php
'controllers' => [
'factories' => [
Controller\AlbumController::class => Controller\Factory\AlbumControllerFactory::class,
All simple, you have mistake in key $this, you did write $htis instead )