array_unshift command doesn't work properly in yii2 - yii2

I have a problem here. I have a drop-down list with a users and when I click on any user, it shows a clients which are assigned to it.
Now I've added Unassigned clients selection into the drop-down top to show which clients are unassigned. I've added it with a array_unshift() command, but now in some existing users (not all of it) it's not showing any clients, but these are assigned in the database.
When I remove array_unshift, the clients shows properly, but then there are no extra selection.
I'm thinking that there are something wrong with the array_unshift(), but not sure..
Here is my select function:
public static function getUsers()
{
$query = self::find()
->select(['id', "CONCAT(name, ' ', surname, ' (', email, ')') as name"]);
$users = ArrayHelper::map($query->asArray()->all(), 'id', 'name');
array_unshift($users, 'Test'));
return $users;
}

From PHP docs:
All numerical array keys will be modified to start counting from zero while literal keys won't be changed.
Use +:
public static function getUnmappedUsersList()
{
$query = self::find()
->select(['id', "CONCAT(name, ' ', surname, ' (', email, ')') as name"]);
return [Yii::t('app', 'ADMIN_PANEL_MIGRATE_UNASSIGNED_CLIENTS')]
+ ArrayHelper::map($query->asArray()->all(), 'id', 'name');
}

Related

Result of a soql parent to child soql request

