Laravel: Store error messages in database - mysql

Any one know how to send error messages to database in laravel which generate from app/exceptions/handler.php ?
I need to send what error massages generated in report() method to database.

If you are interested doing this manually, you can do something as following.
Step 1 -
Create a model to store errors that has a DB structure as following.
class Error extends Model
{
protected $fillable = ['user_id' , 'code' , 'file' , 'line' , 'message' , 'trace' ];
}
Step 2
Locate the App/Exceptions/Handler.php file, include Auth, and the Error model you created. and replace the report function with the following code.
public function report(Exception $exception) {
// Checks if a user has logged in to the system, so the error will be recorded with the user id
$userId = 0;
if (Auth::user()) {
$userId = Auth::user()->id;
}
$data = array(
'user_id' => $userId,
'code' => $exception->getCode(),
'file' => $exception->getFile(),
'line' => $exception->getLine(),
'message' => $exception->getMessage(),
'trace' => $exception->getTraceAsString(),
);
Error::create($data);
parent::report($exception);
}
(I am demonstrating this using laravel 5.6)

Because Laravel uses Monolog for handling logging it seems that writing Monolog Handler would be the cleanest way.
I was able to find something that exists already, please have a look at monolog-mysql package. I did not use it, so I don't know whether it works and if it works well, but it's definitely good starting point.

Related

Insert query works fine on my local but doesn't execute on my live database (Laravel/MySQL)

I have a very simple function that loops through an array and inserts some data into a results table - this works perfectly fine on my local using the very same code. On my local setup (Mac) using Laravel Valet & an MySQL database it hits the function Result::create($data) and inserts this data in the database. However on the live/remote site it never hits the Result::create() within the insertUniqueMatches for some reason.
I have added the db user in the env file and it has been granted all privileges so I cannot understand why this won't insert the entry into the results table. Can anyone explain what I am doing wrong? All migrations have been ran to ensure my local and live db are identical.
P.S i have tried both the $fillable variable with all the relevant items in the array and also with the $guarded as a blank array and the problem persists.
class Result extends Model
{
use HasFactory;
// protected $fillable = ['match_id', 'home_team_id', 'away_team_id', 'home_team_goals', 'away_team_goals', 'outcome', 'match_date', 'properties', 'platform_id'];
protected $guarded = [];
public static function insertUniqueMatches($matches, $platform = null)
{
$inserted = 0;
foreach ($matches as $match) {
// check if existing match already exists in the db, if so don't re-insert this
if (Result::where('match_id', '=', $match['matchId'])->doesntExist()) {
$carbonDate = Carbon::now();
$carbonDate->timestamp($match['timestamp']);
$clubs = collect($match['clubs'])->values();
$data = [
'match_id' => $match['matchId'],
'home_team_id' => $clubs[0]['id'],
'away_team_id' => $clubs[1]['id'],
'home_team_goals' => $clubs[0]['goals'],
'away_team_goals' => $clubs[1]['goals'],
'outcome' => self::getMatchOutcome($clubs[0]),
'match_date' => $carbonDate->format('Y-m-d H:i:s'),
'properties' => json_encode([
'clubs' => $match['clubs'],
'players' => $match['players']
]),
'platform_id' => $platform
];
dump($data); // this shows valid data in the terminal
// this if condition is only reached on my local development but never on live so no inserts happen on the live DB
if (Result::create($data)) {
$inserted++;
dump('inserted matchId: '. $match['matchId']); // never see this on line but always on local
}
}
}
return $inserted;
}
i think better solution for now is you can find the problem.
you could write code into try-catch for more information.
replace this code
try {
Result::create($data);
} catch (\Exception $e) {
dd($e);
}
with:
dump($data); // this shows valid data in the terminal
// this if condition is only reached on my local development but never on live
if (Result::create($data)) {
$inserted++;
dump('inserted matchId: '. $match['matchId']); // never see this on line but always on local
}

CakePHP 3: Best Practice for Temporary SQL Tables

Dear CakePHP 3 developers,
I'd like to use SQL's Temporary Tables in a CakePHP 3.4.13 project for a single run through a script. Going through Cake's documentation, there seems no direct way to tell CakePHP my desire. How would I best go about it, then?
I've prepared a Table in src/Model/Table/TempItemsTable.php:
namespace App\Model\Table;
use Cake\ORM\Table;
class TempItemsTable extends Table
{
public $fields = [
'id' => ['type' => 'integer'],
'con' => ['type' => 'string', 'length' => 255, 'null' => false],
'_constraints' => [
'primary' => ['type' => 'primary', 'columns' => ['id']]
]
];
public function initialize(array $config)
{
// $this->setTable(null);
}
}
The idea to use $fields to tell CakePHP the desired table schema comes from a possibly unrelated documentation for Test Fixtures.
But how do I tell CakePHP not to look for an actual table in the database?
The uncommented line $this->setTable(null); was my poor attempt at that, which is supposedly similiar to the right way in earlier versions of CakePHP, but according to version 3.x documentation, setTable() doesn't accept null, while table() does, but it's deprecated as of 3.4 and also didn't change anything.
Finally, of course, I get this exception as soon as I try to access this "table" in a controller via $temp = TableRegistry::get('TempItems');:
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'mydatabase.temp_items' doesn't exist
Help, I'm stuck. :(
There's no need to tell it to not look for the table, actually that's the opposite of what you want to do, given that you eventually want to access it.
The table class should basically be configured as usual, and you should create the temporary database table before the application causes it to be accessed. You can either write the raw table creation SQL manually, or generate it from a \Cake\Database\Schema\TableSchema instance, which supports temporary tables.
You can either explicitly create the schema object:
$schema = new \Cake\Database\Schema\TableSchema('temp_items');
$schema
->addColumn('id', ['type' => 'integer'])
->addColumn('con', ['type' => 'string', 'length' => 255, 'null' => false])
->addConstraint('primary', ['type' => 'primary', 'columns' => ['id']])
->setTemporary(true);
$TableObject->setSchema($schema);
or let the table object generate it, using your fields definition array:
$TableObject->setSchema($TableObject->fields);
$schema = $TableObject->getSchema()->setTemporary(true);
You can then generate the table creation SQL from the schema object and run it against the database:
$connection = $TableObject->getConnection();
$queries = $schema->createSql($connection);
$connection->transactional(
function (\Cake\Database\Connection $connection) use ($queries) {
foreach ($queries as $query) {
$stmt = $connection->execute($query);
$stmt->closeCursor();
}
}
);
$queries would be an array of SQL commands required to create the table, something along the lines of:
[
'CREATE TEMPORARY TABLE `temp_items` (
`id` INTEGER AUTO_INCREMENT,
`con` VARCHAR(255) NOT NULL,
PRIMARY KEY (`id`)
)'
]
Note that if you do not assign the schema to the table object, you could run into caching problems, as the cached schema wouldn't match anymore when you change the table definition and do not clear the cache.
See also
Cookbook > Database Access & ORM > Schema System
Cookbook > Database Access & ORM > Database Basics

