Laravel - periodically pulling from a database table - php

In Laravel, I have a table of articles which I pulled from a database at the start of my project over a month ago.
This database is separate from my Laravel application but the content may change daily and I've been manually grabbing the content every three days, which as you can imagine takes time.
I've seen that you can have two database connects in Laravel, like so:
<?php
return array(
'default' => 'mysql',
'connections' => array(
# Our primary database connection
'mysql' => array(
'driver' => 'mysql',
'host' => 'host1',
'database' => 'database1',
'username' => 'user1',
'password' => 'pass1'
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
),
# Our secondary database connection
'mysql2' => array(
'driver' => 'mysql',
'host' => 'host2',
'database' => 'database2',
'username' => 'user2',
'password' => 'pass2'
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
),
),
);
So, If I have my secondary article table that I can connect to is it possible to create a cron job that pulls in new content to my Laravel application every hour?
When pulling from the secondary database, how could I avoid overwriting content?

You can define a model for the secondary database like this
namespace App\Secondary;
class Article extends Model {
protected $connection = 'mysql2';
public static function fetchArticles(){
//fetch articles
//TODO all other filter to fetch new records
$articles = Article::all();
return $articles;
}
}
How to avoid overwrite content?
if you have id or any identity column in both primary and secondary connection db table then just fetch the latest article id from primary connection article table and fetch new articles after that id from secondary db table.
Here is the scheduler class
namespace App\Console\Commands;
use Illuminate\Console\Command;
class ArticlePuller extends Command
{
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'articlePuller';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Pull article from secondary database';
/**
* Execute the console command.
*
* #return mixed
*/
public function handle()
{
$articles = Secondary/Article::fetchArticles(); //from secondary db table
Article::insertArticles($articles);
}
}
Define this scheduler in console/Kernel.php
protected $commands = [
Commands\ArticlePuller::class
];
protected function schedule(Schedule $schedule)
{
$schedule->command('articlePuller')->hourly();
}
Now need to add this scheduler entry in cron job
* * * * * php path_to_artisan/artisan schedule:run >> /dev/null 2>&1

Related

How do I connect to a 2nd database entered by parameter in the console? Laravel

I'm entering by parameter in the console on behalf of the database to just do data import. The issue is that I can find the database but I can't connect to see its tables and extract some data.
Database file
'searchDB' => [
'driver' => 'mysql',
'url' => env('DATABASE_URL'),
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => '',
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'prefix_indexes' => true,
'strict' => true,
'engine' => null,
'options' => extension_loaded('pdo_mysql') ? array_filter([
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
]) : [],
],
Comand file
$database = $this->argument('database'); //Name database old
foreach (DB::select('SHOW DATABASES') as $db) {
if($db->Database === $database){
Config::set('database.connections.searchDB.database', $database); //NOT WORKING
$tables = DB::select('SHOW TABLES')->connection('searchDB'); //NOT WORKING
foreach($tables as $table) {
$tableNames[$database][] = $table;
}
}
}
dd($tables);//RETURNS THE CURRENT DATABASE.
Supply the connection to the query builder before running a query
$tables = DB::connection('searchDB')->select('SHOW TABLES'); // NOW WORKING
This is working for me
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\DB;
class StackOverflow extends Command
{
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'overflow:stack {database}';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Command description';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* #return int
*/
public function handle()
{
$database = $this->argument('database'); //Name database old
foreach (DB::select('SHOW DATABASES') as $db) {
if ($db->Database === $database) {
Config::set('database.connections.searchDB.database', $database); // Now Working
$tables = DB::connection('searchDB')->select('SHOW TABLES'); // Now Working
foreach ($tables as $table) {
$tableNames[$database][] = $table;
}
}
}
dd($tables); //RETURNS THE CURRENT DATABASE.
}
}

Setting dynamic database in config during Login - Laravel

