I have some problems with sorting datas when i try type distance for example to 5 i have this error:
Unknown column 'dystans' in 'having clause'
SELECT COUNT(*) AS `numrows` FROM `meet` JOIN `category` ON `category`.`id` = `meet`.`category_id` HAVING `dystans` <= '5' ORDER BY `when` ASC
Filename: C:/xamppNew/htdocs/dzielimypasje/application/controllers/Meetings.php
Line Number: 177
Im using codeigniter. Line 177 is this
$data['count'] = $count = $this->db->count_all_results();
My controller:
$lat = $this->session->userdata('lat');
$lng = $this->session->userdata('lng');
// To pagination
$this->load->library('pagination');
$limit = 10;
$offset = $this->uri->segment(4);
$this->db->start_cache();
$this->db->select('*, meet.id,
(6731 * acos( cos( radians( '.$lat.')) * cos( radians( meet.lat)) *
cos( radians( meet.lng) - radians( '.$lng.')) + sin( radians( '.$lat.')) *
sin( radians( meet.lat)))) AS dystans');
//data from search engine
$level = $this->input->post('level');
$cat = $this->input->post('category');
$dystans = $this->input->post('dystans');
$when = $this->input->post('when');
if ($level) {
$this->db->where('level', $level);
}
if ($cat) {
$this->db->where('category_id', $cat);
}
if ($when) {
$this->db->where('when <=', $when);
}
if ($dystans) {
$this->db->having('dystans <=', $dystans);
}
$this->db->order_by('when', 'ASC');
$this->db->from('meet');
$this->db->join('category', 'category.id = meet.category_id');
$this->db->stop_cache();
// count for pagination
$data['count'] = $count = $this->db->count_all_results();
// to pagination
$this->db->limit($limit, $offset);
$data['meetings'] = $this->db->get();
$this->db->flush_cache();
$config = some config for pagination ...
$this->pagination->initialize($config);
$data['pagination'] = $this->pagination->create_links();
$this->load->view( 'site/meetings/index' , $data );
view:
<select type="text" name="dystans" placeholder="distance">
<option value="">Odległość</option>
<option value="1">Do 1 km</option>
<option value="2">Do 2km</option>
<option value="5">Do 5km</option>
<option value="10">Do 10km</option>
</select>
Any idea how to solve this ?? Propably its something with cache but im not sure, im new in this.
Alright. I dug into this and fixed everything I could find. I ditched active record for straight database access with query() function because...well...I have never liked active record and personally believe it is much much cleaner to write your query in an admin tool and copy it into your model. This gives you access to ALL of mysql's capabilities without having to jump through hoops (not to mention if you wind up using a different code base in the future you already have your queries and don't have to dig back through all of the active record code).
The main reason you were breaking at the dystans block was because you were trying to use a dynamically generated column within your where clause. The where clause only knows about columns that exist within the tables you have joined on. So to do what you are needing you have to run back through your formula.
I have also broken this out so that all of the filters will work in conjunction with one another. A user can now use filter when with filter dystans and the query will be build accordingly.
I haven't tested this code because obviously I do not have your database but it is the same way I code all of my applications. If you have trouble please let me know.
Also you should really consider breaking out your business logic or at least database interaction into a codeigniter model. Controllers should only ever act as a router between your models and views.
The link to my post on codeigniter pagination
<?php
$lat = $this->session->userdata('lat');
$lng = $this->session->userdata('lng');
// To pagination
$this->load->library('pagination');
$limit = 10;
$offset = (isset($this->uri->segment(4)) && is_numeric($this->uri->segment(4))) ? $this->uri->segment(4) : 0;
$bindArray = array();
$query = "SELECT *,"
. " (6731 * acos(cos( radians(?)) * cos( radians( meet.lat))"
. " * cos( radians( meet.lng) - radians(?)) + sin( radians(?))"
. " * sin( radians( meet.lat)))) AS dystans";
$bindArray[] = $lat;
$bindArray[] = $lng;
$bindArray[] = $lat;
$query .= " FROM meet JOIN category ON category.id = meet.category_id"
. " WHERE TRUE = TRUE";
//data from search engine
$level = $this->input->post('level');
$cat = $this->input->post('category');
$dystans = $this->input->post('dystans');
$when = $this->input->post('when');
if($level){
$query .= " AND meet.level = ?";
$bindArray[] = $level;
}
if($cat){
$query .= " AND meet.category_id = ?";
$bindArray[] = $cat;
}
if($when){
$query .= " AND meet.when <= ?";
$bindArray[] = $when;
}
if($dystans){
$query .= " AND (6731 * acos(cos( radians(?)) * cos( radians( meet.lat))"
. " * cos( radians( meet.lng) - radians(?)) + sin( radians(?))"
. " * sin( radians( meet.lat)))) <= ?";
$bindArray[] = $dystans;
}
$query .= "LIMIT ?,?";
$bindArray[] = $offset;
$bindArray[] = $limit;
$query_result = $this->db->query($query, $bindArray);
$data['count'] = $query_result->num_rows();
$data['meetings'] = $query_result->result();
$config = 'YOUR PAGINATION CONFIGURATION';
$this->pagination->initialize($config);
$data['pagination'] = $this->pagination->create_links();
$this->load->view( 'site/meetings/index' , $data );
Related
I'm trying to paginate items in a livewire component, I have this query
protected $listeners = [
'franchises:coords' => 'getFranchises'
];
public $franchiseList;
public function render()
{
return view('livewire.franchise-list', ['franchiseList' => $this->franchiseList]);
}
public function getFranchises($coords)
{
if ($coords) {
$latitude = json_decode($coords)[0];
$longitude = json_decode($coords)[1];
$radiusInMeters = 800;
$this->franchiseList = Franchise::select(DB::raw('*, ( 6371000 * acos( cos( radians(' . $latitude . ') )
* cos( radians( latitude ) ) * cos( radians( longitude ) - radians(' . $longitude . ') )
+ sin( radians(' . $latitude . ') ) * sin( radians( latitude ) ) ) ) AS distance'))
->having('distance', '<', $radiusInMeters)
->orderBy('distance')
->paginate(8);
}
}
the component is included in my "maps.blade"
<div class="lg:basis-1/4 md:basis-1/4 sm:px-6 lg:px-8">
<livewire:franchise-list/>
</div>
and in my blade view, I have this
#if(!empty($franchiseList))
{{$franchiseList->links()}}
#endif
but I get this error
Livewire component's [franchise-list] public property [franchiseList]
must be of type: [numeric, string, array, null, or boolean]. Only
protected or private properties can be set as other types because
JavaScript doesn't need to access them.
If I try to change pagination by adding these lines to the getFranchises function and adding $links to public
public $franchiseList, $links;
//after paginate
$this->links = $this->franchiseList;
$this->franchiseList = collect($this->franchiseList->items);
and in the blade change to this
#if(!empty($franchiseList) && $links->links())
{{$links->links()}}
#endif
I get this error
Error Cannot access protected property
Illuminate\Pagination\LengthAwarePaginator::$items
How can I paginate in livewire? where is the problem?
Ok, as I guess your issue is right there in render method. Instead of doing what you're doing, change this once you have in the mount the property initialized
public $franchiseList;
public function mount()
{
$this->franchiseList = [];
}
public function render()
{
return view('livewire.franchise-list');
}
So, as the property is public you can bind it in blade directly. At load component, it is an empty array and on event (in listener) this will change to passed value. That's the idea, but if you do this ['franchiseList' => $this->franchiseList] it's going to be crashed (when same name). I can't tell you why because I really don't know the answer but I know this happens from my experience.
I am progressively solving (always with your help) this Eloquent query but have not managed to completely solve it. Sorry to still staying at it, but I am struggling to my best.
I have written the query in two flavors. I would like to keep the Laravel one since I am using that but it is that one the one which doesn't work:
WORKS WHEN I DO IT ON PHPMYADMIN SQL WINDOW:
select properties.id, title, city, price, postedat, propertytype,
( 3959 * acos( cos( radians(43) ) * cos( radians( lat ) ) * cos( radians( lng ) - radians(-1.5) ) + sin( radians(43) ) * sin( radians( lat ) ) ) ) AS distance
from properties
join addresses
on properties.id_address_fk = addresses.id
where city = 'Biarritz'
HAVING distance < 100
ORDER BY distance
LIMIT 0, 20;
BELOW DOESN'T WORK (I get a: trying to get property from a non-object error)
$properties = DB::table('properties')
->join('addresses', 'properties.id_address_fk', '=', 'addresses.id')
->select('properties.id', 'title', 'city', 'price', 'postedat', 'propertytype',
DB::raw('3959 * acos( cos( radians(43) ) * cos( radians( lat ) ) * cos( radians( lng ) - radians (-1.5) )+ sin( radians(43) ) * sin( radians( lat ) ) ) as distance') );
if (!empty($location)) {
$properties = $properties->where('location', '=', $location);
}
if (!empty($propertytype)) {
$properties = $properties->where('propertytype', '=', $propertytype);
}
if (!empty($bedrooms)) {
$properties = $properties->where('bedrooms', '>=', $bedrooms);
}
if (!empty($transaction)) {
$properties = $properties->where('transaction', '=', $transaction);
}
if (!empty($minprice)) {
$properties = $properties->where('price', '>=', $minprice);
}
if (!empty($maxprice)) {
$properties = $properties->where('price', '<=', $maxprice);
}
$properties->having('distance', '<', 100)
->orderBy('distance', 'desc')
->skip(0)
->take(5)
->get();
return View::make('propertyfound', compact('premium', 'properties'));
UPDATE:
Of course, the errors are when it tries to get property from a non-object
#foreach($properties as $propfound)
<div class="row premium">
<div class="col-sm-3 col-xs-3">
<a href="{{URL::route('property', array($propfound->id) )}}" class="thumbnail " >{{ HTML::image("public/css/images/houses/$propfound->houses1")}}</a>
<h5>Guide price: £ {{$propfound->price}}</h5>
<h6>Bedrooms: {{$propfound->bedrooms}}</h6>
<h6>Days on site: 4</h6>
<h6>Sqft: {{$propfound->m2}}</h6>
</div>
<div class="col-sm-9">
<h3>{{$propfound->title}}</h3>
<p>{{$propfound->description}}</p>
<p class="hidden-xs">More details, 14 photos, floorplan and brochure | Save property | Contact agent | Upgrade listing</p>
<p class="hidden-xs">Marketed by Knight Frank, Richmond. Telephone: 0843 314 8224 BT 4p/min </p>
</div>
</div>
<hr />
#endforeach
You can't simply chain ->get() to the original DB object and get results.
// Doesn't work
$object->having()->take()->get();
foreach ( $object as $value ) {
// $value is some part of the query builder/eloquent object
}
You have to assign to a new variable
// Works
$results = $object->having()->take()->get();
foreach ( $results as $value ) {
// $value is db result
}
I have been using K2 Scroller module developed by Land of Coder. When I use this module to display same category items in the items view the module displays items in the ascending order of the date created and it is the default and only setting available in the module parameter settings in the back-end. However, I want the module to display the items in date wise descending order. So I chose to edit the default code in the helper which I suppose is used to process items based on the back-end settings. And this is the part of the code in the helper file which I think controls the order:
public function __getList( $params ){
global $mainframe;
/*some irrelevant code removed*/
$condition = $this->buildConditionQuery( $params );
$limitDescriptionBy = $params->get('limit_description_by','char');
$ordering = $params->get( 'k2_ordering', 'created_desc');
$limit = $params->get( 'limit_items', 5 );
$ordering = str_replace( '_', ' ', $ordering );
$my = &JFactory::getUser();
$aid = $my->get( 'aid', 0 );
/*some irrelevant code removed*/
$extraURL = $params->get('open_target')!='modalbox'?'':'&tmpl=component';
$excludeIds = $params->get('exclude_ids', '');
$db = &JFactory::getDBO();
$date =& JFactory::getDate();
$now = $date->toMySQL();
$dateFormat = $params->get('date_format', 'DATE_FORMAT_LC3');
$limitDescriptionBy = $params->get('limit_description_by','char');
$isAuthor= $params->get('itemAuthor',0);
require_once ( JPath::clean(JPATH_SITE.'/components/com_k2/helpers/route.php') );
$query = "SELECT a.*, cr.rating_sum/cr.rating_count as rating, c.name as categoryname,
c.id as categoryid, c.alias as categoryalias, c.params as categoryparams, cc.commentcount as commentcount".
" FROM #__k2_items as a".
" LEFT JOIN #__k2_categories c ON c.id = a.catid" .
" LEFT JOIN #__k2_rating as cr ON a.id = cr.itemid".
" LEFT JOIN (select cm.itemid as id, count(cm.id) as commentcount from #__k2_comments as cm
where cm.published=1 group by cm.itemid) as cc on a.id = cc.id";
$query .= " WHERE a.published = 1"
. " AND a.access get('featured_items_show','0') == 0 ){
$query.= " AND a.featured != 1";
} elseif( $params->get('featured_items_show','0') == 2 ) {
$query.= " AND a.featured = 1";
}
if( trim($excludeIds) ){
$query .= " AND a.id NOT IN(".$excludeIds.") ";
}
$query .= $condition . ' ORDER BY ' . $ordering;
$query .= $limit ? ' LIMIT ' . $limit : '';
$db->setQuery($query);
$data = $db->loadObjectlist();
/*some irrelevant code removed*/
return $data;
}
/**
* build condition query base parameter
*
* #param JParameter $params;
* #return string.
*/
public function buildConditionQuery( $params ){
$source = trim($params->get( 'k2_source', 'k2_category' ) );
if( $source == 'k2_category' ){
$catids = $params->get( 'k2_category','');
if( !$catids ){
return '';
}
$catids = !is_array($catids) ? $catids : '"'.implode('","',$catids).'"';
$condition = ' AND a.catid IN( '.$catids.' )';
} else {
$ids = preg_split('/,/',$params->get( 'k2_items_ids',''));
$tmp = array();
foreach( $ids as $id ){
$tmp[] = (int) trim($id);
}
$condition = " AND a.id IN('". implode( "','", $tmp ) ."')";
}
return $condition;
}
Am I editing the right part of the code or am I missing something else.
I am looking forward to your help
Thanks.
Maybe the best way would be to modify the xml file of the module.
I looked at the code of Lof K2Scroller (v 2.2 for Joomla 2.5) and the different ordering options are there.
However if you want to modify the default option, you are in the right file, just replace 'created_desc' for 'created_asc' .
How to get specific product attribute value if i know product ID without loading whole product?
Mage::getResourceModel('catalog/product')->getAttributeRawValue($productId, 'attribute_code', $storeId);
A way that I know of:
$product->getResource()->getAttribute($attribute_code)
->getFrontend()->getValue($product)
you can use
<?php echo $product->getAttributeText('attr_id') ?>
Please see Daniel Kocherga's answer, as it'll work for you in most cases.
In addition to that method to get the attribute's value, you may sometimes want to get the label of a select or multiselect. In that case, I have created this method which I store in a helper class:
/**
* #param int $entityId
* #param int|string|array $attribute atrribute's ids or codes
* #param null|int|Mage_Core_Model_Store $store
*
* #return bool|null|string
* #throws Mage_Core_Exception
*/
public function getAttributeRawLabel($entityId, $attribute, $store=null) {
if (!$store) {
$store = Mage::app()->getStore();
}
$value = (string)Mage::getResourceModel('catalog/product')->getAttributeRawValue($entityId, $attribute, $store);
if (!empty($value)) {
return Mage::getModel('catalog/product')->getResource()->getAttribute($attribute)->getSource()->getOptionText($value);
}
return null;
}
It seems impossible to get value without loading product model. If you take a look at file app/code/core/Mage/Eav/Model/Entity/Attribute/Frontend/Abstract.php you'll see the method
public function getValue(Varien_Object $object)
{
$value = $object->getData($this->getAttribute()->getAttributeCode());
if (in_array($this->getConfigField('input'), array('select','boolean'))) {
$valueOption = $this->getOption($value);
if (!$valueOption) {
$opt = new Mage_Eav_Model_Entity_Attribute_Source_Boolean();
if ($options = $opt->getAllOptions()) {
foreach ($options as $option) {
if ($option['value'] == $value) {
$valueOption = $option['label'];
}
}
}
}
$value = $valueOption;
}
elseif ($this->getConfigField('input')=='multiselect') {
$value = $this->getOption($value);
if (is_array($value)) {
$value = implode(', ', $value);
}
}
return $value;
}
As you can see this method requires loaded object to get data from it (3rd line).
First we must ensure that the desired attribute is loaded, and then output it. Use this:
$product = Mage::getModel('catalog/product')->load('<product_id>', array('<attribute_code>'));
$attributeValue = $product->getResource()->getAttribute('<attribute_code>')->getFrontend()->getValue($product);
Try this
$attribute = $_product->getResource()->getAttribute('custom_attribute_code');
if ($attribute)
{
echo $attribute_value = $attribute ->getFrontend()->getValue($_product);
}
You don't have to load the whole product.
Magentos collections are very powerful and smart.
$collection = Mage::getModel('catalog/product')->getCollection();
$collection->addAttributeToFilter('entity_id', $product->getId());
$collection->addAttributeToSelect('manufacturer');
$product = $collection->getFirstItem();
$manufacturer = $product->getAttributeText('manufacturer');
At the moment you call getFirstItem() the query will be executed and the result product is very minimal:
[status] => 1
[entity_id] => 38901
[type_id] => configurable
[attribute_set_id] => 9
[manufacturer] => 492
[manufacturer_value] => JETTE
[is_salable] => 1
[stock_item (Varien_Object)] => Array
(
[is_in_stock] => 1
)
This one works-
echo $_product->getData('ATTRIBUTE_NAME_HERE');
You can get attribute value by following way
$model = Mage::getResourceModel('catalog/product');
$attribute_value = $model->getAttributeRawValue($productId, 'attribute_code', $storeId);
$orderId = 1; // YOUR ORDER ID
$items = $block->getOrderItems($orderId);
foreach ($items as $item) {
$options = $item->getProductOptions();
if (isset($options['options']) && !empty($options['options'])) {
foreach ($options['options'] as $option) {
echo 'Title: ' . $option['label'] . '<br />';
echo 'ID: ' . $option['option_id'] . '<br />';
echo 'Type: ' . $option['option_type'] . '<br />';
echo 'Value: ' . $option['option_value'] . '<br />' . '<br />';
}
}
}
all things you will use to retrieve value product custom option cart order in Magento 2: https://www.mageplaza.com/how-get-value-product-custom-option-cart-order-magento-2.html
You could write a method that would do it directly via sql I suppose.
Would look something like this:
Variables:
$store_id = 1;
$product_id = 1234;
$attribute_code = 'manufacturer';
Query:
SELECT value FROM eav_attribute_option_value WHERE option_id IN (
SELECT option_id FROM eav_attribute_option WHERE FIND_IN_SET(
option_id,
(SELECT value FROM catalog_product_entity_varchar WHERE
entity_id = '$product_id' AND
attribute_id = (SELECT attribute_id FROM eav_attribute WHERE
attribute_code='$attribute_code')
)
) > 0) AND
store_id='$store_id';
You would have to get the value from the correct table based on the attribute's backend_type (field in eav_attribute) though so it takes at least 1 additional query.
If you have an text/textarea attribute named my_attr you can get it by:
product->getMyAttr();
I'm looking for a way to retrieve all products from a category includings its subcategories and return me a Product Collection.
I know I can iterate over categories to get ids of product and load them in the view, but I would have liked to get a product collection as it is done currently in most categories/views.
Any ideas?
I've solved this problem by implementing addCategoriesFilter in product collection model, here is the patch. Modified code to be copied to the local pool to allow updates to a newer version.
## -103,6 +103,7 ##
* Allowed filters
* store_id int;
* category_id int;
+ * category_ids array;
* category_is_anchor int;
* visibility array|int;
* website_ids array|int;
## -567,6 +568,21 ##
}
/**
+ * Specify categories filter for product collection
+ *
+ * #param array $categories
+ * #return Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection
+ */
+ public function addCategoriesFilter(array $categories)
+ {
+ $this->_productLimitationFilters['category_ids'] = $categories;
+
+ ($this->getStoreId() == 0)? $this->_applyZeroStoreProductLimitations() : $this->_applyProductLimitations();
+
+ return $this;
+ }
+
+ /**
* Join minimal price attribute to result
*
* #return Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection
## -1592,7 +1608,7 ##
$this->_productLimitationJoinPrice();
$filters = $this->_productLimitationFilters;
- if (!isset($filters['category_id']) && !isset($filters['visibility'])) {
+ if (!isset($filters['category_id']) && !isset($filters['category_ids']) && !isset($filters['visibility'])) {
return $this;
}
## -1604,11 +1620,16 ##
$conditions[] = $this->getConnection()
->quoteInto('cat_index.visibility IN(?)', $filters['visibility']);
}
- $conditions[] = $this->getConnection()
- ->quoteInto('cat_index.category_id=?', $filters['category_id']);
- if (isset($filters['category_is_anchor'])) {
+
+ if (!isset($filters['category_ids'])) {
$conditions[] = $this->getConnection()
- ->quoteInto('cat_index.is_parent=?', $filters['category_is_anchor']);
+ ->quoteInto('cat_index.category_id=?', $filters['category_id']);
+ if (isset($filters['category_is_anchor'])) {
+ $conditions[] = $this->getConnection()
+ ->quoteInto('cat_index.is_parent=?', $filters['category_is_anchor']);
+ }
+ } else {
+ $conditions[] = $this->getConnection()->quoteInto('cat_index.category_id IN(' . implode(',', $filters['category_ids']) . ')', "");
}
$joinCond = join(' AND ', $conditions);
Usage:
$category = $layer->getCurrentCategory();
$categories = $category->getAllChildren(true);
$collection = Mage::getResourceModel('catalog/product_collection');
$collection->addCategoriesFilter($categories);
You have to set that category to Anchor = Yes in de backend. That way your collection will nculde all the products form his subcategories.
If you wanted to show all products assigned to a category below the root category of a store you could do the following (or replace root category with the one you desire):
$root_category = Mage::getModel('catalog/category')->load(Mage::app()->getStore()->getRootCategoryId());
$all_cat_ids = explode(",", $root_category->getAllChildren());
$collection->joinField('category_id', 'catalog/category_product', 'category_id', 'product_id=entity_id', null, 'left');
$collection->addAttributeToFilter('category_id', array('in' => $all_cat_ids));
Hope this helps.
Similar to the answer by Matt, but without the "XXX already exists" error.
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
require_once 'app/Mage.php';
umask(0);
$app = Mage::app('admin');
$rootCategory = Mage::getModel('catalog/category')->load(17);
$collection = Mage::getResourceModel('catalog/product_collection');
$allCatIds = explode(",", $rootCategory->getAllChildren());
$collection
->getSelect()
->group('entity_id');
$collection
->joinField('category_id', 'catalog/category_product', 'category_id', 'product_id=entity_id', null, 'left')
->addAttributeToFilter('category_id', array('in' => $allCatIds));
echo $collection->count();
Sorry for the incomplete answer, but an approach that might work is to look at the category path for the parent (1/2/3) and use a query (on a category collection?) that grabs all descendents of that category (path like 1/2/3%). Then, you could use that to filter a product collection. Maybe someone else can flesh out those details and answer better :)