Action after loginByCookie()

In my app, I'm using session to store some user's data (e.g. name, role). I'm using default User class on common/models from yii2 and I'm getting the data I need by user id.The problem is that the data I stored in session are lost if user resume their previous session without entering password (using remember me option). To solve this, I tried to modify and put the codes for saving user's data inside validateAuthKey() method in User since it's called when yii2 checking for authkey to resume session. As in:
public function validateAuthKey($authKey)
{
$user = Member::findOne(['account_id' => Yii::$app->user->id]);
// Save on session
Yii::$app->session->set('name', $user->first_name . ' ' . $user->last_name);
Yii::$app->session->set('position', $user->position);
// .. other data
return true;
}
As you can see, I use the id of logged user to find Member. But by doing this, I got "Trying to get property of non-object" exception from Yii::$app->user->id. I can only get the id after the login process is completed. After prying around, I found that loginByCookie() from User in vendor\yiisoft\yii2\Web is used to log in. Is there any way to save user's data without tampering codes on vendor? Maybe some kind of event after loginByCookie() is executed.
Create your own User model extends \yii\web\User
namespace frontend\components;
class User extends \yii\web\User
{
protected function afterLogin($identity, $cookieBased, $duration)
{
...Do something here...
parent::afterLogin($identity, $cookieBased, $duration);
}
}
Modify the config (main.php).
'components' => [
'user' => [
'class' => 'frontend\components\User',
'identityClass' => 'common\models\User',
...
]
]
Put the below code in common/config/bootstrap.php
The EVENT_AFTER_LOGIN will be called even if the user is logged in by cookie.
use yii\web\User;
use yii\base\Event;
Event::on(User::className(), User::EVENT_AFTER_LOGIN, function() {
$user = Member::findOne(['account_id' => Yii::$app->user->id]);
// Save on session
Yii::$app->session->set('name', $user->first_name . ' ' . $user->last_name);
Yii::$app->session->set('position', $user->position);
});

Yii Query optimization MySQL

