Softdelete behavior works fine on execute delete statement via the entity manager as the following code:
$entity = $this->em->getRepository('Users')->find(7);
$this->em->remove($entity);
$this->em->flush();
but when execute the same functionality via QueryBuilder hard delete will execute on database
$qb = $this->em->createQueryBuilder();
$qb->delete('Users', 'p');
$qb->where($qb->expr()->eq('p.id', ':id'));
$qb->setParameters(array("id" => 7));
$result = $qb->getQuery()->getResult();
How can I allow softdelete in all cases either via entity manager or query builder
If you use DQL then you have to use a Query Hint. This should do the trick:
$query = $qb->getQuery()
$query->setHint(
\Doctrine\ORM\Query::HINT_CUSTOM_OUTPUT_WALKER,
'Gedmo\SoftDeleteable\Query\TreeWalker\SoftDeleteableWalker'
);
$result = $query->getResult();
Update:
The docs mention that you have to use a Query Hint but don't provide an example so I pulled the usage from their tests.
Docs: https://github.com/l3pp4rd/DoctrineExtensions/blob/master/doc/softdeleteable.md
Test Usage: https://github.com/l3pp4rd/DoctrineExtensions/blob/master/tests/Gedmo/SoftDeleteable/SoftDeleteableEntityTest.php
my old solution after previous answer by #Ken Hannel is:
Edit:
/vendor/doctrine/orm/lib/Doctrine/ORM/Query/SqlWalker.php
Replace walkDeleteClause function as the following:
public function walkDeleteClause(AST\DeleteClause $deleteClause)
{
$class = $this->em->getClassMetadata($deleteClause->abstractSchemaName);
$tableName = $class->getTableName();
$sql = 'DELETE FROM ' . $this->quoteStrategy->getTableName($class, $this->platform);
$this->setSQLTableAlias($tableName, $tableName, $deleteClause->aliasIdentificationVariable);
$this->rootAliases[] = $deleteClause->aliasIdentificationVariable;
//check if SoftDeleteableListener is attached
foreach ($this->em->getEventManager()->getListeners() as $eventName => $listeners) {
foreach ($listeners as $listener) {
if ($listener instanceof \Gedmo\SoftDeleteable\SoftDeleteableListener) {
$date = date('Y-m-d H:i:s');
$sql = 'UPDATE ' . $this->quoteStrategy->getTableName($class, $this->platform) . " SET deletedAt = ' " . $date . " ' ";
}
}
}
return $sql;
}
but really but I think Ken Hannel way is more professional and up to standard.
Related
I was getting the relationship as in laravel 5.3 and was working fine:
//execute the relation of the given model
$data = $model->{$info["relation"]}();
// get the type of the relation
$class = get_class($data);
$dataType = explode("\\", $class);
$relationType = end($dataType);
$options["columns"][$key]["relationType"] = $relationType;
// if its a simple belongs-to statement
if($relationType == "BelongsTo") {
// get all belongs-to query info
$otherTable = $data->getRelated()->getTable();
$foreignKey = $data->getQualifiedForeignKey();
$otherKey = $data->getOtherKey();
// manually join using it
$retrievedRecords->leftJoin($otherTable . ' as ' . $info["relation"], $info["relation"] . '.' . $otherKey, '=', $foreignKey);
} else if($relationType == "HasMany" || $relationType == "HasOne") {
// get all has-many query info
$otherTable = $data->getRelated()->getTable();
$foreignKey = $data->getPlainForeignKey();
$parentKey = $data->getQualifiedParentKeyName();
// manually join using it
$retrievedRecords->leftJoin($otherTable . ' as ' . $info["relation"], $info["relation"] . '.' . $foreignKey, '=', $parentKey);
}
Now i downloaded fresh laravel 5.4 and it gives me error :
Call to undefined method Illuminate\Database\Query\Builder::getOtherKey()
As the getOtherKey() exists in the above code in if() section.
Is there any alternative for that ?
The getOtherKey method has been renamed to getOwnerKey. So you can get the owner key by saying:
$ownerKey = $data->getOwnerKey();
Here's the code in controller
public function actionIndex()
{
$result = new RestResult();
try {
$query = TaskMgr::find()
->join('INNER JOIN', EqpInfo::tableName(), EqpInfo::tableName() . '.EQP_COD =' . TaskMgr::tableName() . '.EQP_COD')
->select([TaskMgr::tableName() . '.EQP_COD', TaskMgr::tableName() . '.TASK_STA', TaskMgr::tableName() . '.TASK_DATE', TaskMgr::tableName() . '.BUSINESS_NATURE', EqpInfo::tableName() . '.EQP_SORT_NAME', EqpInfo::tableName() . '.EQP_VART_NAME', EqpInfo::tableName() . '.USE_UNT_NAME', EqpInfo::tableName() . '.USE_UNT_ADDR', EqpInfo::tableName() . '.INST_AREA_NAME', EqpInfo::tableName() . '.MAKE_UNT_NAME']);
$result->content = $query->asArray(true)->all();
} catch (Exception $e) {
$result->error = $e->getMessage();
$result->content = [];
$result->message = ["error" => Yii::t('rest', "Server error.")];
} finally {
return $result;
}
}
and I got empty array.as pic 1, I thought it might be the problem of QueryBuilder, so I simply excute the sql script in index action:
public function actionIndex()
{
$y = Yii::$app->get('db2')->createCommand('SELECT * FROM "TB_TASK_MGR" INNER JOIN "V_EQPINFO" ON "V_EQPINFO".EQP_COD ="TB_TASK_MGR".EQP_COD')
->queryAll();
return var_dump($y);
}
and I got a empty array again.
but when I ran the sql script in Navicat, I got some rows.as pic 2, that means the sql result is not empty. I thought it might some problems with my DBConnection, so I tried change the action as :
public function actionIndex()
{
$y = Yii::$app->get('db2')->createCommand('SELECT * FROM "TB_TASK_MGR"')
->queryAll();
return var_dump($y);
}
and I got some rows, that means there's no problem in DBConnection, the only difference is the 'join' expression.
I use xampp to deploy site, php version is 5.6.23. oracle client installed and remote oracle version is 11g. php.ini config oci as
extension=php_pdo_oci.dll
Please help me find out why is this, is it because some bugs in php_pdo_oci.dll? and how to excute sql with 'join' in yii2 to oracle.
I tried to log my each SQL query for laravel 5.2 so for that I found many solutions and I tried below code , but somehow it's not gone a work and not generate the log.
In my routes.php - Code not working
Event::listen('illuminate.query', function($query, $bindings, $time, $name) {
dd("here");
$data = compact('bindings', 'time', 'name');
// Format binding data for sql insertion
foreach ($bindings as $i => $binding) {
if ($binding instanceof \DateTime) {
$bindings[$i] = $binding->format('\'Y-m-d H:i:s\'');
} else if (is_string($binding)) {
$bindings[$i] = "'$binding'";
}
}
// Insert bindings into query
$query = str_replace(array('%', '?'), array('%%', '%s'), $query);
$query = vsprintf($query, $bindings);
echo $query;
Log::info('illuminate.query:'. $query);
});
But I tried with the another code sample and it's working fine
code in my routes.php - working fine
DB::enableQueryLog();
DB::listen(
function ($sql) {
// $sql is an object with the properties:
// sql: The query
// bindings: the sql query variables
// time: The execution time for the query
// connectionName: The name of the connection
// To save the executed queries to file:
// Process the sql and the bindings:
foreach ($sql->bindings as $i => $binding) {
if ($binding instanceof \DateTime) {
$sql->bindings[$i] = $binding->format('\'Y-m-d H:i:s\'');
} else {
if (is_string($binding)) {
$sql->bindings[$i] = "'$binding'";
}
}
}
// Insert bindings into query
$query = str_replace(array('%', '?'), array('%%', '%s'), $sql->sql);
$query = vsprintf($query, $sql->bindings);
// Save the query to file
$logFile = fopen(
storage_path('logs' . DIRECTORY_SEPARATOR . date('Y-m-d') . '_query.log'),
'a+'
);
fwrite($logFile, date('Y-m-d H:i:s') . ': ' . $query . PHP_EOL);
fclose($logFile);
}
);
My Question : why Event::listen('illuminate.query' is not working? is there anything i am doing wrong?
Laravel are not firing events as illuminate.query anymore. It was changed to classes. https://github.com/laravel/framework/commit/41599959d45016f0280d986f758d414fbee81863
Now You have to caught Illuminate\Database\Events\QueryExecuted event if You want to log sql queries.
You should define your listeners in EventServiceProvider.php like so:
protected $listen = [
'Illuminate\Database\Events\QueryExecuted' =>[
'App\Listeners\YourListener'
],
]
Adding this as an answer for #Hardy Mathew instead of a comment, since comments can't have code formatting:
Example Listener as requested:
<?php
namespace App\Listeners;
use Illuminate\Database\Events\QueryExecuted;
class QueryExecutedListener
{
public function handle(QueryExecuted $event)
{
dd($event);
}
}
Be sure to add the listener in the EventServiceProvider as told by #Giedrius Kiršys
Can someone give me a hint what I am doing wrong?
public function getPaymentSumByTypeAndProject($project_id,$type) {
$type = (int) $type;
$project_id = (int) $project_id;
$rowset = $this->tableGateway->select(array('total_amount' => new Expression('SUM(payment.amount)')))->where(array('type' => $type, 'project_id' => $project_id));
$row = $rowset->toArray();
if (!$row) {
throw new \Exception("Busted :/");
}
return $rowset;
}
I want to make the same query:
SELECT SUM(amount) FROM payment WHERE type='$type' AND project_id ='$project_id';
Edit:
I made small progress, i have figured out how to sum whole column
public function getPaymentSumByTypeAndProject($project_id, $type) {
$type = (int) $type;
$project_id = (int) $project_id;
$resultSet = $this->tableGateway->select(function (Select $select) {
$select->columns(array(new \Zend\Db\Sql\Expression('SUM(amount) as amount')))->where('type="0"');
});
return $resultSet;
Maybe someone could help me to figure out how to add condition: "WHERE type='$type' AND project_id='$project_id'" ?
I know this is an old question, but I came across it and figured I'd throw in my two cents:
public function getPaymentSumByTypeAndProject($project_id, $type) {
// This TableGateway is already setup for the table 'payment'
// So we can skip the ->from('payment')
$sql = $this->tableGateway->getSql();
// We'll follow the regular order of SQL ( SELECT, FROM, WHERE )
// So the query is easier to understand
$select = $sql->select()
// Use an alias as key in the columns array instead of
// in the expression itself
->columns(array('amount' => new \Zend\Db\Sql\Expression('SUM(amount)')))
// Type casting the variables as integer can take place
// here ( it even tells us a little about the table structure )
->where(array('type' => (int)$type, 'project_id' => (int)$project_id));
// Use selectWith as a shortcut to get a resultSet for the above select
return $this->tableGateway->selectWith($select);
}
Also, an adapter can be retrieved from a table gateway like this:
$adapter = $this->tableGateway->getAdapter();
But you don't really need it anymore when you select using the above mentioned method.
Ok now this is working, tell me is this how it;s should be done?
public function getPaymentSumByTypeAndProject($project_id, $type) {
$type = (int) $type;
$project_id = (int) $project_id;
$adapter = $this->tableGateway->adapter;
$sql = new Sql($adapter);
$select = $sql->select();
$select->from('payment');
$select->where(array('type'=>$type,'project_id'=>$project_id));
$select->columns(array(new \Zend\Db\Sql\Expression('SUM(amount) as amount')));
$selectString = $sql->getSqlStringForSqlObject($select);
$resultSet = $adapter->query($selectString, $adapter::QUERY_MODE_EXECUTE);
return $resultSet;
}
use This one
$select = $this->getSql()->select()
->columns(array('amount' => new \Zend\Db\Sql\Expression('SUM(amount)')))
->where("type ='$type'")
->where("project_id ='$project_id'");
$resultSet = $this->selectWith($select);
$row = $resultSet->current();
// echo $select->getSqlString();die; //check query use this line
if(!$row){
return False;
}
return $row->amount;
try to make like that instead of (int) $type
intval($type);
and
intval($project_id);
and in your sql
change your variables to
'".$type."'
AND
'".$project_id."'
I a, trying to implement a modification to the registration process in opencart. I have modified the form in the view and the values are posted to the account/customer.php model in which I have added some code to process my new fields as shown below:
/* add children and links to product categories */
$this->load->model('account/children');
//loop childrens names to use key for remaining info
foreach($data['children-name'] as $key=>$name){
//re-assign data and purify
$child['name'] = mysql_real_escape_string($name);
$child['surname'] = mysql_real_escape_string($data['children-surname'][$key]);
$child['gender'] = mysql_real_escape_string($data['children-gender'][$key]);
$child['dob'] = mysql_real_escape_string($data['children-dob'][$key]);
$child['school'] = mysql_real_escape_string($data['children-school'][$key]);
$child['unit'] = mysql_real_escape_string($data['children-unit'][$key]);
$child['height'] = mysql_real_escape_string($data['children-height'][$key]);
$child['chest'] = mysql_real_escape_string($data['children-chest'][$key]);
$child['waist'] = mysql_real_escape_string($data['children-waist'][$key]);
$child['waistToKnee'] = mysql_real_escape_string($data['children-waist-to-knee'][$key]);
$child['insideLeg'] = mysql_real_escape_string($data['children-inside-leg'][$key]);
$child['shoeSize'] = mysql_real_escape_string($data['children-shoe-size'][$key]);
$child['customerId'] = $customer_id;
//update/create child record
$this->model_account_children->addChild($child);
}
/* end add children and links to product categories */
I then created the relative model file in account/children.php in which has the following code:
class ModelAccountChildren extends Model {
public function addChild($data) {
//create other fields not in $data
$lastUpdated = date('Y-m-d h:i:s');
$childCat = getChildCategory($data['school']);
$dob = date('Y-m-d h:i:s', $date['dob']);
if($data['gender'] == 'm'){
$data['gender'] = 'Male';
}else{
$data['gender'] = 'Female';
}
echo "INSERT INTO " . DB_PREFIX . "customer_children (customer_id, child_name, child_surname, child_gender, child_dob, category_id, child_school, child_unit, child_height, child_chest, child_waist, child_waist_to_knee, child_inside_leg, child_shoe_size, child_last_updated) VALUES (".$data['customerId'].", '".$data['name']."', '".$data['surname']."', '".$data['gender']."', '".$dob."', ".$childCat['category_id'].", '".$data['school']."', '".$data['unit']."', '".$data['unit']."', '".$data['height']."', '".$data['chest']."', '".$data['waist']."', '".$data['waistToKnee']."', '".$data['insideLeg']."', '".$data['shoeSize']."', '".$lastUpdated."')";
//perform insert
$this->db->query("INSERT INTO " . DB_PREFIX . "customer_children (customer_id, child_name, child_surname, child_gender, child_dob, category_id, child_school, child_unit, child_height, child_chest, child_waist, child_waist_to_knee, child_inside_leg, child_shoe_size, child_last_updated) VALUES (".$data['customerId'].", '".$data['name']."', '".$data['surname']."', '".$data['gender']."', '".$dob."', ".$childCat['category_id'].", '".$data['school']."', '".$data['unit']."', '".$data['unit']."', '".$data['height']."', '".$data['chest']."', '".$data['waist']."', '".$data['waistToKnee']."', '".$data['insideLeg']."', '".$data['shoeSize']."', '".$lastUpdated."')");
}
public function updateChild($data) {
}
public function getChildCategory($childSchoolStr){
$query = $this->db->query("SELECT * FROM " . DB_PREFIX . "category_description WHERE name LIKE '" . $childSchoolStr . "'");
return $query->row;
}
}
For some reason the script is not getting access to the new model at the point I call it in model/account/customer.php on the line:
$this->load->model('account/children');
Am I doing something wrong?
Worked it out chaps.
$childCat = getChildCategory($data['school']);
Bit of a brain lapse, line above should be:
$childCat = $this->getChildCategory($data['school']);
It seems correct to me. You can use it within model. Do you use vqmod? Try deleting cache files.
Maybe add a test function to your model and see you can call it.
What is the error you get?
Have you definitely put the file in catalog/model/account/children.php ? If so, do you get any error messages at all that would help debug this? Also, when you run the code, are you certain that $data['children-name'] contains data?