Writing custom rules for CakePHP model - cakephp

use App\Model\Rule\CustomIsUnique;
$rules->add(new CustomIsUnique(['item_id', 'manufacture_unit_id']), [
'errorField' => 'item_id',
'message' => 'Item Unit must be unique.'
]);
On CustomIsUnique I've copy pasted codes of IsUnique
Cake\ORM\Rule\IsUnique;
But How to extend or add more operations inside the __invoke method ?
Update ::
public function __invoke(EntityInterface $entity, array $options)
{
$result = parent::__invoke($entity, $options);
if ($result) {
return true;
} else {
if ($options['type'] == 'item_units') {
$data = TableRegistry::get('item_units')->find()
->where(['item_id' => $entity['item_id'],
'manufacture_unit_id' => $entity['manufacture_unit_id'],
'status !=' => 99])->hydrate(false)->first();
if (empty($data)) {
return true;
}
} elseif ($options['type'] == 'production_rules') {
$data = TableRegistry::get('production_rules')->find()
->where(['input_item_id' => $entity['input_item_id'],
'output_item_id' => $entity['output_item_id'],
'status !=' => 99])->hydrate(false)->first();
if (empty($data)) {
return true;
}
} elseif ($options['type'] == 'prices') {
$data = TableRegistry::get('prices')->find()
->where(['item_id' => $entity['item_id'],
'manufacture_unit_id' => $entity['manufacture_unit_id'],
'status !=' => 99])->hydrate(false)->first();
if (empty($data)) {
return true;
}
}
}
}
this is how I've implemented for different model and passed extra parameter along with options array. I think this is not the good way to do this.

If you want to extend a core application rule, you can do something like:
<?php
use App\Model\Rule;
class CustomIsUnique extends Cake\ORM\Rule\IsUnique
{
public function __invoke(EntityInterface $entity, array $options)
{
$result = parent::__invoke($entity, $options);
if ($result) {
// the record is indeed unique
return true;
}
// do any other checking here
// for instance, checking if the existing record
// has a different deletion status than the one
// you are inserting
}
}
That will let you add any additional logic for your application.

Related

Retrive data using cakephp

I am new to cakephp and i want to find data that has been created
This is my sql function works
Select Trv_No from Ticket_LO
This is my model in cakephp
$ticket = $this->Ticket->find('first', array('conditions' => array('AND' => array('Ticket.TRV_No' => $trv_no)));
if(empty($ticket))
{
$table_name = 'Ticket_L0';
$this->Ticket->setSource($table_name);
//$ticket = $this->Ticket->find('first', array('conditions' => array('Ticket.TRV_No' => $trv_no)));
$ticket = $this->Ticket->find('first', array('conditions' => array('AND' => array('Ticket.TRV_No' => $trv_no, 'Ticket.HIDDEN_STAT LIKE' =>'0'))));
if(empty($ticket)) { return false; } else { return true; }
}
else
{ return true; }
}
First things first,
You don't need to set $this->Ticket->setSource($table_name); in your model.
You can use $this->find
I'm not sure what do you really want. But, I guess you want something like that.
$ticket = $this->find('first', array(
'conditions' => array(
'Ticket.TRV_No' => $trv_no,
'Ticket.HIDDEN_STAT'=> 0 //if you want to find 0 only, you don't need LIKE. But, if you want some string, you can use something like 'Ticket.HIDDEN_STAT LIKE'=>'yourString%'
)
)
);
And, you can add your condition after that.
if(!empty($ticket)) return true;
else return false;

Codeigniter Insert Array to Database

