Converting a sql term into cake php - sql

I am trying to convert "left(SchoolCode,1) = '1'" which is in the sql i was provided into a correct field for the fine where statement. I am not a sql expert here but have been looking through cakephp documentation and can't seem to find a solution. any help would be appreciated.
The app i am creating, basically has a first screen where it shows the current year and 4 check boxes each with elementary middle and high. so if elementary is selected and submit is pressed then it executes that statement below giving back all records.
select *
from MMSD.vSchoolFromCalendar
where FiscalYear = 2019
and DistrictCode = 'MA'
and summerSchool = '0'
and left(SchoolCode,1) = '1'
public function getElementary()
{
$query = $this->find()
->where([
'FiscalYear' => '2019',
'DistrictCode' => 'MA',
'summerSchool' => '0',
'left(SchoolCode,1)' => '0',
]);
return $query->toArray();
}
My result should return the data with "and left(SchoolCode,1) = '1'" as a selected where field which right now it does not.

public function getSchoolsByLevel(string $code = '0', string $isSummerSchool = '0')
{
$query = $this->find()
->where([
'FiscalYear' => $schoolYear,
'DistrictCode' => 'MA',
'summerSchool' => $isSummerSchool,
'SchoolCode like' => $code,
]);
return $query->toArray();
}

Related

if in array when value null

I have a sql command like the following:
DB::table('tb_angsuran_lainlain')->insert(array(
array('id_kegiatan'=>'1','id_siswa'=>'26338','id_bulan'=>'1','nominal'=>'300000'),
array('id_kegiatan'=>'2','id_siswa'=>'26338','id_bulan'=>'1','nominal'=>'300000'),
array('id_kegiatan'=>'','id_siswa'=>'','id_bulan'=>'','nominal'=>''),
));
I want when the value is empty, it does not fill in the value in the table
array('id_kegiatan'=>'','id_siswa'=>'','id_bulan'=>'','nominal'=>''),
How to master ?
If I understood your question correctly, you only want to create a row for records that has some of their values filled.
To achieve that, use array_filter to get only those record that have some values:
$records = [
['some' => '1', 'key' => '2'],
['some' => '3', 'key' => '4'],
['some' => '', 'key' => ''],
];
$records = array_filter($records, function ($record) {
return count(array_filter($record));
});
DB::table('table_name')->insert($records);

How can I order a row into first position?

