How to store activity log in mongo db from laravel? - mysql

I am using spatie/laravel-activitylog to log the activities and jenssegers/laravel-mongodb connect to a Mongo database. In user Model, the user data is storing into mysql and log data need to be stored in mongodb. I am getting "Call to a member function prepare() on null"
config/activitylog.php
` /*
* This is the database connection that will be used by the migration and
* the Activity model shipped with this package. In case it's not set
* Laravel's database.default will be used instead.
*/
'database_connection' => env('ACTIVITY_LOGGER_DB_CONNECTION'),`
database.php
`'mongodb' => [
'driver' => 'mongodb',
'host' => '127.0.0.1',
'port' => '27017',
'database' => 'test_log',
'username' => '',
'password' => '',
'options' => [
'database' => 'admin'
]
],`
.env
`ACTIVITY_LOGGER_DB_CONNECTION=mongodb`
App\Models\User.php
`<?php
namespace App\Models;
// use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Spatie\Activitylog\LogOptions;
use Spatie\Activitylog\Traits\LogsActivity;
use Jenssegers\Mongodb\Auth\User as Authenticatable;
class User extends Authenticatable implements MustVerifyEmail
{
use LogsActivity;
/**
* The attributes that are mass assignable.
*
* #var array<int, string>
*/
protected $fillable = [];
/**
* The attributes that should be hidden for serialization.
*
* #var array<int, string>
*/
/**
* The attributes that should be cast.
*
* #var array<string, string>
*/
/**
* The attributes that should be mutated to dates.
*
* #var array
*/
public function getActivitylogOptions(): LogOptions
{
return LogOptions::defaults();
}
}
`
In user Model, the user data is storing into mysql and log data need to be stored in mongodb.

The error message "Call to a member function prepare() on null" usually occurs when the database connection is not properly configured or the database connection does not exist.
In this case, you have set the database connection for the activity logs in the config/activitylog.php and .env files. However, it seems that the database connection is not being used properly in the User model.
To resolve this issue, you need to ensure that the database connection defined in 'config/activitylog.php' is being passed to the User model when logging activities.
You can add the following code to your User model to explicitly set the database connection:
use Illuminate\Support\Facades\Config;
protected static $logConnection = 'mongodb';
public function getActivitylogOptions(): LogOptions
{
return LogOptions::defaults()->using(Config::get('activitylog.database_connection') ?: static::$logConnection);
}
This will make sure that the activity logs are stored in the MongoDB database defined in the mongodb connection in config/database.php.

Fixed the issue with the help of this tutorial:: https://nickdevs.wordpress.com/2022/05/17/laravel-laravel-activitylog-inegrate-activity-log-with-mongodb/
The issue was with Spatie-activity-log and Jenssegers MongoDB. Spatie-activity-log uses default Model. We need to overwrite the Spatie Activity Model for Jenssegers MongoDB.
Create Activity.php in App/Models. copy the existing code from Spatie\Activitylog\Models\Activity.php from vendor/spatie/laravel-activitylog/src/Models/Activity.php. Replace the lines listed below.
remove:
namespace Spatie\Activitylog\Models;
use Illuminate\Database\Eloquent\Model;
class Activity extends Model implements ActivityContract
add:
namespace App\Models;
use Jenssegers\Mongodb\Eloquent\Model as MongoDBModel;
class Activity extends MongoDBModel implements ActivityContract

Related

How do I verify a hash code exists in MySQL table using Laravel 8

