Producing proper routes in a nested tree in codeigniter - codeigniter

I am pretty new to CodeIgniter and PHP in general and have two questions that are somewhat related.
I have a nested category tree with unlimited depth that produces links like myapp.com/language and myapp.com/spanish but I would like to have something like myapp.com/language/spanish.
For reference my model returns an array of arrays like:
[Languages] => Array ( [category_id] => 4 [sub] => Array ( [Japanese] => Array ( [category_id] => 5 ) [Spanish] => Array ( [category_id] => 6 )...
My helper function to create the menu:
function buildMenu($menu_array, $is_sub=FALSE){
/*
* If the supplied array is part of a sub-menu, add the
* sub-menu class instead of the menu ID for CSS styling
*/
$attr = (!$is_sub) ? ' id="menu"' : ' class="submenu"';
$menu = "<ul$attr>\n"; // Open the menu container
/*
* Loop through the array to extract element values
*/
foreach($menu_array as $id => $properties) {
/*
* Because each page element is another array, we
* need to loop again. This time, we save individual
* array elements as variables, using the array key
* as the variable name.
*/
foreach($properties as $key => $val) {
/*
* If the array element contains another array,
* call the buildMenu() function recursively to
* build the sub-menu and store it in $sub
*/
if(is_array($val))
{
$sub = buildMenu($val, TRUE);
}
/*
* Otherwise, set $sub to NULL and store the
* element's value in a variable
*/
else
{
$sub = NULL;
$$key = $val;
}
}
/*
* If no array element had the key 'url', set the
* $url variable equal to the containing element's ID
*/
if(!isset($url)) {
$url = $id;
}
/*
* Use the created variables to output HTML
*/
$menu .= "<li><a href='$url'>$url</a>$sub</li>\n";
/*
* Destroy the variables to ensure they're reset
* on each iteration
*/
unset($url, $display, $sub);
}
return $menu . "</ul>\n";
This leads me to my next problem. How do I get these links to call a dynamic function that can return a list of all posts in that category. I am thinking that if I can get the routes working how I want them above that it will be as easy as having a function like get_cat_posts($cat_id). Am I correct in this assumption? Will having more than one sub-level be a problem?
Sorry for the long post. Thanks for any help.

Well I have given up on trying to make this work. It seems untenable to try using this current function to produces the results that I desire so I have moved on to just using an adjacency list and caching the results. Meh.

Related

Put specific item on top without sorting others in laravel collection

I have an ordered laravel collection and i need too put element with id = 20 on top, without sorting other elements. Is it possible to do with sortBy?
You can try to use filter method
// Say $originalCollection is the response from the large request, with data from the database
$modifiedCollection = $originalCollection->filter(fn($item) => $item->id === 20)
->concat($originalCollection->filter(fn($item) => $item->id !== 20));
Or to be more intuitive you can use filter and reject methods
$modifiedCollection = $originalCollection->filter(fn($item) => $item->id === 20)
->concat($originalCollection->reject(fn($item) => $item->id === 20));
The $modifiedCollection will have record with id = 20 at the top and rest of the records will remain in the same order as in $originalCollection
if you want to put a specific item at the top of the array, simply add it separately.
$type = ['20' => 'Select Type'] + $your_sorted_array ;
Example:
$country = ['1' => 'Andorra'] + Countries::orderby('nicename')->pluck('name', 'id')->toArray();
Edit 1:Given new information, the on way you could "manually" do this is by using a combination of unset and unshift AFTER the array is built from the collection.
$key_value = $country[20];
unset($country[20]);
array_unshift($country, $key_value );
if your collection is not very large you can use combination of keyBy, pull and prepend methods
$originalCollection = Model::hereYourBigQuery()->get()->keyBy('id');
/*
now collection will look like this
{
'id1' => objectWithId1,
'id2' => objectWithId2,
...
20 => objectWithId20,
...
}
*/
// pull takes off element by its key
$toMakeFirst = $originalCollection->pull(20);
// prepend adding item into begining of the collection
// note that prepend will reindex collection so its keys will be set by default
$originalCollection->prepend($toMakeFirst);
upd:
if you want to stick with sort there is a way
$collection = Model::yourBigQuery()->get();
$sorted = $collection->sort(function($a, $b){return $a->id == 20 ? -1 : 1;})->values();
as said in docs method sort can take closure as argument and utilizes php uasort under the hood

CodeIgniter escaping table

I know CodeIgniter automatically escapes values being sent to say an insert or update query e.g. $bar, but will it also escape $table if table is being received from say a post or get? I couldn't find any documentation on that.
$this->db->insert($table, array('foo' => $bar));
if you look at CodeIgniter's 2.x system/database/drivers/DB_driver.php near line 902
or
at CodeIgniters 3.x system/database/DB_driver near line 1365
you'll find a function called insert_string() which looks like this:
/**
* Generate an insert string
*
* #access public
* #param string the table upon which the query will be performed
* #param array an associative array data of key/values
* #return string
*/
function insert_string($table, $data)
{
$fields = array();
$values = array();
foreach ($data as $key => $val)
{
$fields[] = $this->_escape_identifiers($key);
$values[] = $this->escape($val);
}
return $this->_insert($this->_protect_identifiers($table, TRUE, NULL, FALSE), $fields, $values);
}
then follow-up function _protect_identifiers() near line 1246 (CI 2.x) or near line 1729 (CI 3.0) which says:
* Since the column name can include up to four segments (host, DB, table, column)
* or also have an alias prefix, we need to do a bit of work to figure this out and
* insert the table prefix (if it exists) in the proper position, and escape only
* the correct identifiers.
so the answer is YES.
in case of doubt you can always use this: echo ($this->db->last_query());die(); which prints out your last query performed what could look like this:
INSERT INTO `googlemaps_marker` (`descr`, `Lat`, `Lng`, `pretty_url`, `ID`, `zone_ID`, `kind`, `author_id`, `author`, `date_updated`) VALUES ('sasasasdas', '41.27780646738183', '-7.437744140625', 'sasasasdas', 4, 4, 1, '1', 'Admini Istrator', '2017-07-15 18:20:40')

Array match in while-loop

I am developing a search tool for my project,
My desired output is to get the common value from the different tables. eg) SKR0BP100
How to get this value ??
As i am running the program in for-loop and fetching the values from while-loop, now how to use array_intersect() function? Because for array intersect function, minimum 2 arrays are needed, but i get only one array at a time, as it runs on for-loop. So what should i do ?? Please Help me!
$result = array_intersect($arr1, $arr2);
But i have only one $array (ie, $sid[$i] at a time, as it runs in for-loop.
My program
for($i=0;$i<$cc;$i++)
{
$m1="select * from $u$sc where $b[$i]='$a[$i]' ";
$m2=mysql_query($m1);
echo"$m1<br><br>";
while($we=mysql_fetch_array($m2))
{
$sid[$i]=$we['SI'];
echo"$sid[$i]<br><br>";
}
}
Desired Output = SKR0BP100
// How to get this??
Present output
select * from Studentsc where Zone='East'
SKR0BP100
SKR0BP12
select * from Studentsc where Area='Rural'
SKR0BP129
SKR0BP13
SKR0BP100
select * from Studentsc where Class='12'
SKR0BP100
SKR0BP101
So if you want to create query then try this
$where = array();
for($i=0;$i<$cc;$i++)
{
$where[] = $b[$i]."='".$a[$i]."'";
}
$m1="select * from $u$sc where ".implode(" and ",$where); //If you are sure that atleast one value vomes

how to use 'like' instead of '=' in magento collection filter for custom module

i have managed to do this with addFieldToFilter default functionality like this:
$collection->addFieldToFilter(
array('first_name','last_name'),
array($post['firstName'],$post['lastName'])
);
this is working when i print sql (this is just part from the whole statement being printed):
((first_name = 'r') OR (last_name = 't'))
now i am trying to understand how to use 'like' instead of =.
need some help in understanding that.
your time and answers are highly appericiated thank you.
It's weird, but after some researching into your question the solution is quite simple - it's given in the comments in the Magento code:
In the comment for the method addAttributeToFilter() in Mage/Eav/Model/Entity/Collection/Abstract.php (which finally gets called) you can read:
/**
* Add attribute filter to collection
*
* If $attribute is an array will add OR condition with following format:
* array(
* array('attribute'=>'firstname', 'like'=>'test%'),
* array('attribute'=>'lastname', 'like'=>'test%'),
* )
*/
Wasn't quite clear to me what this was supposed to mean, but it's as simple: If you want to add an OR condition between the attributes in your statement, then you have to give your parameter for the addAttributeToFilter() method in this way, so in your case:
$collection->addFieldToFilter(
array(
array('attribute'=>'firstname', 'like'=>$post['firstName']),
array('attribute'=>'lastname', 'like'=>$post['lastName'])
));
You can follow this if you look inside the addAttributeToFilter() method:
if (is_array($attribute)) {
$sqlArr = array();
foreach ($attribute as $condition) {
$sqlArr[] = $this->_getAttributeConditionSql($condition['attribute'], $condition, $joinType);
}
$conditionSql = '('.implode(') OR (', $sqlArr).')';
For you googlers, the rigth way to to it is:
$collection->addFieldToFilter(
array('first_name','last_name'),
array(
array('like' => '%'.$post['firstName'].'%'),
array('like' => '%.'$post['lastName'].'%')
)
);
You should pass an array of fields and an array of conditions.
Generated SQL:
... WHERE ((first_name LIKE '%xxxx%') OR (last_name LIKE '%yyy%')) ...
addFieldToFilter( 'sku', array( "like"=>'abc123' ) )
Here you can read much more about Magento collections: http://alanstorm.com/magento_collections
For example, see section named "AND or OR, or is that OR and AND?" in this article.

TYPO3: Calculate Cache identifier hash value?

In TYPO3 I want to remove a single page from the cache table with some GET values. I haven't found an extension, that will handle that or a TYPO3 method.
Is there a function, that I can hand over a URL or similar, that produces the cache hash identifier or removes the specific data from the caching tables?
If not, does anybody know, what the algorithm is, that calculates the hash identifier or in which file I might find it?
So any help will be appreciated.
My TYPO3 version: 4.5.x
You can create a function which clear the cache of a specified page, following code is needed:
TYPO3 6.0
public function clearCache($cacheCmd) {
/** #var $tce \TYPO3\CMS\Core\DataHandling\DataHandler */
$tce = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance("TYPO3\\CMS\\Core\\DataHandling\\DataHandler");
$tce->stripslashes_values = 0;
$tce->start(array(), array());
switch($cacheCmd) {
case 'pages':
case 'all':
$tce->admin = 1;
}
$tce->clear_cacheCmd($cacheCmd);
unset($tce);
}
TYPO3 4.x
public function clearCache($cacheCmd) {
/** #var $tce t3lib_TCEmain */
$tce = t3lib_div::makeInstance("t3lib_TCEmain");
$tce->stripslashes_values = 0;
$tce->start(array(), array());
switch($cacheCmd) {
case 'pages':
case 'all':
$tce->admin = 1;
}
$tce->clear_cacheCmd($cacheCmd);
unset($tce);
}
And $cacheCmd can have following values:
/typo3/sysext/core/Classes/DataHandling/DataHandler.php:clear_cacheCmd (> 6.0) or /t3lib/class.t3lib_tcemain.php (4.x)
/**
* Clears the cache based on the command $cacheCmd.
*
* $cacheCmd='pages': Clears cache for all pages. Requires admin-flag to
* be set for BE_USER.
*
* $cacheCmd='all': Clears all cache_tables. This is necessary if
* templates are updated. Requires admin-flag to be set for BE_USER.
*
* $cacheCmd=[integer]: Clears cache for the page pointed to by $cacheCmd
* (an integer).
*
* $cacheCmd='cacheTag:[string]': Flush page and pagesection cache by given tag
*
* $cacheCmd='cacheId:[string]': Removes cache identifier from page and page section cache
*
* Can call a list of post processing functions as defined in
* $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearCachePostProc']
* (numeric array with values being the function references, called by
* \TYPO3\CMS\Core\Utility\GeneralUtility::callUserFunction()).
*
* Note: The following cache_* are intentionally not cleared by
* $cacheCmd='all':
*
* - cache_md5params: RDCT redirects.
* - cache_imagesizes: Clearing this table would cause a lot of unneeded
* Imagemagick calls because the size informations have
* to be fetched again after clearing.
*
* #param string $cacheCmd The cache command, see above description
* #return void
*/
Call this with a userFunc if a given parameter is set in typoscript or create a simple extension by your own.
It's like this:
You need a proper TSFE object $GLOBALS['TSFE']
then you need the encryption key from the localconf $TYPO3_CONF_VARS['SYS']['encryptionKey']
and the URL parameters e.g. `tx_ttnews[tt_news]
then these steps
create an (sorted) array with the encryption key and the url parameters
Hand over this array to the property cHash_array of the TSFE object
Get the cHash value from the TSFE's getHash method
$arr = array(
'encryptionKey' => $TYPO3_CONF_VARS['SYS']['encryptionKey'],
'tx_ttnews[tt_news]' => $newsid,
// ...
)
ksort($array);
$GLOBALS['TSFE']->cHash_array = $array;
$chash = $GLOBALS['TSFE']->getHash();

Resources