I have this form :
$builder
->add('restaurantsFilter1', 'entity', [
'label' => 'Commune',
'empty_value' => 'Dans toute la Narbonnaise',
'class' => 'AppBundle:City',
'choice_label' => 'name',
'query_builder' => function (EntityRepository $er) {
return $er
->createQueryBuilder('c')
->addSelect('d')
->leftJoin('c.documents', 'd')
->where('d.type = :type')
->orderBy('c.name')
->setParameter('type', Document::T_VILLAGE)
;
},
])
which is a select which displays a list of cities.
A client told me that he needed a field "Around me" which will display all cities around 20 km.
So to do so, I created a new city in my database with this name, but now I need to put it in the first position of my select.
In sql I would use something like ORDER BY (insee_code= '[specific_code_of_the_city]') but I dont know how I could that with the query builder.
Do you have an idea how I could do that with the symfony query builder ?
EDIT: That's the exact issue that How do I return rows with a specific value first?
You could create a hidden field and order by that.
return $er
->createQueryBuilder('c')
->addSelect('CASE
WHEN c.name = "specific_code_of_city"
THEN 0
ELSE 1
END as HIDDEN presetOrder')
->addSelect('d')
->leftJoin('c.documents', 'd')
->where('d.type = :type')
->orderBy('presetOrder', 'ASC')
->addOrderBy('c.name', 'ASC')
->setParameter('type', Document::T_VILLAGE)
;

Cakephp: find in a controller using "like" inside an array of possible values

The main idea of this post is that I need to combine search inside an array via "like" without doing a fetch.
In the following code I extract the zones (part of postal code) depending on session ID:
$sess_id = $this->Session->read('Auth.User');
$this->loadModel('Zone', 2);
$MyZones = $this->Zone->find('list', array('recursive' => -1, 'conditions' => array('Zone.user_id' => $sess_id['id']), 'fields' => array('Zone.zone')));
$this->set('MyZones', $MyZones);
print_r($MyZones);
//output : $MyZone = Array ( [1] => AB [2] => AL [3] => B1 )
Now that I have my array I want to look for persons who live in this zone (example his postalcode can be AB526PQ so he lives in the administrator zone)
$this->loadModel('Person', 2);
$num_persons = $this->Person->find('count', array('recursive' => -1, 'conditions' => array('Person.pc LIKE' => '%' . $MyZones)));
$this->set('num_persons', $num_persons);
I got the following error :
Notice (8): Array to string conversion [APP\Controller\ZonesController.php]
This is the generated sql query:
SELECT COUNT(*) AS `count` FROM `tn`.`personnes` AS `Personne` WHERE `Personne`.`pc` LIKE '%Array'
You will have to break your condition from
$conditions = array('Person.pc LIKE' => '%' . $MyZones);
to
foreach($MyZones as $MyZone) {
$conditions[] = array('Person.pc LIKE' => '%' . $MyZone);
}

Prestashop custom admin module draggable sort/order not working

I'm building a very simple module for Prestashop 1.6 and I added an admin interface that allows to list my records, a form to add and edit and delete.
This is working fine as you can see here:
The problem is that draggable reorder button is not draggable. Hence the reordering is not working...
According to the official docs, if you set the position option in your controller, you get the draggable functionality:
['position'] => 'position', // If set to position, the field will display arrows and be drag and droppable, which will update position in db (optional).
This is the relevant part of my module controller:
$this->fields_list = array(
'id_quicklinks' => array(
'title' => $this->l('ID'),
'align' => 'center',
'width' => 25
),
'titulo' => array(
'title' => $this->l('Titulo'),
'width' => 'auto'
)
, 'lead' => array(
'title' => $this->l('Subtitulo'),
'width' => 'auto'
),
'position' => array(
'title' => $this->l('Ordem'),
'filter_key' => 'a!position',
'position' => 'position',
'align' => 'center',
'class' => 'fixed-width-md'
),
'active' => array(
'title' => $this->l('Publicado'),
'width' => '25',
'active' => 'status'
)
);
As you can see in the print screen, is shows the handles but the drag-an-drop doesn't work. No javascript errors on the console, no nothing... And I can see in the source code that jQuery and jQueryUI are loaded. Other admin pages with reorder feature are working fine...
Any ideas?
Thanks.
Well, if anyone is interested, I managed to get this to work.
In my module admin controller, I've added (before the __construct method, right after opening the Class):
protected $position_identifier = 'id_quicklinks';
id_quicklinks is the primary key of the database table this module uses.
This enabled the drag and drop feature that I was looking for, but altough I could now drag and drop, the order was not saved in the database.
For that to work I've added two more methods adapted from the controllers/admin/AdminCarriersController.php and classes/Carrier.php:
public function ajaxProcessUpdatePositions()
{
$way = (int)Tools::getValue('way');
$id_quicklinks = (int)Tools::getValue('id');
$positions = Tools::getValue('quicklinks');
if (is_array($positions))
foreach ($positions as $position => $value)
{
$pos = explode('_', $value);
if (isset($pos[2]) && (int)$pos[2] === $id_velcroquicklinks)
{
if (isset($position) && $this->updatePosition($way, $position, $id_quicklinks))
echo 'ok position '.(int)$position.' for id '.(int)$pos[1].'\r\n';
else
echo '{"hasError" : true, "errors" : "Can not update id '.(int)$id_quicklinks.' to position '.(int)$position.' "}';
break;
}
}
}
And:
public function updatePosition($way, $position, $id)
{
if (!$res = Db::getInstance()->executeS('
SELECT `id_quicklinks`, `position`
FROM `'._DB_PREFIX_.'quicklinks`
ORDER BY `position` ASC'
))
return false;
foreach ($res as $quicklinks)
if ((int)$quicklinks['id_quicklinks'] == (int)$id)
$moved_quicklinks = $quicklinks;
if (!isset($moved_quicklinks) || !isset($position))
return false;
var_dump($moved_quicklinks['position']);
// < and > statements rather than BETWEEN operator
// since BETWEEN is treated differently according to databases
return (Db::getInstance()->execute('
UPDATE `'._DB_PREFIX_.'quicklinks`
SET `position`= `position` '.($way ? '- 1' : '+ 1').'
WHERE `position`
'.($way
? '> '.(int)$moved_quicklinks['position'].' AND `position` <= '.(int)$position
: '< '.(int)$moved_quicklinks['position'].' AND `position` >= '.(int)$position.'
'))
&& Db::getInstance()->execute('
UPDATE `'._DB_PREFIX_.'quicklinks`
SET `position` = '.(int)$position.'
WHERE `id_quicklinks` = '.(int)$moved_quicklinks['id_quicklinks']));
}
I hope this helps someone with the same problem.
Thank you for your solution.
It took me quite a long time to realize that ajaxProcessUpdatePositions() is somehow call by itself. For those struggling to implement that method, note that echo and var_dump() won't print anything when the method is called when moving element in your table.
Also, I found someway to optimize your code a little bit.
You could replace:
if (!$res = Db::getInstance()->executeS('
SELECT `id_quicklinks`, `position`
FROM `'._DB_PREFIX_.'quicklinks`
ORDER BY `position` ASC'
))
return false;
foreach ($res as $quicklinks)
if ((int)$quicklinks['id_quicklinks'] == (int)$id)
$moved_quicklinks = $quicklinks;
By :
if (!$moved_quicklinks = Db::getInstance()->executeS('
SELECT `id_quicklinks`, `position`
FROM `'._DB_PREFIX_.'quicklinks`
WHERE `id_quicklinks` = ' . (int) $id . '
LIMIT 1;'
))
return false;
The fewer rows (and fields) returned by the database is the best. Moreover, it remove the need of a loop in your PHP code.
You could also merge both your update queries in the same database call:
return (Db::getInstance()->execute('
UPDATE `'._DB_PREFIX_.'quicklinks`
SET `position`= `position` '.($way ? '- 1' : '+ 1').'
WHERE `position`
'.($way
? '> '.(int)$moved_quicklinks[0]['position'].' AND `position` <= '.(int)$position
: '< '.(int)$moved_quicklinks[0]['position'].' AND `position` >= '.(int)$position.'
') . '; UPDATE `'._DB_PREFIX_.'quicklinks`
SET `position` = '.(int)$position.'
WHERE `id_quicklinks` = '.(int)$moved_quicklinks[0]['id_quicklinks']);
Database calls are costly operations, so reducing them to the minimum is a must. Like in your PHP code, the second query won't be executed if the first fails.
Here's how my ajaxProcessUpdatePositions() looks like:
public function ajaxProcessUpdatePositions()
{
$id = (int) Tools::getValue('id');
$positions = Tools::getValue("priority_level");
$way = (boolean) Tools::getValue('way');
//"and $id" because an ID of 0 is invalid (at least if you are using an auto-increment PK)
if (is_array($positions) and $id)
{
foreach ($positions as $position => $value)
{
$pos = explode('_', $value);
if (isset($pos[2]) && (int) $pos[2] === $id)
{
$position = (int) $position;
if ($priorityLevel = Db::getInstance()->executeS(
'SELECT `id_priority_level`,
`priority_level`
FROM `pc_job_priority`
WHERE `id_priority_level` = ' . $id . '
LIMIT 1'
)) {
Db::getInstance()->execute(
'UPDATE `pc_job_priority`
SET `priority_level` = `priority_level` '.
($way ? '- 1' : '+ 1') . '
WHERE `priority_level`' . (
$way ?
' > '. (int) $priorityLevel[0]['priority_level'] .
' AND `priority_level` <= '. $position :
' < '. (int) $priorityLevel[0]['priority_level'] .
' AND `priority_level` >= '. $position
) . ';
UPDATE `pc_job_priority`
SET `priority_level` = ' . $position . '
WHERE `id_priority_level` = ' . $id
);
}
break;
}
}
}
}

Zend_Form Multiple dropdown as one value

For my zend form I would like a month drop down and a year drop down.
I would like them to appear next to each other. Its okay for them to be separate elements in the zend_form and combine and check them in the controller, but for the design I would like them to sit right next to each other.
I could accomplish this by setting no label on the year and then doing some css trickery, but I'd like a cleaner solution.
Edit, Final Code:
public function init($options=array()) {
$this->setName('add');
$this->setMethod('post');
$name = new Zend_Form_Element_Text('name');
$number = new Zend_Form_Element_Text('number');
$cvv = new Zend_Form_Element_Text('cvv');
$expiry_month = new Zend_Form_Element_Select('expiry_month');
$expiry_year = new Zend_Form_Element_Select('expiry_year');
$amount = new Zend_Form_Element_Select('amount');
$submit = new Zend_Form_Element_Submit('Submit');
$amounts = self::load_amounts();
$months = self::load_months();
$years = self::load_years();
$name->setLabel("Name On Card")->setIgnore(false)->setRequired(true);
$number->setLabel("Card Long Number")->setIgnore(false)->setRequired(true);
$cvv->setLabel("CVV2")->setIgnore(false)->setRequired(true);
$expiry_month->setMultiOptions($months);
$expiry_year->setMultiOptions($years);
$amount->setLabel("Amount")->setIgnore(false)->setRequired(true)->setMultiOptions($amounts);
$submit->setLabel("Submit")->setIgnore(true);
$this->addElements(array($name, $number, $cvv, $expiry_month, $expiry_year, $amount, $submit));
$this->addDisplayGroup(array('expiry_month', 'expiry_year'), 'Expires');
}
and if its helpful to anyone, I don't think you can set a label, but you can set a fieldset title via:
$this->addDisplayGroup(array('address', 'city', 'state', 'country', 'zip'), 'Address', array('legend' => 'Billing Address'));
I some code with a different approach, but you can have a label set for the row and both month and year appear on the same row. They are also validated together as one unit with a custom validation class, I'll post the part you asked here.
$expMonth = new Zend_Form_Element_Select('exp_month');
$expMonth->setLabel('Card Expiry Date:')
->addMultiOptions(
array('1' => '01', '2' => '02', '3' => '03', '4' => '04 shortened')
->setDescription('/');
$this->addElement($expMonth);
// Generate the Expiry Year options
$expYearOptions = array();
$thisYear = date('Y');
for ($i = 0; $i < 15; ++$i) {
$val = $thisYear + $i;
$expYearOptions[$val] = $val;
}
// The Expiry Year field
$expYear = new Zend_Form_Element_Select('exp_year');
$expYear->removeDecorator('label')
->addMultiOptions($expYearOptions)
->setDescription(' (Month / Year)');
$this->addElement($expYear);
// Setup Expiry Month decorators
$expMonth->setDecorators(array(
// Show form element
'ViewHelper',
// This opens the wrapping DD tag but doesn't close it, we'll close it on
// the year field decorator later
array(array('data' => 'HtmlTag'), array('tag' => 'dd', 'id' => 'card-expire',
'openOnly' => true)),
// Using this to slip in a visual seperator "/" between both fields
array('Description', array('tag' => 'span', 'class' => 'seperator')),
// Show the label tag displayed for exp_month
array('Label', array('tag' => 'dt'))
));
// Now for the Expiry Year field decorators
$expYear->setDecorators(array(
'ViewHelper',
// Inserting the "(Month / Year)" line using Description
array('Description', array('tag' => 'small', 'class' => 'greyout')),
// "row" is normally used to wrap a whole row, label + form element.
// I'm "misusing" it to close off the DD tag we opened in the month field earlier
// If you are already using "row", you might choose to echo the form line by line,
// where you close the dd tag manually like: echo
// $this->form->getElement('exp_year').'</dd>';
array(array('row' => 'HtmlTag'), array('tag' => 'dd', 'closeOnly' => true))
));
The full code with expiry validation can be found on my blog:
http://hewmc.blogspot.com/2010/08/validating-month-and-year-fields-as-one.html
I did the same task by creating a separate decorator.
ex: In your form init function use this
$decorators = array('ViewHelper',array('Description',array('tag'=>'','escape'=>false)),'Errors');
set a decorator in each element like:
$name = new Zend_Form_Element_Text('name');
$name->setDecorators($decorators);**
and after the following line
$this->addElements(array($name, $number, $cvv, $expiry_month, $expiry_year, $amount, $submit));
use this line of code:
$this->setDecorators (array('FormElements',array (array('data'=>'HtmlTag'), array('tag'=>'table')),'Form'));
now design your phtml according to your requirement use your control in form by their name like
$this->element->FirstName;