So i'm working with com_content component view,
and i need to load related items related to
the one that's beeing viewed.
Is it possible to do that?
This is what i have so far:
$com = JPATH_SITE.DS.'components'.DS.'com_content';
if (!class_exists('ContentController')) require($com.DS.'controller.php');
$config['base_path'] = $com;
$cont = new ContentController($config);
JRequest::setVar('view', 'categories');
$lang =& JFactory::getLanguage();
$lang->load('com_content', JPATH_SITE);
$cont->display();
I don't know if this is exactly how its supposed to be, but wait for any help if possible.
Thanks
Here is the solution, for anyone in my situation:
// Path to wanted component
$com = JPATH_SITE.DS.'components'.DS.'com_content';
// Include controller, if its not already include
if (!class_exists('ContentController')) require($com.DS.'controller.php');
// Inform controller of its base path
$config['base_path'] = $com;
// Init controller
$cont = new ContentController($config);
// Get wanted view
$view =& $cont->getView('category', 'html');
// Add path to wanted template
$view->addTemplatePath(JPATH_SITE.DS.'templates'.DS.'ja_wall'.DS.'html'.DS.'com_content'.DS.'category');
// Adding needed params to load info
JRequest::setVar('view', 'category');
JRequest::setVar('layout', 'blog');
JRequest::setVar('Itemid', '102');
JRequest::setVar('id', $this->item->catid);
// Get and load language
$lang =& JFactory::getLanguage();
$lang->load('com_content', JPATH_SITE);
// Render page
$cont->display();
Related
Using Twig I render a particular view. I need this view to be translated into a language I choose. I display the view using:
return $this->setup->twig->display($view, $params);
Where $view is the name of the *.html.twig template and $params is an array with the parameters I need to pass.
However, if I want to translate the template before displaying it, how I have to do it?
Currently I have included .yml files for different languages and I have also replaced the text inside the views with the appropriate corresponding values from the yml file.
Apart from everything else, I have also loaded the Twig translator in a file separate from the rest of the project. It has the following code:
require dirname(__DIR__) . '/vendor/autoload.php';
use Symfony\Component\Translation\Translator;
use Symfony\Component\Translation\Loader\ArrayLoader;
class Translation
{
public $translator;
public function translator()
{
$this->translator = new Translator('fr_FR');
$this->translator->addLoader('array', new ArrayLoader());
$this->translator->addResource('array', array(
'Symfony is great!' => 'J\'aime Symfony!',
), 'fr_FR');
var_dump($this->translator->trans('Symfony is great!'));
}
}
$show = new Translation;
$show->translator();
And it really displays the translation.
Still, I have no idea how to connect everything together....
Did you try to set the locale before rendering your twig view?
public function exampleAction(Request $request) {
$locale = 'de'; // Set the language
$request->setLocale($locale);
$content = $this->renderView($view, $params);
// Maybe return to default locale....
}
I am working in a custom library for a project to be used in CI3.1 (CodeIgniter 3.1). This is a piece of code:
class NavigationMenu
{
protected $CI;
public function __construct($params = ['config' => 'navigation'])
{
$this->CI =& get_instance();
$this->CI->load->helper('url');
$this->CI->config->load($params['config'], true);
$this->CI->load->model('nav_model', 'nav');
}
....
}
The default config 'navigation.php` file have the following code:
$config['navigation_open'] = '<ul class="nav">';
$config['navigation_close'] = '</ul>';
$config['item_open'] = '<li>';
$config['item_open_active_class'] = 'active';
As you can see I am loading the url helper, the navigation config file and the nav_model model. Is there any way to check if them has been loaded previously? Could be the case when I want to save time and then setup the autoload.php as follow:
$autoload['helper'] = ['url'];
$autoload['config'] = ['navigation'];
$autoload['model'] = ['nav_model'];
If that's the case how do I check if has been loaded in order to not try to load once again?
I have look over the documentation for config class and couldn't find anything helpful
You can check is any function from url helper available at the moment, so You'll be able to understand was helper loaded or You should do it by Yourself:
if(!function_exists('site_url'))
$this->CI->load->helper('url');
It's an easy trick if You need to check is any helper was loaded, but it's not too clear how to check is config/model loaded, so if You really want to create Your own autoloader, You need to do similar checks with the core object ($this->CI):
if(!method_exists($this->CI,'nav'))
$this->CI->load->model('nav_model', 'nav');
I have a long list of dependency injections to display a page with an article, navigation, etc. And currently I put them in a file called index.php to glue them together.
index.php,
use MyCustomVerndorName\Constant\Mapper\ConstantsMapper;
use MyCustomVerndorName\Slug\Mapper\SlugMapper;
.... (more)
$ConstantService = new ConstantService();
$ConstantController = new ConstantController();
$ArticleService = new ArticleService();
$ArticleController = new ArticleController();
// Prepare Nav model.
$NavModel = new NavModel();
$NavMapper = new NavMapper($PdoAdapter);
$NavService->setMapper($NavMapper)->setModel($NavModel);
// Prepare Article model.
$ArticleModel = new ArticleModel();
$ArticleMapper = new ArticleMapper($PdoAdapter);
// Prepare components.
$ArticleContentComponent = new ArticleContentComponent($PdoAdapter);
... (more)
// Inject components.
$ArticleMapper->addComponent($ArticleContentComponent);
... (more)
$NavChildrenComponent = new NavChildrenComponent($PdoAdapter);
... (more)
// Inject components.
$NavMapper->addComponent($NavChildrenComponent);
$NavMapper->addComponent($NavLanguageComponent);
// Controll the slug.
$SlugController->setService($SlugService)->fetchRow([
"url" => $url
]);
// Control the nav.
$NavController->setService($NavService)->fetchRows();
// Controll the article.
$ArticleService->setMapper($ArticleMapper)->setModel($ArticleModel);
$ArticleController->setService($ArticleService)->fetchRow([
"url" => $url
]);
// Prepare template.
$PageTemplate = new PageTemplate();
// Prepare view.
$ArticleView = new ArticleView($PageTemplate, $ArticleModel);
$ArticleView->setSlug($SlugModel);
$ArticleView->setNav($NavModel);
// Render the view.
echo $ArticleView->render('index.php');
in my router.php (I'm using AltoRouter),
use AltoRouter as Router;
$Router = new Router();.
$Router->map('GET', '/', '/article/container');
... (and other routes)
if($match)
{
$target = $match['target'];
$url = isset($match['params']['url']) ? $match['params']['url'] : DEFAULT_HOMEPAGE;
$language = isset($match['params']['language']) ? $match['params']['language'] : null;
include __DIR__ . $target . '.php';
}
I'm thinking to make the list of dependency injections in index.php into a container class so I can call this class whenever it is needed,
For instace in the router.php,
$Router->map('GET', '/', 'MyCustomVerndorName\Article\Container\ArticleContainer');
....
new $target($PdoAdapter, $url, $language);
And this container class,
namespace MyCustomVerndorName\Article\Container;
// Mapper.
use MyCustomVerndorName\Constant\Mapper\ConstantsMapper;
...
class ArticleContainer
{
/*
* Construct dependency.
*/
public function __construct(\MyCustomVerndorName\Adapter\PdoAdapter $PdoAdapter, $url, $language)
{
$ConstantService = new ConstantService();
$ConstantController = new ConstantController();
// Slug.
$SlugService = new SlugService();
$SlugController = new SlugController();
// Nav.
$NavService = new NavService();
$NavController = new NavController();
// Article.
$ArticleService = new ArticleService();
$ArticleController = new ArticleController();
// Prepare Article model.
$ArticleModel = new ArticleModel();
$ArticleMapper = new ArticleMapper($PdoAdapter);
// Prepare components.
$ArticleContentComponent = new ArticleContentComponent($PdoAdapter);
...
// Inject components.
$ArticleMapper->addComponent($ArticleContentComponent);
...
// Control the nav.
$NavController->setService($NavService)->fetchRows();
// Controll the article.
$ArticleService->setMapper($ArticleMapper)->setModel($ArticleModel);
$ArticleController->setService($ArticleService)->fetchRow([
"url" => $url
]);
// Prepare template.
$PageTemplate = new PageTemplate();
// Prepare view.
$ArticleView = new ArticleView($PageTemplate, $ArticleModel);
$ArticleView->setSlug($SlugModel);
$ArticleView->setNav($NavModel);
// Render the view.
echo $ArticleView->render('index.php');
}
}
Basically, I put all the dependency list into __construct,
public function __construct(\MyCustomVerndorName\Adapter\PdoAdapter $PdoAdapter, $url, $language)
{
...
}
So, is this the correct way of doing a DI Container without relying on the well known containers out there for PHP (such as Pimple, Symfony\DependencyInjection, etc)?
Traditionally, a DI container returns services upon demand. What you are calling ArticleContainer is really just a function then renders a view. It does a lot of DI injecting but it's not a container.
Let's assume you had a real container all properly initialized. Your code would look like:
$container = new Container();
// Some initialization
// Now use it
$viewArticle = $container->get('view_article');
echo $viewArticle->render('index.php');
Hopefully you can see the difference. Once the initialization is complete your application just pulls out the view it needs and renders it. No need to worry about pdo or url etc.
So how do we get our article view service into the container?
$container = new Container();
// Some initialization
$container->set('page_template',function($container)
{
return new PageTemplate();
}
$container->set('article_view',function($container)
{
$articleView = new ArticleView(
$container->get('page_template',
$container->get('article_model')
);
$articleView->setSlug($container->get('slug_model');
$articleView->setNav ($container->get('nav_model');
return $articleView;
};
// Now use it
$viewArticle = $container->get('article_view');
echo $viewArticle->render('index.php');
So we defined two service functions for our container. When we do $container->get('article_view');, the container calls the function with the container itself as an argument. The function creates the desired class by pulling dependencies out of the container and then returns the new object.
One assumes that you will probably have more page views in your application and that most of them will need a page_template. The same page_template service we defined can be used by your other views as well. So we start to get some reuse out of the container.
You basically just continue to add services to the container.
You can use Pimple for this but it's also instructive to make your own container. Really not much to it.
Hi i wont to make something like that.
http:// example.com/ - Main Controller
http:// example.com/rules/ - Main Controller where content get from database, but if not exist
return 404 page. (It's ok, isn't problem.)
But if i have subfolder in application/controlles/rules/
I want to redirect it to Main Contorller at Rules folder.
This follow code can solve problem, but i don't know how it right realise.
At routes.php:
$route['default_controller'] = "main";
$route['404_override'] = '';
$dirtest = $route['(:any)'];
if (is_dir(APPPATH.'controllers/'.$dirtest)) {
$route['(:any)'] = $dirtest.'/$1';
} else {
$route['(:any)'] = 'main/index/$1';
}
Ok, what I have:
controllers/main.php
class Main extends CI_Controller {
public function __construct()
{
parent::__construct();
$this->load->model('main_model');
}
public function index($method = null)
{
if (is_dir(APPPATH.'controllers/'.$method)) {
// Need re-rout to the application/controllers/$method/
} else {
if ($query = $this->main_model->get_content($method)) {
$data['content'] = $query[0]->text;
// it shows at views/main.php
} else {
show_404($method);
}
}
$data['main_content'] = 'main';
$this->load->view('includes/template', $data);
}
}
Updated Again (routes.php):
So, seem's like what i search (work example):
$route['default_controller'] = "main";
$route['404_override'] = '';
$subfolders = glob(APPPATH.'controllers/*', GLOB_ONLYDIR);
foreach ($subfolders as $folder) {
$folder = preg_replace('/application\/controllers\//', '', $folder);
$route[$folder] = $folder.'/main/index/';
$route[$folder.'/(:any)'] = $folder.'/main/$1';
}
$route['(:any)'] = 'main/index/$1';
But, in perfectly need some like this:
http:// example.com/1/2/3/4/5/6/...
Folder "controllers" has subfolder "1"?
YES: Folder "1" has subfolder "2"?
NO: Folder "1" has controller "2.php"?
NO: Controller "controllers/1/main.php" has function "2"?
YES: redirect to http:// example.com/1/2/ - where 3,4,5 - parameters..
It is realy nice, when you have structure like:
http://example.com/blog/ - recent blog's posts
http://example.com/blog/2007/ - recent from 2007 year blog's posts
http://example.com/blog/2007/06/ - same with month number
http://example.com/blog/2007/06/29/ - same with day number
http://example.com/blog/web-design/ - recent blog's post's about web design
http://example.com/blog/web-design/2007/ - blog' posts about web design from 2007 years.
http://example.com/blog/current-post-title/ - current post
Same interesting i find http://codeigniter.com/forums/viewthread/97024/#490613
I didn't thoroughly read your question, but this immediately caught my attention:
if (is_dir($path . '/' . $folder)) {
echo "$route['$folder/(:any)'] = '$folder/index/$1';"; //<---- why echo ???
}
Honestly I'm not sure why this didn't cause serious issues for you in addition to not working.
You don't want to echo the route here, that will just try to print the string to screen, it's not even interpreted as PHP this way. There are also some issues with quotes that need to be remedied so the variables can be read as variables, not strings. Try this instead:
if (is_dir($path . '/' . $folder)) {
$route[$folder.'/(:any)'] = $folder.'/index/$1';
}
Aside: I'd like to offer some additional resources that are not directly related to your problem, but should help you nonetheless with a solution:
Preferred way to remap calls to controllers: http://codeigniter.com/user_guide/general/controllers.html#remapping
Easier way to scan directories: http://php.net/manual/en/function.glob.php
It's hard to say why the registering of your routes fails. From your code I can see that you're not registering the routes (you just echo them), additionally I see that the usage of variables in strings are used inconsistently. Probably you mixed this a bit, the codeigniter documentation about routes is not precise on it either (in some minor points, their code examples are not really syntactically correct, but overall it's good).
I suggest you first move the logic to register your dynamic routes into a function of it's own. This will keep things a bit more modular and you can more easily change things and you don't pollute the global namespace with variables.
Based on this, I've refactored your code a bit. It does not mean that this works (not tested), however it might make things more clear when you read it:
function register_dynamic_routes($path, array &$route)
{
$nodes = scandir($path);
if (false === $nodes)
{
throw new InvalidArgumentException(sprintf('Path parameter invalid. scandir("$path") failed.', $path));
}
foreach ($nodes as $node)
{
if ($node === '.' or $node === '..')
continue
;
if (!is_dir("{$path}/{$node}")
continue
;
$routeDef = "{$folder}/(:any)";
$routeResolve = "{$folder}/index/\$1";
$route[$routeDef] = $routeResolve;
# FIXME debug output
echo "\$route['{$routeDef}'] = '{$routeResolve}';";
}
}
$path = APPPATH.'controllers/';
register_dynamic_routes($path, $route);
$route['(:any)'] = 'main/index/$1';
Next to this you probably might not want to shift everything onto the index action, but a dynamic action instead. Furthermore, you might want to have a base controller that is delegating everything into the sub-controllers instead of adding the routes per controller. But that's up to you. The example above is based on the directory approach you outlined in your question.
Edit: Additional information is available in the Controllers section next to the URI Routing section
All this seems kind of complicated.
Plus, if you have hundreds (or thousands or more?) of possible routes in a database you may not want to load all of them into the "$routes" array every time any page loads in your application.
Instead, why not just do this?
last line of routes.php:
$route['404_override'] = 'vanity';
Controller file: Vanity.php:
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
class Vanity extends MY_Controller {
/**
* Vanity Page controller.
*
*/
public function __construct() {
parent::__construct();
}
public function index()
{
$url = $_SERVER['PHP_SELF'];
$url = str_replace("/index.php/", "", $url);
// you could check here if $url is valid. If not, then load 404 via:
//
// show_404();
//
// or, if it is valid then load the appropriate view, redirect, or
// whatever else it is you needed to do!
echo "Hello from page " . $url;
exit;
}
}
?>
I'd like to obtain a list of all controllers in a Codeiginiter project so I can easily loop through each of them and add defined routes. I can't seem to find a method that will give me what I'm after ?
Here is the code snippet from the routes.php file where I would like to access the array: -
// I'd like $controllers to be dynamically populated by a method
//
$controllers = array('pages', 'users');
// Loop through each controller and add controller/action routes
//
foreach ($controllers as $controller) {
$route[$controller] = $controller . '/index';
$route[$controller . '/(.+)'] = $controller . '/$1';
}
// Any URL that doesn't have a / in it should be tried as an action against
// the pages controller
//
$route['([^\/]+)$'] = 'pages/$1';
UPDATE #1
To explain a little more what I'm trying to achieve.. I have a Pages controller which contains pages such as about, contact-us, privacy etc. These pages should all be accessible via /about, /contact-us and /privacy. So basically, any action/method in the Pages controller should be accessible without having to specify /pages/<action>.
Not sure if I'm going about this the right way ?
Well to directly answer to coding question, you can do this:
foreach(glob(APPPATH . 'controllers/*' . EXT) as $controller)
{
$controller = basename($controller, EXT);
$route[$controller] = $controller . '/index';
$route[$controller . '/(.+)'] = $controller . '/$1';
}
Buuuuuut this may not work out to be the most flexible method further down the line.
There are a few other ways to do it. One is to create a MY_Router and insert
$this->set_class('pages');
$this->set_method($segments[0]);
before/instead of show_404();
That will send /contact to /pages/contact, but only if no controllers, methods, routes are mapped to first.
OOOOOOORRRRRR use Modular Separation and add the following to your main routes.php
$routes['404'] = 'pages';