I want to be able to verify comfirm row with specific hashcode exists in a table before a user bearing the given hash code can fill a registration form.
I know the hash code exists because it's in the database. But the application redirect to the page it should if the hash code is non-existent and outputs a message that the hash code doesn't exist.
This used to work in Laravel 5 but it seems the implementation has changed since Laravel 8.
Here's my code:
use App\Http\Controllers\Site\Guest\newMembership\RegistrationForm;
...
Route::get('registration/{hashCode}', [RegistrationForm::class, 'registrationForm'])->name('registration');
Route::post('registration', [RegistrationForm::class, 'registrationProcessing'])->name('registration_data');
My controller, RegistrationForm.php has the code:
namespace App\Http\Controllers\Site\Guest\newMembership;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class RegistrationForm extends Controller
{
public function registrationForm($hashCode)
{
// Check if this $hashCode exists at all, otherwise redirect to referral request home page.
$hash_exists = (new \App\Http\Controllers\Site\Guest\newMembership\Form)->hashExists($hashCode);
// In the event the number of times it occurs is zero
if($hash_exists < 1)
{
// Tell user the referral link is non-existent.
session()->flash('membershipInfo', 'Your code does not exist.');
// Take this user to the referral request welcome page
return redirect()->route('membership.index');
}
// Assign new variable name to hash code
$referralCode = $hashCode;
return view('membership.registration', [
'referralCode' => $referralCode,
]);
}
The Form contoller has the code:
// Import database model
use App\Models\Site\Guest\Referralrequestapplication;
...
/**
* Count number of entries with given ID
*/
public function hashExists($hashCode)
{
//DB::table('referralrequestapplications')
Referralrequestapplication::where(['blocked', 0], ['image_reference', $hashCode])->count();
}
The model code:
namespace App\Models\Site\Guest;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Referralrequestapplication extends Model
{
use HasFactory;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'blocked', 'review', 'reviewer', 'firstname', 'surname', 'phone', 'email', 'nin', 'facebook', 'twitter', 'instagram', 'state', 'city', 'neighbourhood', 'address', 'image_reference', 'created_at', 'updated_at',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $table = 'referralrequestapplications';
}
The migration schema has the code:
Schema::create('referralrequestapplications', function (Blueprint $table) {
$table->bigIncrements('id');
$table->boolean('blocked')->default(0);
$table->boolean('reviewed')->default(0);
$table->string('reviewer')->nullable();
$table->string('firstname', 30)->nullable();
$table->string('surname', 30)->nullable();
$table->string('phone', 30)->nullable();
$table->string('email', 70)->nullable();
$table->string('nin', 20)->nullable();
$table->string('facebook', 70)->nullable();
$table->string('twitter', 70)->nullable();
$table->string('instagram', 70)->nullable();
$table->string('state', 40)->nullable();
$table->string('city', 40)->nullable();
$table->string('neighbourhood', 40)->nullable();
$table->string('address', 200)->nullable();
$table->string('image_reference', 200)->nullable();
$table->timestamps();
});
I fixed this issue by changing the code in Form controller from:
Referralrequestapplication::where(['blocked', 0], ['image_reference', $hashCode])->count();
To:
Referralrequestapplication::where('blocked', 0)->where('mage_reference', $hashCode)->exists();
Also I changed the following in RegistrationForm controller:
if($hash_exists < 1)
To:
if($hash_exists = 0)

Select default schema for MS SQL

I need to configure Yii2 to work with Microsoft SQL server.
The db configuration file (db.php) is something like this
return [
'class' => 'yii\db\Connection',
'dsn' => 'sqlsrv:Server=192.168.77.111;Database=xyz',
'username' => 'xy',
'password' => 'xyz',
This works only if i add before the table name in the tableName() function inside all models the correct schema name.
For example:
public static function tableName()
{
return '{{%xyzschema.users}}';
}
How can i set the db configuration so xyzschema is always added when connecting to the table?
I tried with tablePrefix and schemaMap with defaultSchema but it doesn't work
The error returned is
Invalid object name 'users'.
or
Invalid object name 'xyzschema.users'.
If i add tablePrefix to db.php
Update: The defaultSchema property inside connection's schemaMap/Schema config array gets ingored
For this case i solved changing the schema to the standard "dbo" for each table.

Yii2 Access Rules Using Different Models

I'm having trouble with Yii2 Role Based Access Control. In the usual set-up, the authentication rule takes place when the identity of the current user. Like written in the docs. Authorization
In my case, how can I set up the authorization (aside from the basic feature) using another set of models.? Here is my set up.
Table auth_assignment [item_name, user_id] from rbac migration,
user [id] from the yii2 migration.
I created a new table assignment [user_id related to user, rec_id related to recognition of an organization].
This is the scenario. I have the roles admin, organization-head, member. How can I check if the organization-head, or member belongs to their own Recognition module; not the other modules from other organization-heads?
I used also the context access control filter by peixoto.
Here is my code for checking. RecognitionRule checks if there is a user user_id equal to the identity of the user; and account_id equal to rec_id. The second condition tells if he is belong to the organization
/**
* Checks if ID matches user passed via params
*/
class RecognitionRule extends Rule
{
public $name = 'isRecognition';
/**
* #param string|integer $user the user ID.
* #param Item $item the role or permission that this rule is associated with
* #param array $params parameters passed to ManagerInterface::checkAccess().
* #return boolean a value indicating whether the rule permits the role or permission it is associated with.
*/
public function execute($user, $item, $params)
{
if(isset($params['recognition'])){ //Directly specify the model you plan to use via param
$model = $params['recognition'];
}else{ //Use the controller findModel method to get the model - this is what executes via the behaviour/rules
$id = Yii::$app->request->get('id'); //Note, this is an assumption on your url structure.
$model = Yii::$app->controller->findModel($id); //Note, this only works if you change findModel to be a public function within the controller.
}
return \common\models\Assignment::find()->where(['rec_id' => $model->id, 'user_id' => $user])->exists();
}
}
Still, I am not allowed to perform the action. Any clues?
I got the answers. I based my answer on AccessRule behavior and rbac\Rule $params
snippet of the RecognitionRule
/**
* #param string|integer $user the user ID.
* #param Item $item the role or permission that this rule is associated with
* #param array $params parameters passed to ManagerInterface::checkAccess().
* #return boolean a value indicating whether the rule permits the role or permission it is associated with.
*/
public function execute($user, $item, $params)
{
if(isset($params['recognition'])){ //Directly specify the model you plan to use via param
$model = $params['recognition'];
} else{ //Use the controller findModel method to get the model - this is what executes via the behaviour/rules
$id = Yii::$app->request->get('id'); //Note, this is an assumption on your url structure.
}
return \common\models\Assignment::find()->where(['rec_id' => $id, 'user_id' => $user])->exists();
}
}
?>
RecognitionController
[
'class' => 'common\rbac\ContextAccessRule',
'modelClass' => 'frontend\models\recognition',
'allow' => true,
'actions' => ['view','update'],
'roles' => ['viewOwnRecognition', 'updateOwnRecognition'],
],
],
],
];

