How to copy Joomla administrator component as a site one? - php

I've installed Joomla v3.4.7 to test and prepare my project.I created a component 'HelloWorld' step by step according the official tutorial [https://docs.joomla.org/J3.x:Developing_an_MVC_Component/Using_the_database][1]
,and I succeeded to show the data list,and then the editing page to add or edit existing data, from the Administrator part, just like
localhost/joomla-test/administrator/index.php?option=com_helloworld
After finishing these, I simply copied the files in /Administrator/components/com_helloworld to /components/com_helloworld and overwrite previous files, and access the site component:
localhost/joomla-test/index.php?option=com_helloworld
It didn't work! I used firebug to debug and I got a
NetworkError: 500 Internal Server Error -
http://localhost/joomla-test/index.php?option=com_helloworld
error.... What's happened?
My code:
Site/helloworld.php:
<?php
// import joomla controller library
jimport('joomla.application.component.controller');
// Get an instance of the controller prefixed by HelloWorld
$controller = JControllerLegacy::getInstance('HelloWorld');
// Perform the Request task
$controller->execute(JFactory::getApplication()->input->getCmd('task'));
// Redirect if set by the controller
$controller->redirect();
site/controller.php
<?php
// No direct access to this file
defined('_JEXEC') or die;
// import Joomla controller library
jimport('joomla.application.component.controller');
/**
* General Controller of HelloWorld component
*/
class HelloWorldController extends JControllerLegacy
{
/**
* display task
*
* #return void
*/
protected $default_view = 'helloworlds';
public function display($cachable = false)
{
parent::display($cachable);
echo "controller";
return $this;
}
}
site/views/helloworlds/view.html.php:
<?php
// No direct access to this file
defined('_JEXEC') or die;
// import Joomla view library
jimport('joomla.application.component.view');
/**
* HelloWorlds View
*/
class HelloWorldViewHelloWorlds extends JViewLegacy
{
/**
* HelloWorlds view display method
* #return void
*/
function display($tpl = null)
{
// Get data from the model
$items = $this->get('Items');
$pagination = $this->get('Pagination');
// Check for errors.
if (count($errors = $this->get('Errors')))
{
JError::raiseError(500, implode('<br />', $errors));
return false;
}
// Assign data to the view
$this->items = $items;
$this->pagination = $pagination;
// Set the toolbar
$this->addToolBar();
// Display the template
parent::display($tpl);
}
/**
* Setting the toolbar
*/
protected function addToolBar()
{
JToolBarHelper::title(JText::_('COM_HELLOWORLD_MANAGER_HELLOWORLDS'));
JToolBarHelper::deleteList('', 'helloworlds.delete');
JToolBarHelper::editList('helloworld.edit');
JToolBarHelper::addNew('helloworld.add');
}
}
Please help, thank you all.

It doesn't work this way (by just copying the folder over). You will have to install the component by packaging it and then installing it on the server. You will need to install the zipped component (that has the XML manifest file) on the server.
Try the following: download the basic HelloWorld component from Joomla, and then install it on your website, and then overwrite it with the files from your localhost.

Site and Administrator have slight differences; the most relevant are related to the template, since in Admin you can count on a standard layout; this is why in an administrator view.html you setup the toolbar and the sidemenu; on the frontend, you create menus pointing to views with configuration.
Your best bet is to create fresh files for controller and view, and then you can create your models inheriting from the administrator modules, that is the best for avoiding code duplication, and it will still leave you the maximum flexibility for customizing the views.

Toolbar cannot work in the front end. It's weird, yes, but if you look it is a separate thing in the administrator folder. It actually checks whether you are in admin as well. I once made a patch to removed the check but it turned out that it would have broken tons of components that had worked around this.
Second, there are many calls to things that rely on relative positioning or that might even explicitly require admin access.
Third, there are indeed some things that are slightly different because in the back end you basically never render the normal view, only the list view and the edit view.
If you want to do admin functions in the front end the best general approach is to look at how com_config, Com_templates and com_modules do it.

Related