I have created a form in Codeigniter with a phone number field that dynamically is duplicated using javascript. So basically I can have one or more fields like this.
<input name="phone[]" value=""type="text">
<input name="phone[]" value=""type="text">
Then in my controller I have
$form_data = array(
'first_name' => $this->input->post('first_name'),
'last_name' => $this->input->post('last_name'),
'phone' => $this->input->post('phone[]')
);
Then I am saving this to my dabase like so
function SaveForm($form_data)
{
$this->db->insert('customers', $form_data);
if ($this->db->affected_rows() == '1')
{
return TRUE;
}
return FALSE;
}
but obviously the code for 'phone' is wrong, I just cant figure out how to properly do this.
you can't save array in to database. You can convert it in to string using implode() and whenever you needed then convert it back in array using explode(). Like below
$phone=implode(',',$this->input->post('phone'));
$form_data = array(
'first_name' => $this->input->post('first_name'),
'last_name' => $this->input->post('last_name'),
'phone' => $phone
);
OR
You can convert it to json string and when you needed convert back to Array Like below:
$phone = json_encode($this->input->post('phone'));
Convert back to array
$phone = json_decode($phone, TRUE);
Modify your function as below and it will works like charm,
function SaveForm($form_data)
{
foreach ($form_data as $contact)
{
$data[] = array(
'first_name' => $contact['first_name'],
'last_name' => $contact['last_name'],
'phone' => $contact['phone']
);
}
$this->db->insert_batch('customers', $data);
if ($this->db->affected_rows() > 0)
{
return TRUE;
}
return FALSE;
}
Modified:
Oh, yes you have to edit para array that you passed to SaveForm function.
Please use following code, ignore above code:
foreach($_POST['first_name'] as $key=>$fname)
{
$form_data[] = array(
'first_name' => $_POST['first_name'][$key],
'last_name' => $_POST['last_name'][$key],
'phone' => $_POST['phone'][$key],
);
}
function SaveForm($form_data)
{
$this->db->insert_batch('customers', $data);
if ($this->db->affected_rows() > 0)
{
return TRUE;
}
return FALSE;
}
In controller
$phone = $_POST['phone'];//this will store data as array. Check image 02
$form_data = array(
'first_name' => $this->input->post('first_name'),
'last_name' => $this->input->post('last_name'),
'phone' => $phone,//some times it works with '$phone'
);
In Model
function SaveForm($form_data)
{
$this->db->insert('customers', $form_data);
if ($this->db->affected_rows() == '1')
{
return TRUE;
}
else
{
return FALSE;
}
}
Tested
Image 01 (My form)
Image 02 (After Submitted)
mysql doesn’t has any array data type. So we can not store array directly into mysql database.
To do this we have to first convert array into string using php serialize() function then save it into mysql database.
for eg:php code to store array in database
$array = array("foo", "bar", "hello", "world");
$conn=mysql_connect('localhost', 'mysql_user', 'mysql_password');
mysql_select_db("mysql_db",$conn);
$array_string=mysql_escape_string(serialize($array));
To retrieve array from database
$conn=mysql_connect('localhost', 'mysql_user', 'mysql_password');
mysql_select_db("mysql_db",$conn);
$q=mysql_query("select column from table",$conn);
while($rs=mysql_fetch_assoc($q))
{
$array= unserialize($rs['column']);
print_r($array);
}
for array insertion to database use this programme in codeigniter controller=>
$inputdata=$this->input->post();
$phone=array($inputdata['phone']);
foreach($phone as $arr)
{
$phoneNo=$arr;
$f=count($phoneNo);
for($i=0;$i<$f;$i++)
{
$arre=[
'phone'=>$phoneNo[$i],
];
$insertB= $this->user_model->userdata($arre);
}
}
public function add_theme_pages(){
$page_name = $this->input->post('page');
$page_img = $this->input->post('page_img');
for($i=0; $i < count($page_name); $i++){
$pages_data = array(
'theme_id' => $this->input->post('theme_id'),
'theme_page_name' => $page_name[$i],
'theme_page_img' => $page_img[$i]
);
if($this->backendM->add_theme_pages($pages_data)){
$this->session->set_flashdata('message', 'Theme Added Successfully !');
$this->session->set_flashdata('message_class', 'green');
$this->create_template();
}else{
$this->create_template();
}
}
}

How to send data to custom block content

I'm trying to create a module that will display some last entries from database. I'd like to send last entry object to template file (guestbook-last-entries.tpl.php), that looks like that
<p><?php render($title); ?></p>
<?php echo $message; ?>
I have a function that implements hook_theme
function guestbook_theme() {
return array(
'guestbook_last_entries' => array(
'variables' => array(
'entries' => NULL,
),
'template' => 'guestbook-last-entries'
),
);
}
one that do preprocess
function template_preprocess_guestbook_last_entries(&$variables) {
$variables = array_merge((array) $variables['entries'], $variables);
}
and functions that implements hook_block_view
function guestbook_block_view($delta = '') {
switch ($delta) {
case 'guestbook_last_entries':
$block['subject'] = t('Last entries');
$block['content'] = array();
$entries = guestbook_get_last_entries(variable_get('guestbook_m', 3));
foreach ($entries as $entry) {
$block['content'] += array(
'#theme' => 'guestbook_last_entries',
'#entries' => $entry,
);
}
break;
}
return $block;
}
function that gets data from database
function guestbook_get_last_entries($limit = 3) {
$result = db_select('guestbook', 'g')
->fields('g')
->orderBy('posted', 'DESC')
->range(0, $limit)
->execute();
return $result->fetchAllAssoc('gid');
}
But in this case I get only one entry displayed. Can anyone tell me how to resolve this, how should I build that $block['content']?
Thank you
This here wont work:
$block['content'] += array(
'#theme' => 'guestbook_last_entries',
'#entries' => $entry,
);
Maybe you want this if you need an array as the result:
// note that I replaced += with a simple = and added two brackets that will create a new element in that array $block['content']
$block['content'][] = array(
'#theme' => 'guestbook_last_entries',
'#entries' => $entry,
);

CakePHP Pagination: how can I sort by multiple columns to achieve "sticky" functionality?