Yii2 Gii Table Prefix

I allways setup table prefix - for this post lets say my prefix is abc_.
So in common\config\main-local.php. I have:
'components' => [
'db' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=database',
'username' => 'user',
'password' => 'pwd',
'charset' => 'utf8',
'tablePrefix' => 'abc_',
],
...
I have worked on Yii1 and used gii to generate models.
In this version it generated files like: table.php.
Now I work with Yii2 and learn the differences:
gii generate files like abc_table.php. Yes - I checked "Use Table Prefix".
This is not ok because prefix should be transparent.
Could please anyone tell me what I'm doing wrong?
You may change the model class name AbcTest to Test. For future model generations, check the Use Table Prefix field in the Gii tool. Gii generate correct model like this:
class Test extends \yii\db\ActiveRecord
{
/**
* #inheritdoc
*/
public static function tableName()
{
return '{{%test}}';
}
...
}
In tableName method, it returns '{{%test}}' if you check Use Table Prefix in the Gii tool. If you do not check the Use Table Prefix, this method return 'abc_test' and generated model class will be named as AbcTest.

Symfony 2 Console command for creating custom Database

I am working on a Symfony 2 project where each user have his own database. In my config.yml file I have a doctrine:dbal:orm set for a client but no connection properties because they are set at runtime and referenced by all users. I.e I only have one default dbal connection and two orm-connection and the amount of users is unlimited.
This works fine but I need to create the database and schema when the user is registered (FOS UserBundle). In the extended userbundle controller I can put my own logic.
The problem is that I cannot run the 'php app/console doctrine:database:create' since there are not parameters set for the new user.
Is there any way of specifying a custom database parameter to the console commands?
I could probably get around this by some very ugly mysql commands but I'd rather not.
Many thanks in advance!
You can create your own command using the code below as an outline:
namespace Doctrine\Bundle\DoctrineBundle\Command;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Doctrine\DBAL\DriverManager;
class CreateDatabaseDoctrineCommandDynamically extends DoctrineCommand
{
protected function configure()
{
$this
->setName('doctrine:database:createdynamic')
->setDescription('Creates the configured databases');
}
/**
* {#inheritDoc}
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
/***
** Edit this part below to get the database configuration however you want
**/
$connectionFactory = $this->container->get('doctrine.dbal.connection_factory');
$connection = $connectionFactory->createConnection(array(
'driver' => 'pdo_mysql',
'user' => 'root',
'password' => '',
'host' => 'localhost',
'dbname' => 'foo_database',
));
$params = $connection->getParams();
$name = isset($params['path']) ? $params['path'] : $params['dbname'];
unset($params['dbname']);
$tmpConnection = DriverManager::getConnection($params);
// Only quote if we don't have a path
if (!isset($params['path'])) {
$name = $tmpConnection->getDatabasePlatform()->quoteSingleIdentifier($name);
}
$error = false;
try {
$tmpConnection->getSchemaManager()->createDatabase($name);
$output->writeln(sprintf('<info>Created database for connection named <comment>%s</comment></info>', $name));
} catch (\Exception $e) {
$output->writeln(sprintf('<error>Could not create database for connection named <comment>%s</comment></error>', $name));
$output->writeln(sprintf('<error>%s</error>', $e->getMessage()));
$error = true;
}
$tmpConnection->close();
return $error ? 1 : 0;
}
}