I am open this based from my question in my own comment from Static page dropdown within static page in OctoberCMS.
I have problem when adding $pageList->getPageTree(true). The child pages did not display. My current code is repeating foreach from $pageObject->subpages which is not a good practice.
Below here is my code example:
Plugin.php
<?php namespace MyPlugin\CustomPlugin
use System\Classes\PluginBase;
public function boot() {
\RainLab\Pages\Classes\Page::extend(function($model) {
$model->addDynamicMethod('getPageOptions', function() {
$theme = \Cms\Classes\Theme::getEditTheme();
$pageList = new \RainLab\Pages\Classes\PageList($theme);
$pages = [];
foreach ($pageList->getPageTree(true) as $name => $pageObject) {
$pages[$pageObject->page->url] = $pageObject->page->title;
if ($pageObject->subpages) {
foreach ($pageObject->subpages as $name => $pageObject) {
$pages[$pageObject->page->url] = ' ' . $pageObject->page->title;
if ($pageObject->subpages) {
foreach ($pageObject->subpages as $name => $pageObject) {
$pages[$pageObject->page->url] = ' ' . $pageObject->page->title;
}
}
}
}
}
return $pages;
});
});
}
Appreciate if anyone could help.
may be this will help you.
function onStart() {
$theme = \Cms\Classes\Theme::getEditTheme();
$pageList = new \RainLab\Pages\Classes\PageList($theme);
$treePageList = $pageList->getPageTree(true);
$pages = [];
$this->getRecursivePage($pages, $treePageList);
dd($pages);
}
function getRecursivePage(&$pages, $subpages, $level = 0) {
$level++;
foreach($subpages as $pageArr) {
$pages[$pageArr->page->url] =
str_repeat('-',$level) . ' ' . $pageArr->page->title;
if(count($pageArr->subpages) > 0) {
$this->getRecursivePage($pages, $pageArr->subpages, $level);
}
}
}
Output
array:9 [▼
"/content" => "- Content"
"/content/pages" => "-- Static Pages"
"/content/content" => "-- Content"
"/content/models" => "-- Models"
"/content/urls" => "-- URLs"
"/content/urls/tesets" => "--- tesets"
"/test-sp" => "- test-sp"
"/test-sp/oks" => "-- oks"
"/test" => "- test"
]
here you can just replace - to or just remove that part [ I added because you had that in code so, may be useful to you. ]
For your code
public function boot() {
\RainLab\Pages\Classes\Page::extend(function($model) {
$model->addDynamicMethod('getPageOptions', function() {
$theme = \Cms\Classes\Theme::getEditTheme();
$pageList = new \RainLab\Pages\Classes\PageList($theme);
$treePageList = $pageList->getPageTree(true);
$pages = [];
$this->getRecursivePage($pages, $treePageList);
return $pages;
});
});
}
public function getRecursivePage(&$pages, $subpages, $level = 0) {
$level++;
foreach($subpages as $pageArr) {
$pages[$pageArr->page->url] =
str_repeat('-',$level) . ' ' . $pageArr->page->title;
if(count($pageArr->subpages) > 0) {
$this->getRecursivePage($pages, $pageArr->subpages, $level);
}
}
}
If any doubt please comment.
Related
I have navigation which looks like this in the system:
At the moment, I am able to print an array of objects containing the menu items recursively, and the code looks like this:
public function get() {
$current_path = \Drupal::service('path.current')->getPath();
$path_items = explode ('/',$current_path);
$menu_array = [];
$menu = $path_items[4];
if(!empty ($menu) ){
$sub_nav = \Drupal::menuTree()->load($menu, new \Drupal\Core\Menu\MenuTreeParameters());
foreach($sub_nav as $nav){
array_push($menu_array, $nav);
}
$manipulators = array(
array('callable' => 'menu.default_tree_manipulators:generateIndexAndSort'),
);
$sub_nav = \Drupal::menuTree()->transform($sub_nav, $manipulators);
$this->generateSubMenuTree($menu_array, $sub_nav);
$response = array_values($menu_array);
}
return (new ResourceResponse($response))->addCacheableDependency(array('#cache' => array('max-age' => 0)));
}
private function generateSubMenuTree(&$output, &$input, $parent = FALSE) {
$input = array_values($input);
$items = 0;
foreach($input as $key => $item) {
//If menu element disabled skip this branch
if ($item->link->isEnabled()) {
if ($item->link instanceof \Drupal\menu_link_content\Plugin\Menu\MenuLinkContent) {
$uuid = $item->link->getDerivativeId();
$entity = \Drupal::service('entity.repository')
->loadEntityByUuid('menu_link_content', $uuid);
}
$link_data['name'] = $item->link->getTitle();
if(!empty($item->link->pluginDefinition['url'])){
$link_data['href'] = $item->link->pluginDefinition['url'];
}
//If not root element, add as child
if ($parent === FALSE) {
$output[$key] = $link_data;
} else {
$output['children'][$key] = $link_data;
}
if ($item->hasChildren) {
if ($item->depth == 1) {
$this->generateSubMenuTree($output[$key], $item->subtree, $key);
} else {
$this->generateSubMenuTree($output['children'][$key], $item->subtree, $key);
}
}
$items ++;
}
}
}
The code above results into the following:
However my specification now changed in the sense that for Nav Data and Departments, I should only start including from the child elements onwards.
The result should be something like this:
{
[
{
name : "Shop"
children : [
{
name : "Promotions"
tabletColumn : 0
desktopColumn : 0
children : [...] 3 items
},
{ ... }
]
},
{...}
],
[
{
name : "Personal"
children : [...] 0 items
selected : true
}
],
{...}
{...}
}
Have been struggling with this logic for 24 hours already.
I'm using Parsedown to parse HTML from the database to my site. With Parsedown, you can't really add target="_blank" to the links.
So what I'm trying to do is to add target="_blank" to external links. I've found this function in Parsedown.php:
protected function inlineLink($Excerpt)
{
$Element = array(
'name' => 'a',
'handler' => 'line',
'text' => null,
'attributes' => array(
'href' => null,
'title' => null,
),
);
$extent = 0;
$remainder = $Excerpt['text'];
if (preg_match('/\[((?:[^][]++|(?R))*+)\]/', $remainder, $matches))
{
$Element['text'] = $matches[1];
$extent += strlen($matches[0]);
$remainder = substr($remainder, $extent);
}
else
{
return;
}
if (preg_match('/^[(]\s*+((?:[^ ()]++|[(][^ )]+[)])++)(?:[ ]+("[^"]*"|\'[^\']*\'))?\s*[)]/', $remainder, $matches))
{
$Element['attributes']['href'] = $matches[1];
if (isset($matches[2]))
{
$Element['attributes']['title'] = substr($matches[2], 1, - 1);
}
$extent += strlen($matches[0]);
}
else
{
if (preg_match('/^\s*\[(.*?)\]/', $remainder, $matches))
{
$definition = strlen($matches[1]) ? $matches[1] : $Element['text'];
$definition = strtolower($definition);
$extent += strlen($matches[0]);
}
else
{
$definition = strtolower($Element['text']);
}
if ( ! isset($this->DefinitionData['Reference'][$definition]))
{
return;
}
$Definition = $this->DefinitionData['Reference'][$definition];
$Element['attributes']['href'] = $Definition['url'];
$Element['attributes']['title'] = $Definition['title'];
}
$Element['attributes']['href'] = str_replace(array('&', '<'), array('&', '<'), $Element['attributes']['href']);
return array(
'extent' => $extent,
'element' => $Element,
);
}
Now, what I've tried is this (added a comment of what I changed):
protected function inlineLink($Excerpt)
{
$Element = array(
'name' => 'a',
'handler' => 'line',
'text' => null,
'attributes' => array(
'href' => null,
'target' => null, // added this
'title' => null,
),
);
$extent = 0;
$remainder = $Excerpt['text'];
if (preg_match('/\[((?:[^][]++|(?R))*+)\]/', $remainder, $matches))
{
$Element['text'] = $matches[1];
$extent += strlen($matches[0]);
$remainder = substr($remainder, $extent);
}
else
{
return;
}
if (preg_match('/^[(]\s*+((?:[^ ()]++|[(][^ )]+[)])++)(?:[ ]+("[^"]*"|\'[^\']*\'))?\s*[)]/', $remainder, $matches))
{
$Element['attributes']['href'] = $matches[1];
if (isset($matches[2]))
{
$Element['attributes']['title'] = substr($matches[2], 1, - 1);
}
$extent += strlen($matches[0]);
}
else
{
if (preg_match('/^\s*\[(.*?)\]/', $remainder, $matches))
{
$definition = strlen($matches[1]) ? $matches[1] : $Element['text'];
$definition = strtolower($definition);
$extent += strlen($matches[0]);
}
else
{
$definition = strtolower($Element['text']);
}
if ( ! isset($this->DefinitionData['Reference'][$definition]))
{
return;
}
$Definition = $this->DefinitionData['Reference'][$definition];
$Element['attributes']['href'] = $Definition['url'];
if (strpos($Definition['url'], 'example.com') !== false) { // added this aswell, checking if its our own URL
$Element['attributes']['target'] = '_blank';
}
$Element['attributes']['title'] = $Definition['title'];
}
$Element['attributes']['href'] = str_replace(array('&', '<'), array('&', '<'), $Element['attributes']['href']);
return array(
'extent' => $extent,
'element' => $Element,
);
}
Any suggestions to accomplish this?
Ran into this issue today. I wanted to have all links from a different host open up in a new target automatically. Unfortunately, the accepted answer recommends editing the Parsedown class file, which is a bad idea imo.
I created a new PHP class which extends Parsedown, and created an override for the element method. Here is the whole class:
class ParsedownExtended extends Parsedown
{
protected function element(array $Element)
{
if ($this->safeMode) {
$Element = $this->sanitiseElement($Element);
}
$markup = '<' . $Element['name'];
if (isset($Element['name']) && $Element['name'] == 'a') {
$server_host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : null;
$href_host = isset($Element['attributes']['href']) ? parse_url($Element['attributes']['href'], PHP_URL_HOST) : null;
if ($server_host != $href_host) {
$Element['attributes']['target'] = '_blank';
}
}
if (isset($Element['attributes'])) {
foreach ($Element['attributes'] as $name => $value) {
if ($value === null) {
continue;
}
$markup .= ' ' . $name . '="' . self::escape($value) . '"';
}
}
if (isset($Element['text'])) {
$markup .= '>';
if (!isset($Element['nonNestables'])) {
$Element['nonNestables'] = array();
}
if (isset($Element['handler'])) {
$markup .= $this->{$Element['handler']}($Element['text'], $Element['nonNestables']);
}
else {
$markup .= self::escape($Element['text'], true);
}
$markup .= '</' . $Element['name'] . '>';
}
else {
$markup .= ' />';
}
return $markup;
}
}
Here is where the magic happens:
if (isset($Element['name']) && $Element['name'] == 'a') {
$server_host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : null;
$href_host = isset($Element['attributes']['href']) ? parse_url($Element['attributes']['href'], PHP_URL_HOST) : null;
if ($server_host != $href_host) {
$Element['attributes']['target'] = '_blank';
}
}
Now I simply use ParsedownExtended instead of Parsedown when parsing content, e.g.:
$parsedown = new ParsedownExtended();
return $parsedown->text($this->body);
Hope this helps someone.
Such issue already exists on GitHub. Please see this comment.
My extension can automatically set rel="nofollow" and target="_blank"
attributes to a link when it is detected as an external link. You can
also set those attributes manually through the attribute block:
[text](http://example.com) {rel="nofollow" target="_blank"}
Automatic rel="nofollow" Attribute on External Links
// custom external link attributes
$parser->links_external_attr = array(
'rel' => 'nofollow',
'target' => '_blank'
);
If you want to make changes in Parsedown class without using the parsedown-extra-plugin extension, you can do as follows:
1) In \Parsedown::element method after the first line $markup = '<'.$Element['name']; add this line $Element = $this->additionalProcessElement($Element);
2) Add new method to Parsedown class:
protected function additionalProcessElement($Element) { }
3) Extend Parsedown class and save it as MyParsedown.php file:
<?php
namespace myapps;
require_once __DIR__.'/Parsedown.php';
/**
* Class MyParsedown
* #package app
*/
class MyParsedown extends \Parsedown
{
/**
* #param array $Element
* #return array
*/
protected function additionalProcessElement($Element)
{
if ($Element['name'] == 'a' && $this->isExternalUrl($Element['attributes']['href'])) {
$Element['attributes']['target'] = '_blank';
}
return $Element;
}
/**
* Modification of the funciton from answer to the question "How To Check Whether A URL Is External URL or Internal URL With PHP?"
* #param string $url
* #param null $internalHostName
* #see https://stackoverflow.com/a/22964930/7663972
* #return bool
*/
protected function isExternalUrl($url, $internalHostName = null) {
$components = parse_url($url);
$internalHostName = ($internalHostName == null) ? $_SERVER['HTTP_HOST'] : $internalHostName;
// we will treat url like '/relative.php' as relative
if (empty($components['host'])) {
return false;
}
// url host looks exactly like the local host
if (strcasecmp($components['host'], $internalHostName) === 0) {
return false;
}
$isNotSubdomain = strrpos(strtolower($components['host']), '.'.$internalHostName) !== strlen($components['host']) - strlen('.'.$internalHostName);
return $isNotSubdomain;
}
}
4) Create test.php file and run it:
require_once __DIR__.'/MyParsedown.php';
$parsedown = new \myapps\MyParsedown();
$text = 'External link to [example.com](http://example.com/abc)';
echo $parsedown->text($text);
This HTML code will be displayed on the browser page (if your host is not example.com, of course):
<p>External link to example.com</p>
Just like kjdion84 I'd also extend the Parsedown class. I suggest to not copy and change the element method but overwrite inlineLink; it's less work and more future proof if the base code changes.
Heads up: the urlIsExternal method is by no means complete (host check is missing).
class ParsedownExtended extends Parsedown
{
protected function inlineLink($Excerpt)
{
$link = parent::inlineLink($Excerpt);
if ($this->urlIsExternal($link['element']['attributes']['href'])) {
$link['element']['attributes'] += [
'target' => '_blank',
'rel' => 'nofollow',
];
}
return $link;
}
protected function urlIsExternal($url)
{
$scheme = parse_url($url, PHP_URL_SCHEME);
$host = parse_url($url, PHP_URL_HOST);
if (!$scheme || !$host) {
return false;
}
if (strpos(strtolower($scheme), 'http') !== 0) {
return false;
}
// #TODO check the host
return true;
}
}
This will work.
<?php
declare(strict_types=1);
namespace YourNamespace;
class ParsedownExt extends \Parsedown
{
// Add target to links
protected function element(array $Element)
{
if (strcasecmp($Element['name'], 'a')===0)
$Element['attributes']['target'] = '_blank';
return parent::element($Element);
}
}
I do have a search form on a page which search records from a table in my database. I want to show how many results each query gives us. All this is written in codeigniter.
All my code on that page:
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
class Welcome extends CI_Controller {
public function index() {
$data['title'] = "Welcome | randomsite";
$data['html'] = "";
if($this->input->post()) {
$uq = $this->security->xss_clean($this->input->post('query'));
if(trim($uq) != "") {
$searchBy = $this->security->xss_clean($this->input->post('searchBy'));
$searchByJSON = json_encode(array(1 => "Email", 2 => "Username", 3 => "IP", 4 => "FullName", 5 => "Phone"), JSON_FORCE_OBJECT);
if(isset(json_decode($searchByJSON)->$searchBy)) {
$start = microtime(true);
$this->db->from('Databases');
$rs = $this->db->get()->result();
$end = microtime(true);
$data['html'] .= "Search completed in: " . ($end - $start) . " seconds.<p></p>";
foreach($rs as $row) {
$this->db->distinct();
$this->db->select('Username, Password, Email, FullName, IP, Phone, salt');
$this->db->from('Accounts');
$this->db->where(json_decode($searchByJSON)->$searchBy, $uq);
$this->db->where('DatabaseID', $row->ID);
$query = $this->db->get();
if($query->num_rows() > 0) {
if($searchBy == 5 && $query->row()->Phone == 0) {
break;
}
$resultsHTML = "";
foreach($query->result() as $qr) {
$resultsHTML .= "<div class='card-block-results' style='table-layout:fixed; word-wrap:break-word;'><table class='table table-hover' style='font-size:13px;'>";
foreach($qr as $key => $value) {
if(!empty($value)) {
if($key == "FullName") {
$key = "Full Name";
}
$resultsHTML .= "<tr><td>" . $key . ": " . $value . "</td></tr>";
}
}
$resultsHTML .= "</table></div>";
}
$data['html'] .= $row->Website . " has: <b style='color:lime;'>" . $query->num_rows() . "</b> result(s) found. This data was hacked on approximately " . $row->Date . ". <button class='btn btn-success btn-sm' style='margin-bottom:5px;' id='button" . $row->ID . "'>view results</button><div id='results" . $row->ID . "' style='display:none;'><div class='card card-outline-primary' style='margin-bottom:10px;text-align:left;margin-top:5px;'><div class='card-header card-primary'>Results</div>" . $resultsHTML . "</div></div><script type='text/javascript'>$('#button" . $row->ID . "').click(function() { $(this).hide(); $('#results" . $row->ID . "').show(); });</script><br>";
}
}
if($data['html'] == "Search completed in: " . ($end - $start) . " seconds.<p></p>") {
$data['html'] .= "No results found!<p></p>Are you searching in the right fields? Searching for an email in the phone number field will not work.<br>Make sure first and last names are correct. Example: Mike Tyson";
}
$data['html'] .= "<br><br><br>";
$this->db->from('Lookups');
$query = $this->db->get();
$new_lookup = $query->row()->Number + 1;
$qdata = array(
"Number" => $new_lookup
);
$this->db->update('Lookups', $qdata);
}
} else {
$data['html'] = '<div class="alert alert-danger">×Please enter something in your query before searching!</div>';
}
}
$this->load->view('welcome', $data);
}
}
So how can I add that into every time someone is searching? Like 'Query had x results.'
Like this:
I searched on many different sites about this but I couldn't find anything for my specific question.
you have already used it in your code,
$query->num_rows()
will give you the number of rows u get from the query.
i think this is abusing a framework like CI - i give you some insights in to this framework - if you are willing to learn, study this piece of code because
you nearly don't use any of his built in functionality
in my opinion you've to restructure your code to such an extent that you don't even recognize your previous attempt ;)
i'll try to give you a hunch - but in order to understand - you've to work with this code
put in your models folder the following models
Database Model
class Database_model extends CI_Model
{
private $objCollection;
public function __construct()
{
$this->objCollection = new Database_Collection();
}
public function getCollection()
{
$this->benchmark->mark('code_start');
$this->db->from('Databases');
$this->objCollection->append($this->db->get()->result());
$this->benchmark->mark('code_end');
$this->objCollection->queryTime = $this->benchmark->elapsed_time('code_start', 'code_end');
return $this->objCollection;
}
}
class Database_Collection extends ArrayObject
{
public $queryTime = 0;
}
Accounts Model
class Accounts_model extends CI_Model
{
private $objCollection;
public function __construct()
{
$this->objCollection = new Accounts_Collection();
}
public function getCollection()
{
$this->benchmark->mark('code_start');
$this->db
->distinct()
->select('Username, Password, Email, FullName, IP, Phone, salt')
->from('Accounts');
$this->objCollection->append($this->db->get()->result());
$this->benchmark->mark('code_end');
$this->objCollection->queryTime = $this->benchmark->elapsed_time('code_start', 'code_end');
return $this->objCollection;
}
}
class Accounts_Collection extends ArrayObject
{
public $queryTime = 0;
}
Search Model
class Search_model extends CI_Model
{
private $strSearchQuery = "";
public function getSearchObject()
{
if ($this->isValidSearch())
{
$this->load->model("Database_Model");
$this->load->model("Accounts_Model");
$objSearch = new Search;
$objDBCollection = $this->Database_Model->getCollection();
foreach($objDBCollection AS $objItem)
{
$this->db
->where("DatabaseID", $objItem->ID)
->where($this->input->post("searchBy"), $this->strSearchQuery);
$objItem->collection = $this->Accounts_Model->getCollection();
}
$objSearch->addResultCollection($objDBCollection);
return $objSearch;
}
return false;
}
public function isValidSearch()
{
$strSearchQuery = $this->security->xss_clean($this->input->post('query'));
$this->strSearchQuery = trim($strSearchQuery);
if (empty($this->strSearchQuery)) return false;
$arrValidSearchCriteria = array("Email", "Username", "IP", "FullName", "Phone");
return (in_array($this->input->post("searchBy"),arrValidSearchCriteria));
}
}
class Search
{
public $queryTime = 0;
private $objCollection;
public function addResultCollection(Database_Collection $objCollection)
{
$this->objCollection = $objCollection;
}
public function getRenderedTime()
{
if ($this->queryTime == 0)
{
$this->queryTime += $this->objCollection->queryTime;
foreach($this->objCollection AS $objItem)
{
if (isset($objItem->collection)
{
$this->queryTime += $objItem->collection->queryTime;
}
}
}
return $this->queryTime;
}
public function getCountSearchResults()
{
if (!$this->countSearchResults)
{
$this->countSearchResults = 0;
foreach($this->objCollection AS $objItem)
{
if (isset($objItem->collection)
{
$this->countSearchResults += $objItem->collection->count();
}
}
}
return $this->countSearchResults;
}
}
your controller
class Welcome extends CI_Controller
{
public function index()
{
$this->load->model("Search_model");
$data['title'] = "Welcome | randomsite";
if ($this->Search_model->isValidSearch()
{
$objSearch = $this->Search_model->getSearchObject();
$arrViewData = array("objSearch" => $objSearch);
$this->load->view("list-search", $arrViewData);
}
}
}
pS: maybe there are some typos because i just wrote it down
I have a SilverStripe (3.4) Page with a form that would work if I didn't have a DataObject in it.
public function AntwortForm($ID) {
$Nummer = Vortest_Fragen::get()->byID($ID);
if ($Nummer) {
$Art=$Nummer->Art;
}
if ($Art == 'Normal') {
$fields = new FieldList(
TextAreaField::create('Antwort'),
HiddenField::create('ID', 'ID', $ID),
HiddenField::create('VortestID', 'VortestID', $this->request->param('ID')),
HiddenField::create('Aktion', 'Aktion', $this->request->param('Action'))
);
} else {
$Optionen = explode(';', $Nummer->Optionen);
$a = 'A';
for ( $i = 0 ; $i < count ($Optionen); $i++) {
$Op[$a] ='<div style="width:25px;display:inline;">' . $a . ')</div> ' . $Optionen[$i];
$a++;
}
$fields = new FieldList(
CheckboxSetField::create('Antwort', 'Antwort', $Op),
HiddenField::create('ID', 'ID', $ID),
HiddenField::create('VortestID', 'VortestID', $this->request->param('ID')),
HiddenField::create('Aktion', 'Aktion',$this->request->param('Action')),
HiddenField::create('Art', 'Art', $Nummer->Art)
);
}
$actions = new FieldList(
FormAction::create('AntwortEintragen', 'Eintragen')
);
$form = new Form($this, 'AntwortForm', $fields, $actions);
return $form;
}
function AntwortEintragen($data, $form) {
$Antwort = Vortest_Antwort::get()->filter(array('FrageID' => $data['ID'], 'SchreiberID' => Member::currentUserID()));
foreach($Antwort as $item) {
$item->delete();
}
foreach ($data['Antwort'] as $Antwort) {
$Ant .= $Antwort . ',';
}
$Antwort = new Vortest_Antwort();
if ($data['Antwort']) {
$form->saveInto($Antwort);
if ($data['Art'] == 'Mechanics') {
$Antwort->Antwort = $Ant;
}
$Antwort->SchreiberID = Member::currentUserID();
$Antwort->FrageID = $data['ID'];
$Antwort->write();
}
$VID = $data['VortestID'];
if ($data['Aktion'] == 'AlleFragen') {
$this->redirect('/vortest/AlleFragen/' . $VID . '#' . $data['FrageNr']);
} elseif ($data['Aktion'] == 'Einzelfrage') {
$this->redirect('/vortest/Einzelfrage/' . $VID);
} else {
$this->redirect('/vortest/Test/' . $VID.'#' . $data['FrageNr']);
}
}
It works when I change the $ID to a number in this line $Nummer = Vortest_Fragen::get()->byID($ID);
When I don't change it I get the following error:
[Recoverable Error] Object of class SS_HTTPRequest could not be converted to string
How do I fix this problem?
Althought it is not clearly documented, Silverstripe secretly passes a request argument to and form methods on a controller. Your $ID argument is actually not what you think it is, you will find it is actually an SS_HTTPRequest object that Silverstripe has passed (without you realising).
To fix this, change the first line:
public function AntwortForm($ID) {
To:
public function AntwortForm($request, $ID) {
And make sure you update anywhere that you call this method :-)
I have to extend an existing menu to a multilevel one. I am having a hard time wrapping my head around it so I'm hoping somebody can help me out.
First I've added another table in the database with the name parent_id.
Then I'd like to see if this column is filled out, so greater than > 0.
And then of course, check to see if id == parent_id.
If so, I'd like to display my submenu on hover of the parent item.
My current menu is a multi lang menu.
This is my current model:
var $default_order_by = array('position');
function findView($page)
{
$language = $this->config->item('language');
$p = new Page();
$p->where('url_' . $language, $page)->get();
return $p->view;
}
function findPageMenu($page)
{
$language = $this->config->item('language');
$p = new Page();
$p->where('url_' . $language, $page)->get();
return $p->menu;
}
function findAllByView()
{
$pages = new Page();
$result = array();
foreach ($pages->get() as $page)
$result[$page->view] = $page;
return $result;
}
function getMenu()
{
$pages = new Page();
if ($this->session->userdata('is_admin'))
return $pages->where('position >', 0)->get();
else
return $pages->where('position >', 0)->where('admin', 0)->get();
}
function getUrlByView($view)
{
$page = new Page();
$page->where('view', $view)->get();
$language = $this->config->item('language');
return $page->{'url_' . $language};
}
And this is my view:
<ul class="primary-nav">
<?php foreach($menu as $page): ?>
<li class="primary-nav__item">
<a class="primary-nav__link" <?php if ($page_menu == $page->view): ?>class="active" <?php endif; ?>href="<?php echo base_url() . $this->config->item('language_abbr') . '/' . $page->{'url_' . $this->config->item('language')}; ?>">
<?php echo mb_strtoupper($page->{'title_' . $this->config->item('language')}, 'UTF-8'); ?>
</a>
</li>
<?php endforeach; ?>
I was thinking of doing something like this:
function getSubMenu()
{
if ($this->session->userdata('is_admin'))
return $pages->where('position >', 0 && 'parent_id >', 0)->get();
else
// return $pages->where('position >', 0 && 'parent_id >', 0)->get();
echo '<h1> yay </h1>';
}
(ignore the yay, lol) But this obviously doesn't even begin to cut it.
Suggestion: You can add the "parent_id" in the same table. If there is a parent then fill it with parent id or with 0.
Answer: Get your data as a one dimentional array with all the rows with parent id. Then use the below function to create a multi dimensional array with parent and child.
function formatTree($tree, $parent = NULL) {
$treeArray = array();
foreach ($tree as $item) {
if ($item['menu_parent'] == 0) {
$treeArray[$item['menu_id']] = $item;
}
else {
$treeArray[$item['menu_parent']]['sub'][] = $item;
}
}
return $treeArray;
}
Now use the below function to make an intended ul-li list of parent-child menu
function buildMenu($menu_array, $is_sub = FALSE) {
$attr = (!$is_sub) ? ' class="sidebar-menu"' : ' class="treeview-menu"';
$menu = "<ul>"; // Open the menu container
foreach ($menu_array as $id => $properties) {
if (!isset($properties['sub'])) {
$is_sub = TRUE;
}
elseif (empty($properties['sub'])) {
$is_sub = TRUE;
}
foreach ($properties as $key => $val) {
if (is_array($val) && !empty($val)) {
$sub = $this -> buildMenu($val, TRUE);
}
else {
$sub = NULL;
$$key = $val;
}
}
if ($properties['menu_url']) {
$url = $properties['menu_url'];
}
$menu .= "<li>" . $menu_name . "</li>";
unset($url, $menu_name, $sub);
}
return $menu . "</ul>";
}
I am using this in my application. The array structure of menu data should be
array(
[0] => array(
'menu_name' => 'name',
'menu_url' => 'url',
'menu_id' => 'id',
'menu_parent' => 'parent id'
),
[1] => array(
'menu_name' => 'name',
'menu_url' => 'url',
'menu_id' => 'id',
'menu_parent' => 'parent id'
)
)