I see that this paginate can't sort two columns at the same time ticket is still open, which leads me to believe that what I'm trying to do is not possible without a workaround. So I guess what I'm looking for is a workaround.
I'm trying to do what many message boards do: have a "sticky" function. I'd like to make it so that no matter which table header link the user clicks on to sort, my model's "sticky" field is always the first thing sorted, followed by whatever column the user clicked on. I know that you can set $this->paginate['Model']['order'] to whatever you want, so you could hack it to put the "sticky" field first and the user's chosen column second. The problem with this method is that pagination doesn't behave properly after you do it. The table header links don't work right and switching pages doesn't work right either. Is there some other workaround?
User ten1 on the CakePHP IRC channel helped me find the solution. I told him that if he posted the answer here then I would mark it as the correct one, but he said I should do it myself since he doesn't have a Stack Overflow account yet.
The trick is to inject the "sticky" field into the query's "order" setting using the model's "beforeFind" callback method, like this:
public function beforeFind($queryData) {
$sticky = array('Model.sticky' => 'DESC');
if (is_array($queryData['order'][0])) {
$queryData['order'][0] = $sticky + $queryData['order'][0];
}
else {
$queryData['order'][0] = $sticky;
}
return $queryData;
}
What you can do is code it in the action. Just create the query you want when some parameters exist on the URL. (parameters has to be sent by GET)
For example:
public function posts(){
$optional= array();
if(!empty($this->params->query['status'])){
if(strlower($this->params->query['status']=='des')){
$optional= array('Post.status DESC');
}
else if(strlower($this->params->query['status']=='asc')){
$optional= array('Post.status ASC');
}
}
if(!empty($this->params->query['department'])){
//same...
}
//order first by the sticky field and then by the optional parameters.
$order = array('Post.stickyField DESC') + $optional;
$this->paginate = array(
'conditions' => $conditions,
'order' => $order,
'paramType' => 'querystring',
);
$this->set('posts', $this->paginate('Post'));
}
I have used something similar to filter some data using $conditions instead of $order and it works well.
You can use custom field for sorting and update pagination component.
Controller code
$order['Document.DATE'] = 'asc';
$this->paginate = array(
"conditions"=> $conditions ,
"order" => $order ,
"limit" => 10,
**"sortcustom" => array('field' =>'Document.DATE' , 'direction' =>'desc'),**
);
Changes in pagination component.
public function validateSort($object, $options, $whitelist = array()) {
if (isset($options['sort'])) {
$direction = null;
if (isset($options['direction'])) {
$direction = strtolower($options['direction']);
}
if ($direction != 'asc' && $direction != 'desc') {
$direction = 'asc';
}
$options['order'] = array($options['sort'] => $direction);
}
if (!empty($whitelist) && isset($options['order']) && is_array($options['order'])) {
$field = key($options['order']);
if (!in_array($field, $whitelist)) {
$options['order'] = null;
}
}
if (!empty($options['order']) && is_array($options['order'])) {
$order = array();
foreach ($options['order'] as $key => $value) {
$field = $key;
$alias = $object->alias;
if (strpos($key, '.') !== false) {
list($alias, $field) = explode('.', $key);
}
if ($object->hasField($field)) {
$order[$alias . '.' . $field] = $value;
} elseif ($object->hasField($key, true)) {
$order[$field] = $value;
} elseif (isset($object->{$alias}) && $object->{$alias}->hasField($field, true)) {
$order[$alias . '.' . $field] = $value;
}
}
**if(count($options['sortcustom']) > 0 )
{
$order[$options['sortcustom']['field']] = $options['sortcustom']['direction'];
}**
$options['order'] = $order;
}
return $options;
}
Easy insert 'paramType' => 'querystring',
Show Code Example:
$this->paginate = array(
'conditions' => $conditions,
'order' => array(
'Post.name' => 'ASC',
'Post.created' => 'DESC',
),
'paramType' => 'querystring',
);
$this->set('posts', $this->paginate('Post'));

CodeIgniter Session do not saving Array

i using CodeIgniter Session with database for save a array with $_FILES, but don't save. I do this (but the array never increment):
The post of form, redirects to himself.
Function to upload e load the page of upload.
public function getUpload($codtemp, $codmessage){
$this->load->library('session');
$this->layout = '';
$data = array();
$data['codmessage'] = $codmessage;
$data['codtemp'] = $codtemp;$tempfiles= $this->session->userdata('tempfiles');
if (isset($_FILES['attachment']))
{
$files = $this->fixGlobalFilesArray($_FILES['attachment']);
foreach($files as $file)
{
$tempfiles[$codtemp][] = $file;
}
$this->session->set_userdata('tempfiles', $tempfiles);
unset($files);
}
$this->parser->parse('attachment_upload', $data);
}
private static function fixGlobalFilesArray($files) {
$ret = array();
if(isset($files['tmp_name']))
{
if (is_array($files['tmp_name']))
{
foreach($files['name'] as $idx => $name)
{
$ret[$idx] = array(
'name' => $name,
'tmp_name' => $files['tmp_name'][$idx],
'size' => $files['size'][$idx],
'type' => $files['type'][$idx],
'error' => $files['error'][$idx]
);
}
}
else
{
$ret = $files;
}
}
else
{
foreach ($files as $key => $value)
{
$ret[$key] = self::fixGlobalFilesArray($value);
}
}
return $ret;
}
Before save the array, serialize the data and after get the data, unserialize. If data is empty, create a array

Resources