Magento 2.3 graphql get custom attribute option values - graphql

I’m pretty frustrated with the graphql api of Magento. How is it not possible to receive the values of a custom attribute. I mean it’s easy to make a custom select-option attribute and making it available through graphql but you are only getting the integer value.
What’s the best procedure to following
1. Query the complete attribute to get the value
2. Extending the graphql schema (this involves a developer every time the client changes something)
3. Am I missing some functionality inside the graphql endpoints to Fix this?

From Native GraqpQl we cannot get the expected result.But we can write a custom module with the graphql and achieve it.What my suggestion is get the product detail by sku using _productRepository->get($sku);. This will return the entire product details.So you can get the attribute data by using $attributes = $_product->getAttributes(); Here is my data provider file.
/**
* #params string $sku
* this function return all the product data by product sku
**/
public function getProductBySku($sku)
{
return $this->_productRepository->get($sku);
}
/**
* #params int $id
* this function return all the word of the day by id
**/
public function getAttributesBySku( $sku ){
$_product = $this->getProductBySku($sku);
$attributes = $_product->getAttributes();// All Product Attributes
$attributes_data = [];
$x=0;
foreach ($attributes as $attribute) {
if($attribute->getIsUserDefined()){ // Removed the system product attribute by checking the current attribute is user created
$attributeLabel = $attribute->getFrontend()->getLabel();
$attributeValue = $attribute->getFrontend()->getValue($_product);
if($attribute->getAttributeCode()=="language"){
$attributeLabelAndValue = $attributeLabel." - ".$attributeValue;
$attributes_data[$x]['atr_data'] = $attributeLabelAndValue;
}
}
$x++;
}
return $attributes_data;
}
This code will return the need
$attribute->getFrontend()->getLabel(); this will return the label and
$attribute->getFrontend()->getValue($_product); this will return the value.
To check the entire graphQl query and resolver file kindly view How to get product attribute value, label using GraphQl in Magento 2.3?
Hope this will help you.

You can try creating custom graphql attribute with custom resolver.
$product = $this->_productRepository->getById($value['entity_id']);
$data = array();
foreach ($args['fields'] as $fi) {
$att = $product->getResource()->getAttribute($fi);
if (isset($att) && $att) {
if (in_array(
$att->getFrontendInput(),
['multiselect', 'select']
)) {
$data[$fi . '_label'] = $product->getAttributeText($fi);
}
$data[$fi] = $product->getData($fi);
}
}
return json_encode((object) $data);
which should display all provided attributes with their labels.
"sku": "testProduct",
"fabric": 60,
"work": 65,
"dynamicAttributes": "{
"fabric_label":"Pure Silk",
"fabric":"60",
"work_label":"Tanchoi",
"work":"65"
}",
Check out entire module here

Related

Storing a new post tag if it doesn't exist in the table?

I have a single input field (using select2 plugin) in a blog post form which allow user to insert post tags from existing tags in the table or create new ones and store them in the Tag table and also attach them to the post when they hit submit post button. I've managed to get this work by filtering the input with array_filter(), if the input is !is_numeric the input will first get stored in Tag table and then attach the id to the post.
The problem with this is that it's not working when the new tag from the input is in full numeric type, like 2017 tag. Is there a solution to get this working so the new tag is not limited to string only but also numeric type ? and if possible, I don't want to use any package for this.
The post store method :
public function store(PostsReq $request) {
$input = $request->all();
$post = Post::create($input);
//Handle the tags
$getTags = $request->input('tagspivot');
$oldTags = array_filter($getTags, 'is_numeric');
$newTags = array_filter($getTags, function($item) {
return !is_numeric($item);
});
foreach ($newTags as $newTag) {
if ($tag = Tag::create(['title' => strtolower(trim($newTag))])) {
$oldTags[] = $tag->id;
}
}
$post->tags()->attach($oldTags);
// Upload Image
if ($request->hasFile('image')) {
$input['image'] = $this->uploadImage($request, $post);
}
return redirect()->route('postindex')->with($this->postStoreSuccess);
}
Here is three lines of code would be more than enough:
$tag = Tag::firstOrCreate([
'title' => $request->input('tagspivot'),
]);
You don't need to check for !is_numeric. However, in your form don't use tag id as value. use the title.

Magento _searchCriterias cannot be changed

