Nestable tree structure handle with left and right value
I already done the functionality of add parent node, child node and delete node.
But How to save tree value after moving nodes drag and drop with the nestable.js
Lest see my output what I want to do....
i want to manage with data-left, data-right values
And my database structure is
Please help in this how to manage drag and drop functionality.
I tried to comment this, but the website tells me I need 50 Reputation in order to do so, so this may or may not answer your question, I'd have to wait until I got home when I could fiddle with something similar in database / Javascript structure.
I'm fairly familiar with left/right_id tables and such. The first place I saw them was in phpBB3.0 and I spent a whole lot of time reading up on them.
One thing you could do to help you expedite your queries is to add a parent_id column, this way you can immediately get ALL the child notes without having to use "left_id > 1 AND right_id < 8" in your SQL statements.
Now, for your javascript question, how I will try to go about this when I get home is to declare an array of id keys => child values. So, in the screenshot example you've given above you could hopefully get to something like this
array(
2 => array(
5 => array(
3
),
6
),
3 => array(
8
),
4
)
In order to get this you'd have to loop through the DOM for each member of the list, using their id's and the array.push function to add values as necessary.
I'll try and help more once I can get to my house where I have a PHP server setup, but this should give you an Idea of how to get it started.
Are you using any Javascript framework (such as MooTools, jQuery)?
Edit:
So, I've worked on it for quite some time and I've got a general thing working. Below is the code directly responsible for looping through the DOM tree and assigning left/right_id values. It should be fairly easy to edit it for your liking.
I have a preference for MooTools, so I wrote this using the mootools library (it offers some Element features that are quite nice and in fact gave me a multi-level drag and sort tool to test this with). If you prefer to use another library, it should be fairly easy to switch the code to work for it, but I do not use jQuery so I am unfortunately not helpful in that regard
Link to download all files involved: Here
function calculate_ids(el,left_id, parent_id){
var el = $(el);
//makes the element a MooTools Element
var left_id = left_id || 1;
//If left_id is given, we are using this function recursively
var parent = parent_id || 0;
//Gives us a quick method in order to figure out what level we are currently on
var id_array = {};
/*ID array object will look like
{
1:{
'left_id':1,
'right_id':2,
'parent':0
},
2:{
'left_id':3,
'right_id':6,
parent_id:0
},
3:{
'left_id':4,
'right_id':5
},
etc.
}
*/
var els = el.getChildren('li');
//Get the immediate children
els.each(function(child){
var id = child.get('id');
//The ID
var descendants = child.getElements('li');
//Gets ALL most descendent children that match the format, these are ordered the way they are in the DOM
var right_id = left_id + descendants.length * 2 + 1
id_array[id] = {
'left_id':left_id,
'right_id':right_id,
'parent':parent
};
if(descendants.length > 0){
//There are child elements to this thing, recursion!
id_array = Object.merge(id_array, calculate_ids( child.children[0], left_id + 1, id) );
}
left_id = right_id + 1;
//Increment the left_id counter
});
return id_array;
}
Known Issues
The example code I posted doesn't correctly calculate the left/right ids after they've been calculated a first time or moved up/down a level if they were calculated previously. I'm guessing this has something to do with how the multi-level sort class moves the items around. This code is meant to serve as a starting point. I'm really busy (unfortunately), so I may or may not be able to fix this issue in the future, but either way this code should serve as a great starting point.
Related
I am working on a Laravel project where people can post tiles on a page then click a button to move them up or down on the page. Currently I have a table setup for tiles like so:
$table->string('tile_name');
$table->text('tile_rules');
$table->integer('tile_order');
Then on the frontend I have a button should either move the tile up or down depending which arrow you press. For my up function I thought I could just take the current order from the Tile and Add which does work in its simplest form, but my question is what is the best approach for looping back through and updating all the other tiles on the page? I think it is also fair to say there will never likely be more than ten tiles on a page that would need reordering.
I was thinking this must be do able with a foreach loop:
$currentOrder = $currentTile->tile_order;
foreach($Tiles as $tile) {
Tiles::whereKey($tile->id)->update(['tile_order' => ++$order]);
}
but what I missing is how do I tell it to start at a particular tile and only update the tiles above or below it depending on whether or not I am moving it up or moving it down?
If someone could push me in the right direction that would be greatly appreciated!
I debated handling on the frontend and allowing the user to save the order when they had completed it, but instead I created an Up and Down function that would find the item above or below it and just switch the order integer with it. This seems to work better than looping through everything and updating the count.
if ($tileAbove == 0) {
session()->flash('message', 'This Tile can not be moved any higher');
} else {
//Update the current Tile to the new order and tileAbove to the old order
$tileAboveObj = $positionTiles->filter(function($item) use ($tileAbove) {
return $item->tile_order == $tileAbove;
})->first();
Tiles::whereKey($currentTile->id)->update(['tile_order' => $tileAbove]);
Tiles::whereKey($tileAboveObj->id)->update(['tile_order' => $currentTileOrder]);
}
with $tileAbove just being the current tile order subtracted by 1.
I've checked the lib.php in the course folder but I don't understand what it's doing so I'm going to ask here.
I am trying to create a course with PHP and MySQL code, not with the Moodle API, by hooking up with the Moodle database.
So far, I've written a method to create a course by inserting values into the mdl_course table but nothing shows up in course homepage. It's in the database, it's enrollable and it's also visible but it doesn't show up.
I know course_sections and course_category is affected when a new course is created but how do calculate what values to put into each field?
What is modinfo in mdl_course? How do I calculate this?
How do I calculate sortorder in mdl_course? Right now I am finding the category of the where the course will be placed, then I find all the sortorders in that category, then I increment it by 1 as my new sortorder value. I'm not sure if that is correct.
Right now this is my method to create a course, obviously it is no where near complete:
public function createCourse()
{
//find category
//calculate sortorder i.e. search in mdl course for all course with category. select sortorder MAX then ++
require "/mysqli_connect.php";
$t = time();
$insert_q = "INSERT INTO mdl_course
(category, fullname, shortname, summary, startdate, maxbytes,
timecreated, newsitems, numsections, expirythreshold)
VALUES (30, 'Fullname', 'shortname', 'This is the summary', '$t', 268435456, '$t', 5, 10, 864000)";
$insert_r = mysqli_query($mysqli, $insert_q);
$insert_n = mysqli_affected_rows($mysqli);
//var_dump($insert_n);
if($insert_n == 1)
{
return true; //insert successful
}
else
{
return false;
}
}
In my experience, Moodle is not the simplest or the most transparent system to graft your own code onto. An individual entity has many different table entries. For example, a lesson will appear in mdl_lessons, mdl_course_modules, mdl_grade items, and others. I would suggest using Moodle's own API for as much as possible. If you can't do that, you could try reverse-engineering it by adding a course through the standard interface, then checking your SQL log to see what table entries it made.
Regarding the bewildering mess that is modinfo, this post on the moodle forums says that it's automatically generated. This post explains that once a course's lessons and activities are all in place, you can call rebuild_course_cache($courseid) to repopulate modinfo.
I'm trying to create configurable products programmatically in Magento 1.5.1.
I understand I need first to create simple related products, what I did. Now I manage to associate these simple products to make a configurable one.
Here is the critical part...
I keep the ids and some of the attributes values in an array, so I can later make my configurable product, but some of them are missing, I don't know which method to call.
I found this entry in Magento Wiki, that helped me and seems to fit my needs.
However, at the end the author is setting two things :
$product->setConfigurableProductsData($data);
$product->setConfigurableAttributesData($data);
and the values in the arrays have been taken in the admin page source using Firebug....and then translated into PHP arrays (array example for the first call) :
"I’ve harcoded the values for my associated products and attribute
data. You can get attribute data by viewing the source through the
admin interface and using Firebug for Firefox."
$data = array('5791'=>array('0'=>array('attribute_id'=>'491', // I already got this
'label'=>'vhs', // this too
'value_index'=>'5', // but what is value_index ?
'is_percent'=>0,
'pricing_value'=>'')),
'5792'=>array('0'=>array('attribute_id'=>'491',
'label'=>'dvd',
'value_index'=>'6',
'is_percent'=>0,
'pricing_value'=>'')));
My question is : is there a way to retrieve these values without using Firebug (which in my script won't help me a lot !), but programmatically. I already found a way to retrieve attribute values, labels, etc... using its code, but one field I don't know is value_index.
I guess this may be the option position in an option list, but not sure.
Also if someone knows a good/better way to create a configurable product in Magento, please tell me.
Any help is welcome thank you.
It seems you're asking where to retrieve the value_index value where you already have the label. Here's what I had: I didn't test this on 1.5x.
function get_attribute_id($option, $type) {
$attributeId = Mage::getResourceModel('eav/entity_attribute')->getIdByCode('catalog_product', $type);
$attribute = Mage::getModel('catalog/resource_eav_attribute')->load($attributeId);
$attributeOptions = $attribute->getSource()->getAllOptions();
foreach ($attributeOptions as $opts_arr) {
if (strtoupper($opts_arr['label']) == strtoupper($option)) {
return $opts_arr['value'];
}
}
return FALSE;
}
$value_index = get_attribute_id('vhs', 'media_format');
No one else seemed to mention the easiest way to figure out what the value_index of vhs is: In the backend, under
Catalog > Manage > media_format > Manage Label/Options
Inspect the source of the individual form inputs. Where you have 'vhs' you should have an input named option[value][6]
As far as I understand your question, there are two options: a) create simple products by script, put the generated id's in an array and create the configurables using the ids or b) read the id's from the admin and put them in your script. Since programming is about automation I'd definately go for option a.
I'm trying to create a node (B type) & assign it to a A type node's CCK nodereference field using node_save() method.
$node_type_A = node_load($some_nid);
$node_type_A->field_type_B_node_ref[]['nid'] = $node_type_B_nid;
$node_type_A = node_submit($node_type_A);
node_save($node_type_A);
As the result, a new B type node will be created, but no reference will be assigned to the A type node. any help would be appreciated.
GApple is right, the format is correct, but there are couple of things that you might want to care about.
Delta Value
First you need to know the delta value of the latest node reference attached to $node_type_A, the delta is actually a partial index, when combined with vid field of the $node_type_A, they become the index for node reference table in the database. In other words, its a count for $node_type_B which are referenced in $node_type_A, ok?
GApple is right again, you have to exactly say where to add the new reference. When you got that delta value you can exactly say where to append (delta+1) the new reference. Here it is:
function get_current_delta($node_vid){
return db_result(db_query("SELECT delta FROM {content_field_type_A_node_ref}
WHERE vid = '%d'
ORDER BY delta DESC
LIMIT 1", $node_vid));
}
Adding the new reference
We got delta! so we can attach the new $node_type_B node to our $node_type_A node:
// Loading type_A node.
$node_type_A = node_load($some_nid);
// Getting current delta value.
$current_delta = get_current_delta($node_type_A->vid);
// "Appending" a node reference based on delta.
$node_type_A->field_type_B_node_ref += array($current_delta + 1 => array('nid' => $node_type_B_nid));
Resaving the updated node
Optionally call node_submit() to populate some essential fields in the node object and save it by utilizing node_save(). After all, you need to call content_insert() to make the node completely saved asidelong with its CCK fields:
// Resaving the updated node.
$node_type_A = node_submit($node_type_A);
node_save($node_type_A);
content_insert($node_type_A);
Flushing the content cache
Probably the most important part, this was killin' me for couple of days. CCK has a cache table in the database called cache_content (take a look at its structure), after resaving the updated node, you will notice that nothing has changed in the $node_type_A theme output even though that the tables are updated. We have to remove a record from that content cache table, this will force Drupal to show the latest snapshot of the data. You can define the following as a function:
db_query("DELETE FROM {cache_content} WHERE cid = '%s'", 'content:' . $node_type_A->nid . ':' . $node_type_A->vid);
Hope it helps ;)
I just checked one of my own modules that does something similar for the object format, and $node_type_A->field_type_B_node_ref[]['nid'] should be correct.
One thing to check for is that when you load the node, CCK may pre-populate the node reference array with an empty value. If you have configured the field to only allow one value, by using the array append operator (field_type_B_node_ref[]) it will create a second entry that will be ignored (field_type_B_node_ref[1]), instead of overwriting the existing value (field_type_B_node_ref[0]). Try explicitly specifying the array key if possible.
Great post, but one correction: don't flush cache entries by manually querying the DB. In the event someone is using memcache or any other external cache it's going to fail.
cache_clear_all() is your friend for clearing.
Suggested code, direct from the CCK module:
cache_clear_all('content:'. $node_type_A->nid .':'. $node_type_A->vid, content_cache_tablename());
I show CCK storing node references as $node->field_node_reference[0]['items'][0]['nid'], not $node->field_node_reference[0]['nid']. Have you tried mimicking that?
"Flushing the content cache" This works for me, especially if you get a data from node_load()
I'm working on the application at http://demos.zatechcorp.com/codeigniter/
In its current incarnation running on my machine, I loaded the ZendFramework inside Codeigniter, and generated an index, like this:
// ... Some code that loads all the markets
foreach ($markets as $market)
{
$doc = new Zend_Search_Lucene_Document();
// Id for retrieval
$doc->addField(Zend_Search_Lucene_Field::UnIndexed('id', $market->id));
// Store document URL to identify it in search result.
$doc->addField(Zend_Search_Lucene_Field::Text('url', $market->permalink));
// Index document content
$doc->addField(Zend_Search_Lucene_Field::UnStored('contents', $market->description));
// Title
$doc->addField(Zend_Search_Lucene_Field::Text('title', $market->title));
// Phone
$doc->addField(Zend_Search_Lucene_Field::Keyword('phone', $market->phone));
// Fax
$doc->addField(Zend_Search_Lucene_Field::Keyword('fax', $market->fax));
// Street
$doc->addField(Zend_Search_Lucene_Field::Keyword('street', $market->street));
// City
$doc->addField(Zend_Search_Lucene_Field::Keyword('city', $market->city));
// State
$doc->addField(Zend_Search_Lucene_Field::Keyword('state', $market->state));
// Zip
$doc->addField(Zend_Search_Lucene_Field::Keyword('zip', $market->zip));
// Type
$doc->addField(Zend_Search_Lucene_Field::UnIndexed('type', 'market'));
// Store Document
$index->addDocument($doc);
}
In my search, I do this:
$hits = $index->find($q);
This works with simple words, but when I want to do a search like "Sheba Foods" (quotes included), it returns one result, but the wrong one, which doesn't even have the word "Sheba".
I moved away from MySQL full-text search because of its obvious problems, and can't make any headway with this.
I've been looking at the Zend_Search_Lucene_Search_QueryParser::parse() method. Does the answer lie in this method?
I figured it out. With Lucene, you can add a field with the name 'id', but retrieving id from a hit gives you something different -- I'll guess this is the id of the search term within the entire search results.
What I had to do in this case was use a different field name like this:
// Id for retrieval
$doc->addField(Zend_Search_Lucene_Field::UnIndexed('item_id', $market->id));
I have used MySQL full-text search in the past, but it's really CPU intensive.
You could always rely on a SELECT * FROM table WHERE column = '%query%'