Silverstripe Elemental Module redirects to frontend 404 page on element save

I use dnadesign/silverstripe-elemental 2.x-dev, and Silverstripe 4.0.1.
I created a module for page to hold all pages. This is how i added the extension to HomePage.
XYPage\Model\HomePage:
extensions:
- DNADesign\Elemental\Extensions\ElementalPageExtension
This is my HomePageController:
namespace XYpage\Controller;
use PageController;
class HomePageController extends PageController
{
}
This is my HomePageModel:
namespace XYpage\Model;
use Page;
use XYpage\Controller\HomePageController;
class HomePage extends Page
{
private static $table_name = 'HomePage';
/**
* As our controller resides in a different namespace we have to
overwrite this method
*
* #return string
*/
public function getControllerName()
{
return HomePageController::class;
}
}
I changed the template variable to $ElementalArea. I see the expected UI in the BackEnd.
Now if i save an single element in the backend i always get redirected into the front-end to the 404 Page.
When i switch back to the Backend the element is linked to the page.
If i fill in content to the WYSIWYG editor on the Content Element and save it the content gets displayed on the page in the frontend.
If i try to edit that element misses the WYSIWYG editor for the content.
I tried hard to fix this, red the docs but i donĀ“t see what i did wrong.
There is an issue with BetterButtons & DNADesign Elemental.
Just add this to disable BetterButtons for ElementContent in the meantime.
DNADesign\Elemental\Models\ElementContent:
better_buttons_enabled: false
You have two problems that I can see immediately:
1: Your YAML configuration is referencing XYPage\HomePage, where the class's namespace is actually XYPage\Model\HomePage. I suspect this is actually an error in your example rather than your actual project, since you say that the elemental editor is working in the CMS.
2: Your getControllerName() method is returning HomePageController::class which isn't imported in the class, so it will be resolving to the same namespace as the model (XYPage\Model\HomePageController). While this is the default/expected location for SiteTree controllers, overloading this code means it's all on you! Add use XYPage\Controller\HomePageController; to your class definition.
After a lot of debugging i found out what caused this some of that behavior. In my case one problem was that i used unclecheese/silverstripe-gridfield-betterbuttons with elemental.
The next Problem is a react error:

How to create a route with custom path in Symfony RoutingBundle (PHPCR)?

I'm currently researching Symfony CMF and PHPCR for a project I recently started. What I'm currently trying to figure out is how to create a Route and save it into the database. As far as I understand, I must use Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr\Route and persist the element into the database. This works fine, but automatically generates a route path, which is not what I want. What I need to do is generate a custom route which links to a specific controller. Here is my code:
$em = $this->get('doctrine_phpcr.odm.document_manager');
$parent = $em->find(null, '/cms/routes');
$route = new \Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr\Route();
$route->setParentDocument($parent);
$route->setName('my_route_name');
$route->setDefault('_controller', 'AppBaseBundle:Frontend/Users:index');
$em->persist($route);
$em->flush();
If i execute this code, the generated route will be /cms/routes/my_route_name. From what I can see, you could use $route->setPath('/testing');, but that generates the following exception:
Can not determine the prefix. Either this is a new, unpersisted document or the listener that calls setPrefix is not set up correctly.
Does anybody have any ideas how to solve this?
In PHPCR, every document has a path where it is store. If you are familiar with doctrine ORM, the path has the role of the ID. The difference with ORM is that all documents (regardless of their type) live in the same tree. This is great, because your route can reference just anything, it is not limited to specific document types. But we need to create some structure with the paths. This is why we have the prefix concept. All routes are placed under a prefix (/cms/routes by default). That part of the document path is removed for the URL path. So repository path /cms/route/testing is the url domain.com/testing.
About your sample code: Usually, you want to configure the controller either by class of the content document or by route "type" attribute to avoid storing a controller name into your database to allow for future refactoring. A lot of this is explained in the [routing chapter of the CMF documentation][1] but the prefix is only used there, not explicitly explained. We need to improve the documentation there.
[1] http://symfony.com/doc/master/cmf/book/routing.html
I managed to find a way to overcome this issue. Because in my project I also have the RouteAutoBundle, I created a class which extends \Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr\Route. Inside that class I added:
/**
* #PHPCR\Document(referenceable=true)
*/
class MenuRoute extends Route
{
protected $url;
/**
* Get $this->url
*
* #return mixed
*/
public function getUrl() {
return $this->url;
}
/**
* Set $this->url
*
* #param mixed $url
*/
public function setUrl($url) {
$this->url = $url;
}
}
After that I added this to cmf_routing_auto.yml:
App\MenuBundle\Document\MenuRoute:
uri_schema: /{getUrl}
token_providers:
getUrl: [content_method, { method: getUrl }]
So now one would just create an instance of MenuRoute (just like when using Route) and call the method setUrl($your_url) passing the desired url.
If anybody finds a better way, I'm opened to suggestions.