I'm trying to change the database connection on login based on the user's company.
Here my user has a company and its DB is companyA.
Below is my LoginController where I changed the connection:
public function authenticated(Request $request,User $user)
{
\Config::set('database.connections.dynamicdb', array(
'driver' => 'mysql',
'host' => '127.0.0.1',
'database' => $user->company,
'username' => 'root',
'password' => '',
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'strict' => false,
'options' => [
\PDO::ATTR_EMULATE_PREPARES => true
]
));
return redirect()->intended($this->redirectPath());
}
So based on user->company which is already defined in users table, the database name is changed.
But somehow it doesn't work. The error shown is
No database selected.
I tried below code to check if the values are set during login.
return \Config::get('database.connections.dynamicdb');
It showed all values set to my requirements. But when I check after login and reaching /home, the value of database in config is null.
So what all changes should I do. Is my technique right? Or is there any other solution for this.
In my Stock Model i have added the below lines:
protected $table = 'stocks';
protected $connection = 'dynamicdb';
And the query I'm running is just a get all query:
Stock::orderBy('tag_no','asc')->get()
Can anyone please tell me why this happens? What should i do?
All requests are stateless so current request doesn't know that you set new config value in previous request.
You should call Config::set(...) every time when you want to use dynamic database and set database name getting this value from User instance.
Setting above should be done using middleware and service provider.
Create new middleware and register it for web middleware group (You may do this using the $middlewareGroups property of your HTTP kernel):
protected $middlewareGroups = [
'web' => [
//...
\App\Http\Middleware\YourMiddleware::class,
],
//...
];
Then:
<?php namespace App\Http\Middleware;
class YourMiddleware
{
public function handle($request, Closure $next)
{
if (Auth::check()) {
$database_name = Auth::user()->company;
// Set your config here using $user->company
// ...
}
return $next($request);
}
}
If you must to set this value once (during authentication), you should combine above code and sessions to store this information between requests:
session(['db_name' => $dbname]); // Set db_name and store it
$db_name = session('db_name'); // Get db_name from session
Read more about HTTP Sessions: https://laravel.com/docs/5.7/session#retrieving-data
First you need create new default db for connection and add to database.php like normal connection
'dynamicdb' => [
'driver' => 'mysql',
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => 'default',
//others
],
next overriding model methods in Stock
protected $table = 'stocks';
protected $connection = 'dynamicdb';
/**
* #return string
*/
public function getTable()
{
$table = parent::getTable();
$database = config('database.connections.dynamicdb.database');
return starts_with($table, $database)
? $table
: $database . '.' . parent::getTable();
}
/**
* Set the table associated with the model.
*
* #param string $table
* #return $this
*/
public function setTable($table)
{
$database = config('database.connections.dynamicdb.database');
$this->table = starts_with($table, $database)
? $table
: $database . '.' . $table;
return $this;
}
Usage : \Config::set('database.connections.dynamicdb.database',$user->company); or you can create helper for it
Don't forget this method work only one connection and connected user have access all databases
Add Multiple DB in .env
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=database1
DB_USERNAME=root
DB_PASSWORD=
ALT_DB_HOST=127.0.0.1
ALT_DB_PORT=3306
ALT_DB_DATABASE=database2
ALT_DB_USERNAME=root
ALT_DB_PASSWORD=
Edit config/database.php
'connections' => [
'mysql' => [
......
],
'alt_mysql' => [
'driver' => 'mysql',
'host' => env('ALT_DB_HOST', '127.0.0.1'),
'port' => env('ALT_DB_PORT', '3306'),
'database' => env('ALT_DB_DATABASE', 'vibecloud'),
...
],
If Whole model used for ALT_MYSQL then
protected $connection = 'alt_mysql';
ELSE
protected function stock_info() {
return \DB::connection('alt_mysql')->select('*')->from('stocks')->get();
}

Change database connection according to login in laravel 5.3?

Current i am trying create a SaaS software in Laravel 5.3.The current issue is i am unable to switch database according to the user login.
I want to achieve the following work flow .
1) User login with username,Password,and a database name - Finished
2)Need to fetch credentials according to the provided database name from master database - Finished
3)I Need to Switch the entire application connection to provided database name if database name is valid.
i already created a middleware for switching database as follows
class SetDb
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if (Session::has('DB_DATABASE')) {
Config::set('database.connections.mysql7', array(
'driver' => 'mysql',
'host' => env('DB_HOST','127.0.0.1'),
'port' => env('DB_PORT','3306'),
'database' => Session::get('DB_DATABASE'),
'username' => Session::get('DB_USER'),
'password' => Session::get('DB_PASSWORD'),
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
));
DB::reconnect('mysql7');
dd(DB::reconnect('mysql7'));
} else {
Auth::logout();
Session::flush();
DB::reconnect('mysql');
}
return $next($request);
}
}
i hope someone is able to finished the task , Thanks in advance :)

Error: undefined table, when trying to access PostgreSQL with Doctrine2