I am not very good with DB queries. And with Yii it's more complicated, since I am not very used to it.
I need to optimize a simple query
$userCalendar = UserCalendar::model()->findByAttributes(array('user_id'=>$user->id));
$unplannedEvents = CalendarEvent::model()->findAllByAttributes(array('calendar_id'=> $userCalendar->calendar_id,'planned'=>0));
CalendarEvent table, i.e the second table from which I need records does not have an user_id but a calendar_id from which I could get user_id from UserCalendar, i.e. the first table hence I created a UserCalendar object which is not a very good way as far as I understand.
Q1. What could I do to make it into one.
Q2. Yii does this all internally but I want to know what query it built to try it seperately in MySQL(phpMyAdmin), is there a way to do that?
Thanks.
Q1: You need to have the relation between UserCalendar and CalendarEvent defined in both of your active record models (in the method "relations").
Based on your comments, it seems like you have the Calendar model that has CalendarEvent models and UserCalendar models.
Lets assume your relations in Calendar are:
relations() {
return array(
'userCalendar' => array(self::HAS_MANY, 'UserCalendar', 'calendar_id'),
'calendarEvent' => array(self::HAS_MANY, 'CalendarEvent', 'calendar_id'),
}
In CalendarEvent:
relations() {
return array( 'calendar' => array(self::BELONGS_TO, 'Calendar', 'calendar_id'), );
}
And in UserCalendar:
relations() {
return array( 'calendar' => array(self::BELONGS_TO, 'Calendar', 'calendar_id'), );
}
So to make the link between UserCalendar and CalendarEvent you'll need to use Calendar
$criteria = new CDbCriteria;
$criteria->with = array(
"calendarEvent"=>array('condition'=>'planned = 0'),
"userCalendar"=>array('condition'=> 'user_id =' . $user->id),
);
$calendar = Calendar::model()->find($criteria);
and $calendar->calendarEvent will return an array of calendarEvent belonging to the user
Q2: you can enable web logging so all the db request (and others stuffs) will appear at the end of your page:
Logging in Yii (see CWebLogging)
In your application configuration put
'components'=>array(
......
'log'=>array(
'class'=>'CLogRouter',
'routes'=>array(
array(
'class'=>'CWebLogRoute',
),
),
),
),

Error: SQLSTATE[42000]: Syntax error or access violation with cakePHP

I am using the framework cakePHP for my application. I programmed it on localhost with xampp and try to upload it on my website now. It worked without any problems on localhost. Now there is only this one page, which does not work on the new server. The other sites (which use the database connection too) work alright.
For this one site the following message appears:
Error: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'add' at line 1
SQL Query: add
The function add() looks like this.
public function add() {
//$this->create();
$word_id = $this->Word->getWord_id();
$save = $this->save(array('word_id' => $word_id, 'text' => $this->getText($word_id), 'mistake' => 0));
return $save['Game']['id'];
}
On localhost I used MySQL-Client-Version: mysqlnd 5.0.8-dev - 20102224 - $Revision: 310735 $ and PHP Version 5.3.8.
On the server I use MySQL-Client-Version: 5.1.62 and PHP Version 5.3.17.
Thank you very much for helping!
Edit:
The model 'Game':
class Game extends AppModel {
public $name = 'Game';
public $belongsTo = 'Word';
public $searchedWord = '';
public function addGame() { // Create new game
$word_id = $this->Word->getWord_id();
$save = $this->save(array('word_id' => $word_id, 'text' => $this->getText($word_id), 'mistake' => 0));
return $save['Game']['id']; // Build the hangman
}
}
When I debug $this->Game, the output is:
object(AppModel) {
useDbConfig => 'default'
useTable => 'games'
id => null
data => array()
schemaName => null
table => 'games'
primaryKey => 'id'
validate => array()
validationErrors => array()
validationDomain => null
name => 'Game'
alias => 'Game'
tableToModel => array(
'games' => 'Game'
)
cacheQueries => false
belongsTo => array()
hasOne => array()
hasMany => array()
hasAndBelongsToMany => array()
actsAs => null
Behaviors => object(BehaviorCollection) {
modelName => 'Game'
defaultPriority => (int) 10
}
whitelist => array()
cacheSources => true
findQueryType => null
recursive => (int) 1
order => null
virtualFields => array()
__backAssociation => array()
__backInnerAssociation => array()
__backOriginalAssociation => array()
__backContainableAssociation => array()
findMethods => array(
'all' => true,
'first' => true,
'count' => true,
'neighbors' => true,
'list' => true,
'threaded' => true
)
}
usually, if this error happens, you don't have the model instance, but an app model instance you work on. the app model instance doesnt have the add() method and directly queries the db with add().
so make sure your model is properly included. since you didnt show us the code how you call the method (and how you make the model available to the controller) I cannot offer any concrete advice, though.
if you manually include it:
$this->ModelName = ClassRegistry::init('ModelName');
add is a reserved word in MySQL and you're probably using it in a SQL query without "escape".
Check if you have any field named add in your database.
I just had this error and I felt pretty stupid. I'm sure this has been solved a long time ago, but in case anyone else comes across it...
Using your example I'll show basically what I also stupidly did in my Controller and how it caused the same type of error you had:
public function index($gameid = null, $letter = null) {
if ($gameid == null) {
// New game
$gameid = $this->Game->addGame();
}
}
Since you already have the instance (controller class) and you're not calling the Model method of addGame here, but the Controller's method, you simply remove the Game-> from your one-line command.
$gameid = $this->addGame();
Simple and easy oversight. That said, if you moved the addGame method to your Model class, it probably would have worked as expected. :)