Prevent publish all in silverstripe

Silverstripe has the ability for users to publish all pages on a site available at /admin/pages/publishall and the publish all code is in /cms/code/controllers/CMSMain.php
We've had some problems with users accidentally running publish all in production when it should only be run from other environments - How can I disable the publishall functionality?
My first approach to fixing this was to create a custom CMSPageController.php in which I would overwrite publishall, and just place a call to parent::publishall($request) inside an if block checking which environment we were in. The problem with this approach was that injecting the custom class created issues with editing pages. Ideally I would have been able to just extend publishall but as Nunser mentioned above, Silverstripe(frustratingly) hasn't included extension hooks in that method.
I ended up creating a custom route to overwrite admin/pages/publishall
so inside mysite/_config/routes.yml
'admin/pages/publishall': CustomPublishallController
and in mysite/code/controllers/CustomPublishallController.php
<?php
/**
* Controller for providing silverstripes inbuilt publishall functionality with the ability to
* run in production removed.
*
* #package sitename
* #subpackage mysite
*/
class CustomPublishallController extends Controller {
public function index($request){
$cmsMain = new CMSMain();
if(ENVIRONMENT_CONSTANT != 'prod'){
return $cmsMain->publishall($request);
}
return Security::permissionFailure($this);
}
}

How to disable front-end login component in Joomla 3?

How to disable front-end login component in Joomla 3?
I have managed to disable front-end user registration by disallowing registration as below.
But still the login form is accessible via below url
index.php?option=com_users&view=login
How can I disable front-end login component without editing the core files?
Given that I have gone through below. I don't want to use a RewriteRule to get it done. I want to show a msg to user that it's disabled.
joomla 3 - how to disable front end login component?
Try this,
Joomla default login module is protected. So you can't edit/disable it from admin side.
Just check extensions-> extension manager -> Search for login
Then that module will display. but you can't make it disable.
So the solution for override this feature without touching core files is template override.
You can simply override this view index.php?option=com_users&view=login in your template.
Editing Protected extension via DB tables
The extensions can not be edited, but you can manage it by turning it
ON, or OFF. Protected, mean that this extension can not be managed,
otherwise it will broke structure of your site. However, if you wish
to bring extension to unlocked status, you can access your DB (in my
case MySQL edited by phpMyAdmin), find reliable table of structure,
find desired string, and change "Status" from "1" to "0". Usually your
host providing you with some DB administering tools.
Hope it helps..
I wrote a plugin for that. It completely disables 'Users' at the front-end.
You could also disable a specific view only for these:
index.php?option=com_users&view=login
index.php?option=com_users&view=registration
index.php?option=com_users&view=profile&layout=edit
This is the code for completely disable users at the front-end
<?php defined('_JEXEC') or die;
use Joomla\CMS\Factory;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\CMS\Router\Route;
class PlgSystemCobizDisableLogin extends CMSPlugin
{
public function onAfterInitialise()
{
$this->disableLogin();
}
protected function disableLogin()
{
$app = Factory::getApplication();
if ($app->isClient('site') === false) return;
$disable_users = $this->params->get('disable_users', 1);
if (!$disable_users) return;
$option = $app->input->getCmd('option');
if ($option == 'com_users') {
$this->redirect();
}
}
protected function redirect()
{
$Itemid = $this->getHomePageItemid();
$app = Factory::getApplication();
$link = Route::_('index.php?Itemid=' . $Itemid);
Factory::getApplication()->enqueueMessage('Toegang gewijgerd', 'error');
$app->redirect($link);
}
protected function getHomePageItemid()
{
$tableName = '#__menu';
$db = Factory::getDbo();
$query = $db->getQuery(true);
$query->select('id');
$query->from($db->quoteName($tableName));
$query->where($db->quoteName('published') . ' = ' . $db->quote(1));
$query->where($db->quoteName('home') . ' = ' . $db->quote(1));
$db->setQuery($query);
$data = $db->loadResult();
return $data;
}
}
Or am I overlooking something here? I acknowledge this disables also registration for users on the front-end. But in most cases that's what I want as well! :-)
in joomla 3.x a
simple way i have found is to edit /components/com-users/controller.php
and mark view string login like that. i got 404 server response but thats what i wanted.
since this is not a url but a component view it is abit hard to redirect.
// Set the default view name and format from the Request.
// $vName = $this->input->getCmd('view', 'login');
$vFormat = $document->getType();
If you want to avoid the 404 server response, after editing /components/com-users/controller.php as indicated in the previous comment, you can create a redirection to send from the frontend login page to wherever you want, say the homepage. It does work.