I want to access a PostgreSQL Database with Doctrine 2 in a Zend 2 Application, but I get the error, that the table I want to access is not defined.
The same access on a MySQL Database works fine.
My Doctrine configuration (local.php) is:
return array(
'doctrine' => array(
'connection' => array(
'orm_default' => array(
// MySQL - Config
// 'driverClass' => 'Doctrine\DBAL\Driver\PDOMySql\Driver',
// 'params' => array(
// 'host' => '192.168.1.100',
// 'port' => '3306',
// 'user' => 'user',
// 'password' => 'password',
// 'dbname' => 'mydb',
// 'charset' => 'utf8',
// ),
// PostgreSQL
'driverClass' => 'Doctrine\DBAL\Driver\PDOPgSql\Driver',
'params' => array(
'host' => '192.168.1.100',
'port' => '5432',
'user' => 'user',
'password' => 'password',
'dbname' => 'mydb',
'charset' => 'utf8',
),
),
),
),
);
My Controller tries to display an Entity "Horse":
class HorsesController extends AbstractActionController
{
/**
* #var Doctrine\ORM\EntityManager
*/
protected $em;
public function getEntityManager()
{
if (null === $this->em) {
$this->em = $this->getServiceLocator()->get('doctrine.entitymanager.orm_default');
}
return $this->em;
}
/**
* The default action - show the home page
*/
public function indexAction()
{
$id = (int)$this->getEvent()->getRouteMatch()->getParam('id');
$horse = $this->getEntityManager()->find('Doctrine2mapper\Entity\Horse', $id);
return new ViewModel(array(
'horse' => $horse,
));
}
}
The Entity Horse is:
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Zend\Form\Annotation; // !!!! Absolutely neccessary
use Zend\Db\Sql\Ddl\Column\BigInteger;
/**
* Horses
*
* #ORM\Table(name="Horse")
* #ORM\Entity(repositoryClass="Doctrine2mapper\Entity\Repository\HorseRepository")
* #Annotation\Name("Horse")
* #Annotation\Hydrator("Zend\Stdlib\Hydrator\ClassMethods")
*/
class Horse
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
* #Annotation\Exclude()
*/
private $id;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
.
.
.
(many attributes, getter and setter)
When trying to access PostgreSQL I get this error:
An exception occurred while executing 'SELECT t0.id AS id1, ...
FROM Horse t0 WHERE t0.id = ?' with params [1]:
SQLSTATE[42P01]: Undefined table: 7 ERROR: relation "horse" does not exist
LINE 1: ...ated AS created29, t0.modified AS modified30 FROM Horse t0 W...
I have a PostgreSQL Database "mydb" with the schema "public" and the table "Horse"
-- Table: "Horse"
CREATE TABLE "Horse"
(
id serial NOT NULL,
.
.
.
);
exists and can be accessed using pgAdminIII.
Any help is welcome!
Best regards
rholtermann
Found the answer, now it works.
I just had to add the schema and had to escape it a little:
In my Horse-Entity:
#ORM\Table("Horse")
had to be replaced with:
#ORM\Table(name="""public"".""Horse""")
I got the hint from here

Laravel 4 migrate base table not found