I'm building a custom search results page, and I have the IDs of all products that have to be included in the results. I want to override the default search criteria, and yes, I can override $this->_searchCriterias, but it does not change the results page itself.
This is my custom code of CatalogSearch/Model/Advanced.php
public function getSearchCriterias()
{
$search = $this->_searchCriterias;
var_dump($search);
$search = array();
if(isset($_GET['productid'])) {
$value = $this->getIdsFromSearchUrl($_GET['productid']);
if(is_array($value)){
foreach($value as $v){
if(is_numeric($v)){
$product = Mage::getModel('catalog/product')->load($v);
var_dump($product->getId());
$search[] = array('name'=>'Name','value'=>$product->getName());
}
}
} else {
if(is_numeric($value)){
$product = Mage::getModel('catalog/product')->load($value);
$search[] = array('name'=>'Name','value'=>$product->getName());
}
}
}
var_dump($search);
$this->_searchCriterias = $search;
return $search;
}
Any help appreceated.
The way I understand is that you want the site to always include some "featured products", which are not necessarily related to the search term.
I would suggest an alternative method instead of tampering with the search engine logic:
Create a block and template for displaying featured products.
Add the block to Search engine result page inside the product_list block (under catalogsearch_result_index)
Modify list.phtml and echo out the child block you just added.
Let me know if this helps.

How to create an invoice for magento downloadable product?

I have an problem with invoice generating for my downloadable product.
I tried to create an invoice. But it shows like this error message Cannot create an invoice without products.
Can any one help to solve this issue.
Thanks
meaning that you have not selected the products that you need to invoice if you look at the code that gives this error in following file
app/code/core/Mage/Adminhtml/controllers/Sales/Order/InvoiceController.php:88: Mage::throwException($this->__('Cannot create an invoice without products.'));
you see that this error is given when no items are found
$savedQtys = $this->_getItemQtys();
$invoice = Mage::getModel('sales/service_order', $order)->prepareInvoice($savedQtys);
if (!$invoice->getTotalQty()) {
Mage::throwException($this->__('Cannot create an invoice without products.'));
}
and you can also see that the items are looked from your post
/**
* Get requested items qty's from request
*/
protected function _getItemQtys()
{
$data = $this->getRequest()->getParam('invoice');
if (isset($data['items'])) {
$qtys = $data['items'];
} else {
$qtys = array();
}
return $qtys;
}
meaning that you have not selected or posted whatever needs to be posted to this method.

codeigniter count_all_results

I'm working with the latest codeIgniter released, and i'm also working with jquery datatables from datatables.net
I've written this function: https://gist.github.com/4478424 which, as is works fine. Except when I filter by using the text box typing something in. The filter itself happens, but my count is completely off.
I tried to add in $res = $this->db->count_all_results() before my get, and it stops the get from working at all. What I need to accomplish, if ($data['sSearch'] != '') then to utilize the entire query without the limit to see how many total rows with the search filter exists.
If you need to see any other code other than whats in my gist, just ask and I will go ahead and post it.
$this->db->count_all_results() replaces $this->db->get() in a database call.
I.E. you can call either count_all_results() or get(), but not both.
You need to do two seperate active record calls. One to assign the results #, and one to get the actual results.
Something like this for the count:
$this->db->select('id');
$this->db->from('table');
$this->db->where($your_conditions);
$num_results = $this->db->count_all_results();
And for the actual query (which you should already have):
$this->db->select($your_columns);
$this->db->from('table');
$this->db->where($your_conditions);
$this->db->limit($limit);
$query = $this->db->get();
Have you read up on https://www.codeigniter.com/userguide2/database/active_record.html#caching ?
I see you are trying to do some pagination where you need the "real" total results and at the same time limiting.
This is my practice in most of my codes I do in CI.
$this->db->start_cache();
// All your conditions without limit
$this->db->from();
$this->db->where(); // and etc...
$this->db->stop_cache();
$total_rows = $this->db->count_all_results(); // This will get the real total rows
// Limit the rows now so to return per page result
$this->db->limit($per_page, $offset);
$result = $this->db->get();
return array(
'total_rows' => $total_rows,
'result' => $result,
); // Return this back to the controller.
I typed the codes above without testing but it should work something like this. I do this in all of my projects.
You dont actually have to have the from either, you can include the table name in the count_all_results like so.
$this->db->count_all_results('table_name');
Count first with no_reset_flag.
$this->db->count_all_results('', FALSE);
$rows = $this->db->get()->result_array();
system/database/DB_query_builder.php
public function count_all_results($table = '', $reset = TRUE) { ... }
The
$this->db->count_all_results();
actually replaces the:
$this->db->get();
So you can't actually have both.
If you want to do have both get and to calculate the num rows at the same query you can easily do this:
$this->db->from(....);
$this->db->where(....);
$db_results = $this->get();
$results = $db_results->result();
$num_rows = $db_results->num_rows();
Try this
/**
* #param $column_name : Use In Choosing Column name
* #param $where : Use In Condition Statement
* #param $table_name : Name of Database Table
* Description : Count all results
*/
function count_all_results($column_name = array(),$where=array(), $table_name = array())
{
$this->db->select($column_name);
// If Where is not NULL
if(!empty($where) && count($where) > 0 )
{
$this->db->where($where);
}
// Return Count Column
return $this->db->count_all_results($table_name[0]);//table_name array sub 0
}
Then Simple Call the Method
Like this
$this->my_model->count_all_results(['column_name'],['where'],['table name']);
If your queries contain a group by, using count_all_results fails. I wrote a simple method to work around this. The key to preventing writing your queries twice is to put them all inside a private method that can be called twice. Here is some sample code:
class Report extends CI_Model {
...
public function get($page=0){
$this->_complex_query();
$this->db->limit($this->results_per_page, $page*$this->results_per_page);
$sales = $this->db->get()->result(); //no table needed in get()
$this->_complex_query();
$num_results = $this->_count_results();
$num_pages = ceil($num_results/$this->results_per_page);
//return data to your controller
}
private function _complex_query(){
$this->db->where('a', $value);
$this->db->join('(subquery) as s', 's.id = table.s_id');
$this->db->group_by('table.column_a');
$this->db->from('table'); //crucial - we specify all tables here
}
private function _count_results(){
$query = $this->db->get_compiled_select();
$count_query = "SELECT count(*) as num_rows FROM (".$query.") count_wrap";
$r = $this->db->query($count_query)->row();
return $r->num_rows;
}
}