I would to know how I can display the result from a soql child to parent request.
$query = "SELECT FirstName, LastName, (select Retreat_Booking__c.Retreat__c from Retreat_Bookings__r)FROM Contact"
$response = $mySforceConnection->query($query);
$queryResult = new QueryResult($response);
while($queryResult->current()->FirstName!='' || $queryResult->current()->LastName!='')
{
echo $queryResult->current()->FirstName." ".$queryResult->current()->LastName." ".$queryResult->current()->Retreat__c." <BR/>";
$queryResult->next();
}
The request works and display "FirstName" and "LastName" but not "Retreat__c".
I know the result in the 2nd select is a json and I tried many things, but nothing works.
Query should be like below
$query = "SELECT FirstName, LastName, (select Retreat_Booking__r.Retreat__c from Retreat_Bookings__c)FROM Contact";
That is,
Retreat_Booking__r.Retreat__c instead of Retreat_Booking__c.Retreat__c
and
from Retreat_Bookings__c instead of Retreat_Bookings__r
After FROM there should be the custom object name which is (extension is __c) Retreat_Bookings__c and retrieving data from a reference objects field, you should use __r extension and thus Retreat_Booking__r.Retreat__c
Update
For your 2nd question, you can try
$query = "SELECT FirstName, LastName, (select Retreat_Booking__r.Retreat__c from Retreat_Bookings__c) AS rb FROM Contact"
and then
while($queryResult->current()->FirstName!='' || `$queryResult->current()->LastName!='')
{
echo $queryResult->current()->FirstName." ".$queryResult->current()->LastName." ".$queryResult->current()->rb.Retreat__c" <BR/>";
$queryResult->next();
}`

Doctrine and Mysql data migration during table structure change

There is Entities User and Company. Company has user_id.
Now table structure changes and next one user can represent many companies and vice versa (Many to Many eg One to Many - Many to One). This introduces CompanyRepresentative Entity in the middle with fields user_id, company_id and role. Companies user_id will be dropped with that change.
How to make data migration script for that situation? There must be CompanyRepresentative entry for each company present right now that connects same user and company that are connected right now.
Environment is symfony 4 application with Doctrine and Mysql.
Doctrine migrations have functions preUp and postUp. In preUp it is possible to select all needed data and in postUp this data can be inserted to correct places after database structure changes.
For example
public function preUp(Schema $schema)
{
parent::preUp($schema);
$query = "SELECT id, user_id FROM company";
$data = $this->connection->prepare($query);
$data->execute();
foreach ($data as $row) {
$userId = $row['id'];
$companyId = $row['user_id'];
$this->customSQL[] = "($userId, $companyId)";
}
}
public function up(Schema $schema)
{
//Change the schema
}
public function postUp(Schema $schema)
{
parent::postUp($schema);
$SQL = 'INSERT INTO company_rep (user_id, company_id) VALUES ' . implode(', ', $this->customSQL);
$this->connection->executeQuery($SQL);
}
You have to use DoctrineMigrationBundle to do this. look at the documentation here, you should get away with it.

Multi-select Filter Search in Laravel 4

I need help/guidance in developing a multi-select filter search for my Laravel 4 app.
I have a table in my database called 'accounts'. This table is linked to other tables in the database via the following relationships:
'users' via belongs to (User model has a has many relationship to accounts)
'account_types' via belongs to (AccountType model has a has one relationship to accounts)
In my view I would like 3 multi-select boxes, company names (taken from the accounts table 'company_name' field), account managers (taken from the account_managers table, 'first_name' and 'last_name' fields) and account type (taken from the account_types table, 'type' field).
When a user selects values from these multi-select boxes and submits the form, I need to search the relevant tables and bring back the results. I don't want to use joins for this, as it is very slow. Especially, when bringing back values for the multi-select boxes.
If possible I would like to use Eloquent relationships in a way that brings back the results quickly.
I have this working with joins and query strings but it is very slow, up to 10 to 15 seconds.
I hope someone can help me out with this. Cheers.
OK, I have this working like a charm now by implementing select2, rather than simply loading all contacts in one go. Works much nicer too.
Here's my index method in AdminContactsController.php:
public function index()
{
$contact_names_value = explode(',', Input::get('contact_names_value'));
$accounts_value = explode(',', Input::get('accounts_value'));
$account_managers_value = explode(',', Input::get('account_managers_value'));
// In the view, there is a dropdown box, that allows the user to select the amount of records to show per page. Retrive that value or set a default.
$perPage = Input::get('perPage', 10);
// This code retrieves the order from that has been selected by the user by clicking on table ciolumn titles. The value is placed in the session and is used later in the Eloquent query and joins.
$order = Session::get('contact.order', 'cname.asc');
$order = explode('.', $order);
$message = Session::get('message');
$default = ($perPage === null ? 10 : $perPage);
$contacts_trash = Contact::contactsTrash($order)->get();
$this->layout->content = View::make('admin.contacts.index', array(
'contacts' => Contact::contacts($order, $contact_names_value, $accounts_value, $account_managers_value, $perPage)->paginate($perPage)->appends(array('accounts_value' => Input::get('accounts_value'), 'account_managers_value' => Input::get('account_managers_value'))),
'contacts_trash' => $contacts_trash,
'perPage' => $perPage,
'message' => $message,
'default' => $default
));
}
My scopeContacts method in my Contact.php model:
public function scopeContacts($query, $order, $contact_names_value, $accounts_value, $account_managers_value, $perPage)
{
$query->leftJoin('accounts', 'accounts.id', '=', 'contacts.account_id')
->leftJoin('users', 'users.id', '=', 'accounts.user_id')
->orderBy($order[0], $order[1])
->select(array('contacts.*', DB::raw('contacts.id as cid'), DB::raw('CONCAT(contacts.first_name," ",contacts.last_name) as cname'), DB::raw('CONCAT(users.first_name," ",users.last_name) as amname')));
if (empty($contact_names_value[0])) {
//
} else {
$query = $query->whereIn('contacts.id', $contact_names_value);
}
if (empty($accounts_value[0])) {
//
} else {
$query = $query->whereIn('accounts.id', $accounts_value);
}
if (empty($account_managers_value[0])) {
//
} else {
$query->whereIn('users.id', $account_managers_value);
}
}
Here's my JS code:
$('#contact_names_value').select2({
placeholder: 'Search contacts',
minimumInputLength: 3,
ajax: {
url: '/admin/get-contact',
dataType: 'json',
data: function (term, page) {
return {
contact_names_value: term
};
},
results: function (data, page) {
return {results: data};
}
},
tags: true
});
Here's my method getContactByName implemented in my AdminContactsController.php (similar methods implemented for users and accounts) code:
public function getContactByName()
{
$name = Input::get('contact_names_value');
return Contact::select(array('id', DB::raw('concat(first_name," ",last_name) as text')))->where(DB::raw('concat(first_name," ",last_name)'), 'like', "%$name%")->get();
}
Notice during my select statement, I do a DB::raw and set the 'first_name' and 'last_name' fields to be selected as 'text'. I think this was one of the major issues, as the plugin requires 'id' and 'text' to function.
My route was simply:
Route::get('admin/get-contact', 'AdminContactsController#getContactByName');

mysql_real_escape_string preventing unsanitized fields with bad characters from being added to the database

mysql_real_escape_string is preventing the unsanitized fields with bad characters from being added to the database. I don't want to have to specify all the fields on each form (since that's both cumbersome to do for each field and doesn't accommodate special characters which people may include or typos), but at the moment this code prevents anything from being inserted if any threatening characters are present in the unsanitized fields but still advances to the next page.
I'm also using jQuery validate on this page, but haven't been able to use that to prevent SQL injection.
function clean($str) {
$str = #trim($str);
if(get_magic_quotes_gpc()) {
$str = stripslashes($str);
}
return mysql_real_escape_string($str);
}
//Sanitize the POST values
$user_name = clean($_POST['user_name']);
$password = clean($_POST['password']);
//Create INSERT query
$qry = "INSERT INTO customer_info(fname, lname, gender, zip, email, phone, terms, security_question, security_answer, participating_retailers, notify_new_items, notify_promotions, priority1, priority2, priority3, priority4, priority5, privacy, user_name, password)
VALUES('$_POST[fname]','$_POST[lname]','$_POST[gender]','$_POST[zip]','$_POST[email]','$_POST[phone]','$_POST[terms]','$_POST[security_question]','$_POST[security_answer]','$_POST[participating_retailers]','$_POST[notify_new_items]','$_POST[notify_promotions]','$_POST[priority1]','$_POST[priority2]','$_POST[priority3]','$_POST[priority4]','$_POST[priority5]','$_POST[privacy]','$user_name','$password')";
$result = #mysql_query($qry);
$qry="SELECT * FROM customer_info WHERE user_name='$user_name' AND password='$password'";
$result=mysql_query($qry);
session_regenerate_id();
$member = mysql_fetch_assoc($result);
$_SESSION['SESS_USER_ID'] = $member['user_id'];
$_SESSION['SESS_FIRST_NAME'] = $member['fname'];
$_SESSION['SESS_LAST_NAME'] = $member['lname'];
session_write_close();
header("location: flatter-form.html");
exit();
mysql_query has been deprecated. PDO or mysqli both provide security against SQL injections. In addition to both having escaping functionality, PDO has the ability to also quote the string. Using prepared and parameterized queries makes it almost impossible for an attacker to inject SQL.
$stmt = $pdo->prepare('SELECT * FROM employees WHERE name = :name');
$stmt->execute(array(':name' => $name));
foreach ($stmt as $row) {
// do something with $row
}
Sample from: Prepared statements
Take a look at PDO vs. MySQLi.

How to insert array into mysql using PDO and bindParam?

I'm using the following code. The code works, but I want to change it so that it uses bindparam
try {
$dbh = new PDO("mysql:host=$hostname;dbname=$dbname", $username, $password);
$stqid=array();
for ($i=0; $i<$array_count; $i++){
$stqid[$i][0]=$lastInsertValue;
$stqid[$i][1]=$qid[$i][0];
$stqid[$i][2]=$qid[$i][1];
}
$values = array();
foreach ($stqid as $rowValues) {
foreach ($rowValues as $key => $rowValue) {
$rowValues[$key] = $rowValues[$key];
}
$values[] = "(" . implode(', ', $rowValues) . ")";
}
$count = $dbh->exec("INSERT INTO qresults(instance, qid, result) VALUES ".implode (', ', $values));
$dbh = null;
}
catch(PDOException $e){
echo $e->getMessage();
}
I replaced the following
$count = $dbh->exec("INSERT INTO qresults(instance, qid, result) VALUES ".implode (', ', $values));
with
$sql = "INSERT INTO qresults (instance, qid, result) VALUES (:an_array)";
$stmt = $dbh->prepare($sql);
$stmt->bindParam(':an_array', implode(',', $values),PDO::PARAM_STR);
$stmt->execute();
but the insert doesn't work anymore (I didn't get any error messages though).
QUESTION: What am I doing wrong? How can I rewrite the code to use bindParam?
You're trying to create a statement and bind a param.
Statement are great because it potentially nullify any kind of SQL injection. And it does it by removing the concept of a query being only seen as a string. The SQL query is seen as a string with a parameter list and an the associated data as binded variables.
So the query is not only text, but text + data.
I mean:
This simple query:
SELECT * FROM A WHERE val="$param"
It is not safe because the query is only viewed as a string. And if $param is not checked, it is a SQLi hole.
But when create a statement, your query becomes:
SELECT * FROM A WHERE val=:param
Then you use bindparam to specify the value a :param. Which mean the value is not appended to the query string, but the query is already parsed and the data is provided.
In your case, you bind to the param :array an imploded array (I assume "data1", "data2", etc..). Which is only one parameter with the value as a string ( "data1, data2, data3..." ), so it will only result in one insert and not multiple insertions.
You can change your statement generation by generating a query with enough parameters to handle your array
$sql = "INSERT INTO qresults (instance, qid, result) VALUES ( :val0, :val1, :val2, ...)";
Then loop on your array and call the bindparam method for each parameters.
$count = 0;
foreach($values as $val)
{
$stmt->bindParam(":val$count", $val,PDO::PARAM_STR);
$count++;
}
This will work.
Edit: This solution show how it works for a one dimensional array, but can be easily extended to your problem by tweaking the statement query generation and modify the bindparam loop.
Your statement should looks like:
$sql = "INSERT INTO qresults (instance, qid, result) VALUES (:val0, :val1, :val2) , (:val3, :val4, :val5), ...";
You just have to count the number of element in your base array.