I'm trying to make following tutorial: https://medium.com/on-coding/e8d93c9ce0e2
When it comes to run:
php artisan migrate
I get following error:
[Exception]
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'laravel.user' doesn't
exist (SQL: alter table `user` add `id` int unsigned not null auto_increment prim
ary key, add `username` varchar(255) null, add `password` varchar(255) null, add
`email` varchar(255) null, add `created_at` datetime null, add `updated_at` datet
ime null) (Bindings: array (
))
Database connection is working, the migrations table was created successfully. Database name was changed as you can see in the error message.
Whats quite strange to me, is that it tries to alter the table - which doesn't exists - and not to create it.
Here are my other files, like UserModel, Seeder, Migtation and DB Config.
CreateUserTable:
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateUserTable extends Migration {
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::table('user', function(Blueprint $table)
{
$table->increments("id");
$table
->string("username")
->nullable()
->default(null);
$table
->string("password")
->nullable()
->default(null);
$table
->string("email")
->nullable()
->default(null);
$table
->dateTime("created_at")
->nullable()
->default(null);
$table
->dateTime("updated_at")
->nullable()
->default(null);
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::table('user', function(Blueprint $table)
{
Schema::dropIfExists("user");
});
}
}
UserModel:
use Illuminate\Auth\UserInterface;
use Illuminate\Auth\Reminders\RemindableInterface;
class User extends Eloquent implements UserInterface, RemindableInterface {
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'user';
/**
* The attributes excluded from the model's JSON form.
*
* #var array
*/
protected $hidden = array('password');
/**
* Get the unique identifier for the user.
*
* #return mixed
*/
public function getAuthIdentifier()
{
return $this->getKey();
}
/**
* Get the password for the user.
*
* #return string
*/
public function getAuthPassword()
{
return $this->password;
}
/**
* Get the e-mail address where password reminders are sent.
*
* #return string
*/
public function getReminderEmail()
{
return $this->email;
}
}
UserSeeder:
class UserSeeder extends DatabaseSeeder
{
public function run()
{
$users = [
[
"username" => "ihkawiss",
"password" => Hash::make("123456"),
"email" => "ihkawiss#domain.com"
]
];
foreach ($users as $user)
{
User::create($user);
}
}
}
DatabaseSeeder:
class DatabaseSeeder extends Seeder {
/**
* Run the database seeds.
*
* #return void
*/
public function run()
{
Eloquent::unguard();
$this->call('UserSeeder');
}
}
Database Config:
return array(
/*
|--------------------------------------------------------------------------
| PDO Fetch Style
|--------------------------------------------------------------------------
|
| By default, database results will be returned as instances of the PHP
| stdClass object; however, you may desire to retrieve records in an
| array format for simplicity. Here you can tweak the fetch style.
|
*/
'fetch' => PDO::FETCH_CLASS,
/*
|--------------------------------------------------------------------------
| Default Database Connection Name
|--------------------------------------------------------------------------
|
| Here you may specify which of the database connections below you wish
| to use as your default connection for all database work. Of course
| you may use many connections at once using the Database library.
|
*/
'default' => 'mysql',
/*
|--------------------------------------------------------------------------
| Database Connections
|--------------------------------------------------------------------------
|
| Here are each of the database connections setup for your application.
| Of course, examples of configuring each database platform that is
| supported by Laravel is shown below to make development simple.
|
|
| All database work in Laravel is done through the PHP PDO facilities
| so make sure you have the driver for your particular database of
| choice installed on your machine before you begin development.
|
*/
'connections' => array(
'sqlite' => array(
'driver' => 'sqlite',
'database' => __DIR__.'/../database/production.sqlite',
'prefix' => '',
),
'mysql' => array(
'driver' => 'mysql',
'host' => 'localhost',
'database' => 'laravel',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
),
'pgsql' => array(
'driver' => 'pgsql',
'host' => 'localhost',
'database' => 'database',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
'prefix' => '',
'schema' => 'public',
),
'sqlsrv' => array(
'driver' => 'sqlsrv',
'host' => 'localhost',
'database' => 'database',
'username' => 'root',
'password' => '',
'prefix' => '',
),
),
/*
|--------------------------------------------------------------------------
| Migration Repository Table
|--------------------------------------------------------------------------
|
| This table keeps track of all the migrations that have already run for
| your application. Using this information, we can determine which of
| the migrations on disk have not actually be run in the databases.
|
*/
'migrations' => 'migrations',
/*
|--------------------------------------------------------------------------
| Redis Databases
|--------------------------------------------------------------------------
|
| Redis is an open source, fast, and advanced key-value store that also
| provides a richer set of commands than a typical key-value systems
| such as APC or Memcached. Laravel makes it easy to dig right in.
|
*/
'redis' => array(
'cluster' => true,
'default' => array(
'host' => '127.0.0.1',
'port' => 6379,
'database' => 0,
),
),
);
Hope somebody can give me a hint here.
Best regards ihkawiss
In your CreateUserTable migration file, instead of Schema::table you have to use Schema::create.
The Schema::table is used to alter an existing table and the Schema::create is used to create new table.
Check the documentation:
http://laravel.com/docs/schema#creating-and-dropping-tables
http://laravel.com/docs/schema#adding-columns
So your user migration will be:
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateUserTable extends Migration {
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('user', function(Blueprint $table) {
{
$table->increments("id",true);
$table->string("username")->nullable()->default(null);
$table->string("password")->nullable()->default(null);
$table->string("email")->nullable()->default(null);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists("user");
}
}
The underlying cause of this may be if the syntax used for creating the migration php artisan migrate ... is not quite correct. In this case the --create will not get picked up properly and you will see the Schema::table instead of the expected Schema::create. When a migration file is generated like this you might also be missing some of the other markers for a create migration such as the $table->increments('id'); and $table->timestamps();
For example, these two commands will not create a create table migration file as you might expect:
php artisan migrate:make create_tasks_table --table="tasks" --create
php artisan migrate:make create_tasks2_table --table=tasks2 --create
However, the command will not fail with an error. Instead laravel will create a migration file using Schema::table
I always just use the full syntax when creating a new migration file like this:
php artisan migrate:make create_tasks_table --table=tasks --create=tasks
to avoid any issues like this.
Sometimes it is caused by custom artisan commands. Some of these commands might initiate few classes. And because we did a rollback, the table cannot be found. Check you custom artisan commands. You can comment out the lines which are causing the trigger. Run the php artisan migrate command and then uncomment. This is what I had to do.

Categories