Execute PHP script inside Joomla! cms once - geo based redirection

Hi
I'm trying to figure the best way to execute a PHP script inside Joomla!
I want to redirect users if they are not from X country (already have a database and the script)
I found this extension but I want to make my own stuff http://bit.ly/daenzU
1) How could I execute the script once for each visitor? Working with Cookies?
2) As I'll put the script inside Joomla! template, I'll modify templates/XXX/index.php
3) Based on 2), Joomla! loads templates/XXX/index.php each time a page loads, so I have to avoid redirection script to be executed twice for an user
Thanks in advance for your ideas and suggestions
Just remember that, in Joomla 3.x, (according to the docs) in order to check an information about the user before the 'Login' event, you need to create you plugin in the 'authentication' context. That is, you need to have your plugin at 'root_to_joomla/plugins/authentication/myplugin/myplugin.php'.
Also, your plugin should be a class named PlgAuthenticationMyplugin, it shold extend the base plugin class 'JPlugin' and should have a public method named 'onUserAuthenticate'.
<?php
...
class PlgAuthenticationMyplugin extends JPlugin {
...
public function onUserAuthenticate($credentials, $options, &$response)
{
//your code here (check the users location or whatever)
}
....
If you want to do that after the Login event, your plugin should be at the user context, at root_to_joomla/plugins/user/myplugin/myplugin.php. And should have a public method 'onUserLogin'.
<?php
class PlgUserMyplugin extends JPLugin {
...
public function onUserLogin($user, $options)
{
//your test goes here
}
...
You can see all other User related events here.
DO NOT modify the template, this will do the trick but is not the right place.
I advise you to create a plug-in, see Joomla docs on plug-ins. Here is event execution order of events.
Create a system plugin and implement onAfterInitialise method. In that method add all of your code.
To prevent the execution of script twice for each user set the user state, see Joomla documentation for states. You can also use session $session = JFactory::getSession(), see documentation.
Here is code... for your plug-in.
// no direct access
defined( '_JEXEC' ) or die( 'Restricted access' );
jimport( 'joomla.plugin.plugin' );
class plgMyPlugin extends JPlugin {
//
public function __construct(){
// your code here
}
//
public function onAfterInitialise(){
$app = JFactory::getApplication();
//
$state = $app->getUserStateFromRequest( "plgMyPlugin.is_processed", 'is_processed', null );
if (!$state){
// your code here
// ....
// Set the Steate to prevent from execution
$app->setUserState( "plgMyPlugin.is_processed", 1 );
}
}
}

Categories