Programmatically change product attribute at store view level

I'm sorry if this question is trivial but I've been struggling to find what I am doing wrong here. I am trying to change the value of an attribute on a store view level but the default is also changed whereas it shouldn't be. Of course, this attribute is set up to be "store-view-scoped". To keep it simple, I've tried with the product name. No success.
Below are unsuccessful tests I've tried...
Do you see what I am doing wrong here?
Many thanks.
My tries :
$product = Mage::getModel('catalog/product')->load(PRODUCT_ID);
$product->setStoreId(STORE_ID)->setName('new_name')->save();
$product = Mage::getModel('catalog/product')->load(PRODUCT_ID);
$product->setStoreId(STORE_ID)->setStore(STORE_CODE)->setName('new_name')->save();
$product = Mage::getModel('catalog/product')->load(PRODUCT_ID);
$product->setStoreId(STORE_CODE)->setName('new_name')->save();
$product = Mage::getModel('catalog/product')->setStoreId(STORE_ID)->load(PRODUCT_ID);
$product->setName('new_name')->save();
$product = Mage::getModel('catalog/product')->setStoreId(STORE_ID)->load(PRODUCT_ID);
$product->setStoreId(STORE_ID)->setName('new_name')->save();
I even tried by adding the line below before the product model load...
Mage::app()->setCurrentStore(STORE_ID);
So here is the complete snippet to change attribute value for a specific product attribute on a specific store view. Example with the product name :
Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID);
$product = Mage::getModel('catalog/product')->load(PRODUCT_ID);
$product->setStoreId(STORE_ID)->setName('my_new_product_name')->save();
And as an additional answer, one could be interested in changing the attribute value to the default one. In this case, the argument 'false' must be passed to the setAttribute :
Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID);
$product = Mage::getModel('catalog/product')->load(PRODUCT_ID);
$product->setStoreId(STORE_ID)->setName(false)->save();
You need to set the current store to admin at the top of your code block:
Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID);
note when loading product with data for some store view, also default values get loaded. saving such product will save default values as store values (thus unset "Use Default Value" for fields)
i ended up with following function to clean-up product data from default values
public static function _removeDefaults($item) {
static $attributeCodes = null;
if($attributeCodes == null) {
$attributes = Mage::getSingleton('eav/config')
->getEntityType(Mage_Catalog_Model_Product::ENTITY)->getAttributeCollection();
$attributeCodes = array();
foreach($attributes as $attribute) {
$ac = $attribute->getAttributeCode();
if(in_array($ac, array('sku','has_options','required_options','created_at','updated_at','category_ids'))) {
continue;
}
$attributeCodes[] = $ac;
}
}
foreach($attributeCodes as $ac) {
if(false == $item->getExistsStoreValueFlag($ac)) {
$item->unsetData($ac);
}
}
}
remember to send only product loaded for some store view

Resources