Insert multi record to database with yii2 - yii

I want to insert many record to database in one action.
In this controller I used foreach for insert to database, but just the last record inserts to database, I don't know why. I want to insert all the record to database.
My controller:
if (isset($_POST['month'])) {
$name = $_POST['month'];
$price = $_POST['Request'];
$i = 0;
foreach ($name as $month) {
$model->month = $month;
$model->price = $price['price'];
$model->save(false);
$i++;
}
$pay_info = [
'cost' => $price['price'],
'title' => 'title'];
return $this->render('payment', ['pay_info' => $pay_info]);
}

A simple way is based on the fact you should create a new model in you foreach for each instance you want save
(your controller code is not complete so i can't know your model )
if (isset($_POST['month'])) {
$name = $_POST['month'];
$price = $_POST['Request'];
$i = 0;
foreach ($name as $month) {
$model = new YourModel(); /* here */
$model->month = $month;
$model->price = $price['price'];
$model->save(false);
$i++;
}
$pay_info = [
'cost' => $price['price'],
'title' => 'title'];
return $this->render('payment', ['pay_info' => $pay_info]);
}
but i siggest to explore also the batchInsert command http://www.yiiframework.com/doc-2.0/yii-db-command.html#batchInsert()-detail
For batch insert you can build an asscociative array with month and price eg:
$my_array= [
['January', 30],
['Febrary', 20],
['March', 25],
]
\Yii::$app->db->createCommand()->
batchInsert('Your_table_name', ['month', 'price'],$my_array)->execute();

Related

Implement Phalcon 4 Database Existence validator (similar to Uniqueness)

Often I need to validate if given value is existing in certain column (attribute) of a table (model).
This can be useful in foreign keys of a model, to check if the given values exists.
Most probably the validation logic can be mostly the same as for Uniqueness, except the comparison here can be something like > 0.
A possible usage scenario could be like below:
$validator->add(
'organization_id',
new ExistenceOnDbValidator(
[
'model' => Organization::class,
'expr'=> ' id = %s ',
'excludeNullValue'=> true,
'message' => 'Organization does not exist.',
]
)
);
Finally I implemented myself a validator called ExistenceOnDbValidator and it works fine.
Usage
$validator = new Validation();
$validator->add(
'organization_id',
new ExistenceOnDbValidator(
[
'model' => Organization::class,
'expr' => ' id = %s ',
'ignoreNullValue' => false,
'message' => 'Selected organization does not exist.',
]
)
);
Implenentation
use Phalcon\Messages\Message;
use Phalcon\Validation;
use Phalcon\Validation\AbstractValidator;
use Phalcon\Validation\ValidatorInterface;
class ExistenceOnDb extends AbstractValidator implements ValidatorInterface
{
public function validate(Validation $validator, $attribute): bool
{
$expr = $this->getOption('expr');
$model = $this->getOption('model');
$value = $validator->getValue($attribute);
$ignoreNullValue = true;
if ($this->hasOption('ignoreNullValue')) {
$ignoreNullValue = $this->getOption('ignoreNullValue');
}
if ((is_null($value) || empty($value)) && $ignoreNullValue == true) {
return true;
}
$expr = sprintf(
$expr,
$value,
);
$result = $model::findFirst($expr);
if ((is_null($result) || empty($result))) {
$message = $this->getOption('message');
$validator->appendMessage(new Message($message));
return false;
}
return true;
}
}

get values between two dates in silverstripe

i have added two date fields. i want to retrieve the data between those two table.PaymentDate and ChequePostedDate are two fields. so i need to get the rows between two dates.
simply search content have two date fields. i want to retrieve the rows(data) between those two dates
public function __construct($modelClass, $fields = null, $filters = null) {
$fields = new FieldList(array(
DateField::create('PaymentDate','Payment Date : from')
->setConfig('dateformat', 'yyyy-MM-dd')
->setConfig('showcalendar', true)
->setAttribute('placeholder','YYYY-MM-DD')
->setDescription(sprintf(
_t('FormField.Example', 'e.g. %s', 'Example format'),
Convert::raw2xml(Zend_Date::now()->toString('yyyy-MM-dd'))
)),
DateField::create('ChequePostedDate','cr Date : to')
->setConfig('dateformat', 'yyyy-MM-dd')
->setConfig('showcalendar', true)
->setAttribute('placeholder','YYYY-MM-DD')
->setDescription(sprintf(
_t('FormField.Example', 'e.g. %s', 'Example format'),
Convert::raw2xml(Zend_Date::now()->toString('yyyy-MM-dd'))
)),
));
$filters = array(
'PaymentDate' => new PartialMatchFilter('PaymentDate'),
'ChequePostedDate' => new PartialMatchFilter('ChequePostedDate'),
);
parent::__construct($modelClass, $fields, $filters);
}
public function getQuery($searchParams, $sort = false, $limit = false, $existingQuery = null) {
$dataList = parent::getQuery($searchParams, $sort, $limit, $existingQuery);
$params = is_object($searchParams) ? $searchParams->getVars() : $searchParams;
$query = $dataList->dataQuery();
if(!is_object($searchParams)) {
if (isset($params['PaymentDate'])&& $params['ChequePostedDate'] ) {
$query->where('`PaymentNote`.PaymentDate BETWEEN \''.$params['PaymentDate'].' \' AND \''.$params['ChequePostedDate'].'\'');
}
}
return $dataList->setDataQuery($query);
}
}
You can also use WithinRangeFilter something like the following, but you need to use the setMin(), setMax() methods as per this forum response: https://www.silverstripe.org/community/forums/form-questions/show/11685
public function getQuery($searchParams, $sort = false, $limit = false, $existingQuery = null) {
$dataList = parent::getQuery($searchParams, $sort, $limit, $existingQuery);
$params = is_object($searchParams) ? $searchParams->getVars() : $searchParams;
$query = $dataList->dataQuery();
if(!is_object($searchParams)) {
if (!empty($params['PaymentDate'] && !empty($params['ChequePostedDate'])) {
return $dataList->filter('PaymentDate:WithinRange', [$params['PaymentDate'], $params['ChequePostedDate']]);
}
}
return $dataList;
}
i solved it..
simply remove $filters
$filters = array(
// 'PaymentDate' => new PartialMatchFilter('PaymentDate'),
//'ChequePostedDate' => new PartialMatchFilter('ChequePostedDate'),
);
then it works

How to create Category / Subcategory Friendly URL in PrestaShop?

I have a question about formatting the friendly URL for category and subcategory and getting the matching products. I am using PrestaShop 1.5.2.0
Let's say we have a structure like this:
Category 1
Spare Parts
Accessories
Category 2
Chips
Accessories
I want to display the link like this: /category-1/accessories and to display the products from category 1->accessories. How can I achieve this?
The current behavior is when I click on accessories, being in category 1, the link is /accessories and the products that are displayed belong from both /category-1/accessories and /category-2/accessories
Thanks!
This question was answered on the PrestaShop forum.
You can find it here http://www.prestashop.com/forums/topic/220017-category-subcategory-url/
The solution - add this changes to the fallowing classes
CLASSES/Dispatcher.php
'rule' => '{categories:/}{id}-{rewrite}/',
'categories' => array('regexp' => '[/_a-zA-Z0-9-\pL]*'),
CLASSES/Link.php
$cats = array();
foreach ($category->getParentsCategories() as $cat)
if (!in_array($cat['id_category'], array(1, 2, $category->id)))//remove root, home and current category from the URL
$cats[] = $cat['link_rewrite'];
$params['categories'] = implode('/', array_reverse($cats));
The above code is valid for the older versions, but it would not work for the newer/latest version. I updated the same solution for the newer version (1.7.7.4.), it might be used for others.
change CLASSES/Dispatcher.php
at about line 55 in the above file copy paste
public $default_routes = [
'category_rule' => [
'controller' => 'category',
**/** added 1 line below*/
'rule' => '{category:/}{id}-{rewrite}/',
/** commented 1line below*/
/**'rule' => '{id}-{rewrite}',*/
'keywords' => [
'id' => ['regexp' => '[0-9]+', 'param' => 'id_category'],
/*** added 1 line below*/
'category' => ['regexp' => '[_a-zA-Z0-9-\pL]*'],
'rewrite' => ['regexp' => self::REWRITE_PATTERN],
'meta_keywords' => ['regexp' => '[_a-zA-Z0-9-\pL]*'],
'meta_title' => ['regexp' => '[_a-zA-Z0-9-\pL]*'],**
],
],
In the file classes/link.php find the function getCategoryLink and replace it with the function code below
/**
* Create a link to a category.
*
* #param mixed $category Category object (can be an ID category, but deprecated)
* #param string $alias
* #param int $idLang
* #param string $selectedFilters Url parameter to autocheck filters of the module blocklayered
*
* #return string
*/
public function getCategoryLink(
$category,
$alias = null,
$idLang = null,
$selectedFilters = null,
$idShop = null,
$relativeProtocol = false
) {
$dispatcher = Dispatcher::getInstance();
if (!$idLang) {
$idLang = Context::getContext()->language->id;
}
$url = $this->getBaseLink($idShop, null, $relativeProtocol) . $this->getLangLink($idLang, null, $idShop);
// Set available keywords
$params = [];
if (!is_object($category)) {
$params['id'] = $category;
} else {
$params['id'] = $category->id;
}
// Selected filters is used by the module ps_facetedsearch
$selectedFilters = null === $selectedFilters ? '' : $selectedFilters;
if (empty($selectedFilters)) {
$rule = 'category_rule';
} else {
$rule = 'layered_rule';
$params['selected_filters'] = $selectedFilters;
}
if (!$alias) {
$category = $this->getCategoryObject($category, $idLang);
}
$params['rewrite'] = (!$alias) ? $category->link_rewrite : $alias;
if ($dispatcher->hasKeyword($rule, $idLang, 'meta_keywords', $idShop)) {
$category = $this->getCategoryObject($category, $idLang);
$params['meta_keywords'] = Tools::str2url($category->getFieldByLang('meta_keywords'));
}
if ($dispatcher->hasKeyword($rule, $idLang, 'meta_title', $idShop)) {
$category = $this->getCategoryObject($category, $idLang);
$params['meta_title'] = Tools::str2url($category->getFieldByLang('meta_title'));
}
if ($category !='var'){
$category = $this->getCategoryObject($category, $idLang);
$pcategory= new Category($category->id_parent, $idLang);
if($category->id_parent!=1 && $category->id_parent!=2){
$params['category'] = $pcategory->link_rewrite;
//append the categoryID with its name
$params['category'] = $category->id_parent . '-'. $params['category'];
}
}
return $url . Dispatcher::getInstance()->createUrl($rule, $idLang, $params, $this->allow, '', $idShop);
}
in the same file classes/link.php update if condition as follows at line 218 in the code for (function getProductLink)
if ($dispatcher->hasKeyword('product_rule', $idLang, 'categories', $idShop)) {
$product = $this->getProductObject($product, $idLang, $idShop);
$params['category'] = (!$category) ? $product->category : $category;
$cats = [];
foreach ($product->getParentCategories($idLang) as $cat) {
if (!in_array($cat['id_category'], Link::$category_disable_rewrite)) {
//remove root and home category from the URL
//commented the line below
//$cats[] = $cat['link_rewrite'];
//replaced the above line with the line below to append the category ID in the products link
$cats[] = $cat['id_category'].'-'.$cat['link_rewrite'];
}
}
$params['categories'] = implode('/', $cats);
}
I happened to be using the prestashop version 1.7.7.4. You can see this solution working on my site https://jinbaba.pk
Also after making the above changes in the code files, do not forget to update shopparameters-->SEO&URL Setting, change the category and product routes as follows (if they are not already like this)
"Route to category" = {category:/}{id}-{rewrite}
"Route to product" = {categories:/}{id}{-:id_product_attribute}-{rewrite}{-:ean13}.html
Just a suggestion for SEO : You do not need to remove category ID and product ID from the URL. They have minimal or no impact on SEO.
also the about solution will work for 2 level nesting e.g.
yourdomain.com/category-1/category-2/1-product.html
do not create more nesting of categories in your catalog. If you plan to do create deeper nesting your site you will need to update this solution. However, for SEO deep nesting is not recommended.

Yii CActiveRecord use search twice

I'm trying to create small application on Yii framework but can't understand one moment. I have Order model that extends from CActiveRecord and in index action I trying to use Order model twice but having some troubles.
The reason is to show paginated records in table and in last row I wish to show average totals for some fields, and this totals must be calculated for all records filtered by sort/filter criteria
Here is code of action:
public function actionIndex()
{
$model = new Order('search');
$model->unsetAttributes();
if (isset($_GET['Order']))
$model->attributes = $_GET['Order'];
// Get average totals by current filters
$totals = array();
$tm = clone $model;
$tmdp = $tm->search();
$tmdp->criteria->select = array('avg(price) as avgPrice', 'avg(cost) as avgCost');
$data = $tmdp->getData(true);
$totals['cost'] = number_format($data[0]->avgCost, 0, '.', ' ');
$totals['price'] = number_format($data[0]->avgPrice, 0, '.', ' ');
$totals['marja'] = Order::getMarjaVal(round($data[0]->avgCost, 0), round($data[0]->avgPrice, 0));
$this->render('index', array(
'model' => $model,
'totals' => $totals
));
}
In my view I'm getting data in the same way $data = $model->search()->getData();
So if I view first page - all working good, but if I change page then $data = $tmdp->getData(true); getting empty array. I also tried to set page for $tmdp like:
$tmdp->criteria->select = array('avg(price) as avgPrice', 'avg(cost) as avgCost');
$tmdp->pagination->setCurrentPage(0);
$data = $tmdp->getData(true);
but after this I getting data in my view only from first page.
Please can someone tell me how to do this correctly???
When we change current page in pagination Yii automatically updates $_GET['Order_page'] value (if this value wasn't setted - it will create it), and pagination automatically gets this value when we getting data from data provider. So for this code i made such changes:
public function actionIndex()
{
$model = new Order('search');
$model->unsetAttributes();
if (isset($_GET['Order']))
$model->attributes = $_GET['Order'];
// Get average totals by current filters
$totals = array();
$tm = clone $model;
$tdp = $tm->search();
$tdp->criteria->select = array('avg(price) as avgPrice', 'avg(cost) as avgCost');
if (isset($_GET['Order_page'])) {
$curPage = $_GET['Order_page'] - 1;
} else {
$curPage = 0;
}
$tdp->pagination->currentPage = 0;
$data = $tdp->getData(true);
$totals['cost'] = number_format($data[0]->avgCost, 0, '.', ' ');
$totals['price'] = number_format($data[0]->avgPrice, 0, '.', ' ');
$totals['marja'] = Order::getMarjaVal(round($data[0]->avgCost, 0), round($data[0]->avgPrice, 0));
$tdp->pagination->currentPage = $curPage;
$this->render('index', array(
'model' => $model,
'totals' => $totals
));
}
So we trying to get page from $_GET global array and after owr operation we just update this value back

codeigniter pagination for a query

So far found plenty of help to get the pagination working for a get(table) command.
What I need is to pick only few of the entries from a couple of linked tables based on a sql where statement.
I guess the query command is the one to use but in this case how do I do the pagination since that command does not take extra parameters such $config['per_page']
Thanks for the help
Without any more info to go on I think that what you're looking for is something like the following.
public function pagination_example($account_id)
{
$params = $this->uri->ruri_to_assoc(3, array('page'));
$where = array(
'account_id' => $account_id,
'active' => 1
);
$limit = array(
'limit' => 10,
'offset' => (!empty($params['page'])) ? $params['page'] : 0
);
$this->load->model('pagination_model');
$data['my_data'] = $this->pagination_model->get_my_data($where, $limit);
foreach($this->uri->segment_array() as $key => $segment)
{
if($segment == 'page')
{
$segment_id = $key + 1;
}
}
if(isset($segment_id))
{
$config['uri_segment'] = $segment_id;
}
else
{
$config['uri_segment'] = 0;
}
$config['base_url'] = 'http://'.$_SERVER['HTTP_HOST'].'/controller_name/method_name/whatever_your_other_parameters_are/page/';
$config['total_rows'] = $this->pagination_model->get_num_total_rows();// Make a method that will figure out the total number
$config['per_page'] = '10';
$this->load->library('pagination');
$this->pagination->initialize($config);
$data['pagination'] = $this->pagination->create_links();
$this->load->view('pagination_example_view', $data);
}
// pagination_model
public function get_my_data($where = array(), $limit = array())
{
$this->db
->select('whatever')
->from('wherever')
->where($where)
->limit($limit['limit'], $limit['offset']);
$query = $this->db->get();
if($query->num_rows() > 0)
{
$data = $query->result_array();
return $data;
}
return FALSE;
}
This should at least get you on the right track
If this isn't what you're asking I'd happy to help more if you can be a little more specific. How about some of your code.
The only other options that I can think of would be to either code a count in your select statement or not limit the query and use array_slice to select a portion of the returned array.