I'm using the CakeDC Tags plugin in my CakePHP project. I am using the TagCloudHelper to output a list of links but this helper isn't formatting the links the way I would like. Specifically the method _tagUrl($tag, $options) is generating links with named parameters instead of using the query string.
Instead of
$options['url'][$options['named']] = $tag[$options['tagModel']]['keyname'];
I get the desired behavior with the following change
$options['url']['?'][$options['named']] = $tag[$options['tagModel']]['keyname'];
what is the best practice way of overriding this method? Do I make another class that extends TagCloudHelper? How then would I tell CakePHP to use my class instead of the plugin's?
I was able to override the helper with my own
// app/View/Helper/MyTagCloudHelper.php
App::uses('TagCloudHelper', 'Tags.View/Helper');
class MyTagCloudHelper extends TagCloudHelper {
protected function _tagUrl($tag, $options) {
$options['url']['?'][$options['named']] = $tag[$options['tagModel']]['keyname'];
return $options['url'];
}
}
Then in the controller
public $helpers = array('TagCloud' => array('className'=>'MyTagCloud'));
the className option let's you alias the name of the helper
Related
Is it possible to set a variable from within a Listener. This is what I am trying accomplish:
I created a Blog plugin and because the Homepage will be complex I wanted to attach an event to beforeRender for the Pages controllers and then return a list of 200 items that can be 'consumed' in different views and elements(ie. /src/Template/Pages/display.ctp and /src/Template/Element/latest_blog_items.ctp)
So far I have created this
// Blog.config/bootstrap.php
<?php
$homepageListener = new HomepageListener();
EventManager::instance()->attach($homepageListener);
And in the same plugin
// Blog.src/Event/HomepageListener.php
<?php
namespace Blog\Event;
use Cake\Event\Event;
use Cake\Event\EventListenerInterface;
use Cake\Core\Configure;
use Cake\ORM\TableRegistry;
class HomepageListener implements EventListenerInterface {
public function implementedEvents() {
return [
'Controller.beforeRender' => 'getBlogItems',
];
}
public function getBlogItems(Event $event) {
if ($event->subject()->name == 'Pages') {
$fBlogItems = TableRegistry::get('Blog.BlogPosts')->find('all')->order(['BlogPosts.created' => 'desc'])->limit(200)->toArray();
// This works, but I didn't want to do it this way
Configure::write('fBlogItems', $fBlogItems);
// My desired solution would be creating a variable similar to what is done in Controllers
// ie. $this->set('fBlogItems', $fBlogItems);
}
}
}
I have not figure out how, if possible, I can set a variable (ie. $this->set('fBlogItems, $fBlogItems) and ensure it is available in my Template files.
Is this even possible or advisable?
Does it break MVC?
Is there a better way?
$event->subject() is your controller instance so just use $event->subject()->set().
I have a helper we use in all our CakePHP apps that I am trying to extend to include an app-specific method. However, I'd like to refer to the helper by its original name.
e.g., instead of
$appSpecificHelperName->method()
I want to have my child class referred to by the base class name:
$helperName->method()
in the view.
Is there a way to do that? This is specifically in Cake 1.2, but the app will be upgraded to Cake 2 or possibly 3 next year, and I'd like to know the solution for any/all version(s).
Found the answer in the docs:
One common setting to use is the className option, which allows you to create aliased helpers in your views. This feature is useful when you want to replace $this->Html or another common Helper reference with a custom implementation:
// app/Controller/PostsController.php
class PostsController extends AppController {
public $helpers = array(
'Html' => array(
'className' => 'MyHtml'
)
);
}
// app/View/Helper/MyHtmlHelper.php
App::uses('HtmlHelper', 'View/Helper');
class MyHtmlHelper extends HtmlHelper {
// Add your code to override the core HtmlHelper
}
I'm new in CakepHP and I want to use a method (that returns a value) in an action in CakePHP 3. Sort of like this:
public function specify(){
if(isObject1){
// do something}
}
private isObject1($objname){
return true;
}
What is the right syntax?
CakePHP is PHP
The way to call a method from another method of the same class is the same as with any php project using objects - by using $this:
public function specify() {
$something = 'define this';
if($this->isObject1($something)) {
// do something
}
}
private function isObject1($objname) {
return true;
}
There's more info on how to use objects in The PHP manual.
The answer by #AD7six suggests adding a method within the controller which is not right if it is not going to be used as an action.
I think you should consider creating classes under vendor and including them in your controller and calling your class/method. The convention is vendor/$author/$package. You can either autoload them with composer or use a require call to include your file. If you don't want to create a class and just want to have functions, that can be done too.
Do take a look at cakephp's loading vendor files section.
We are familiar with Components and Helpers in CakePHP.
I have an ABC Component and XYZ helper and both have same function (around 2000 lines total 4000 lines).
there is any way to use same function in Controller and .CTP files. it's not good to use same function 2 time.
any method so i can use Component/Helper function in Helper/Component without rewrite ?
same method into component and helper >>
Component
class DATAComponent extends Component {
public $components = array('Session', 'THmail');
public function UsaStateList()
{ /********/}
Helper
class LabHelper extends AppHelper {
public function UsaStateList()
{ /********/}
}
Well, you will have to rewrite something, it's not going to solve itself.
CakePHP is still PHP, so you can easily apply common patterns to keeps things DRY. The most straight forward way would probably be to move the shared functionality into an utility class that your component and helper can both use internally while leaving their public API unchanged.
Some of CakePHPs helpers do something similar, check for example the time helper.
http://book.cakephp.org/2.0/en/core-libraries/helpers/time.html
http://book.cakephp.org/2.0/en/core-utility-libraries/time.html#CakeTime
Traits might be an option too, depending on the amount of functionality being shared and how much it is tied to the use in a component/helper.
I wanted to use a component inside a helper. So i came out with the following solution.
<?php
App::uses('AppHelper', 'View/Helper');
App::import('Component', 'MyComponent');
class MyHelperHelper extends AppHelper {
private $MyComponent = null;
public function __construct(View $View, $settings = array()) {
$collection = new ComponentCollection();
$this->MyComponent = new MyComponentComponent($collection);
parent::__construct($View, $settings);
}
public function myCustomFunction() {
return $this->MyComponent->myCustomFunction();
}
}
Simple Answer
For common functions across your application, add a Lib or Utility class.
app/Lib/MyClass.php
class MyClass {
public static function usaStateList() {
// ...
}
}
Then add this at the top of whichever file you want access to the function:
App::uses('MyClass', 'Lib');
And call your function wherever you like:
$myClass = new MyClass();
$states = $myClass::usaStateList();
Better Answer
It looks to me like your specific problem is that you want to be able to get a list of US states in both your controller and your view. The best way to do this is to have a database table of US states.
Create a table in your database called us_states.
Example SQL:
CREATE TABLE `us_states` (
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
`name` VARCHAR(20) NOT NULL,
`abbreviation` CHAR(2) NOT NULL
) ENGINE = MYISAM
Insert all the states as data in that table. You can find SQL dumps on the Internet which already have that for you (e.g. Like this one).
Create a UsState model in CakePHP.
/**
* Model for US States
*
* #package app.Model
*/
class UsState extends AppModel {
/**
* Default sort order
*
* #var string|array
*/
public $order = 'UsState.name';
}
What you can then do is access the states from your controller just by using the model.
/**
* Your Controller
*
* #package app.Controller
*/
class YourController extends AppController {
public function index() {
// Get a list of US states
$this->loadModel('UsState');
$states = $this->UsState->find('all');
}
}
And if you want to access those states in your View, then you should pass along that data as you normally would any other variables.
I imagine you would want to do that so you can have a select menu of US states, perhaps.
public function index() {
// Get a list of US states
$this->loadModel('UsState');
$states = $this->UsState->find('all');
// Make the states into an array we can use for a select menu
$stateOptions = array();
foreach ($states as $state) {
$stateOptions[$state['id']] = $state['name'];
}
// Send the options to the View
$this->set(compact('stateOptions'));
}
And in your view you can display a select menu for that like this:
echo $this->Form->select('us_state_id', $stateOptions);
I would go with a class in Lib folder. It is pretty clear how to deal with a library class that has only static methods. So, I omit this case. A workable solution for instantiating the class could be to create it in the controller and put it into the registry. If you really need to access CakeRequest, CakeResponse and CakeSession (take a note that CakeSession has many static methods, so you often do not need an instance of that class) from that class you can set it from the controller:
$MyLib = new MyLib();
$MyLib->setRequest($this->request); // optional
ClassRegistry::addObject('MyLib', $MyLib);
Then from the view or any other place you would just get an instance of MyLib from the registry:
ClassRegistry::getObject('MyLib');
or simply
$list = ClassRegistry::getObject('MyLib')->UsaStateList();
So, your class would be something like this:
// /Lib/MyLib.php
class MyLib {
public function setRequest(CakeRequest request) {...}
public function UsaStateList() {...}
}
ok you want to use a single function in component and helper, I can think of 3 things you can do:
Calling a function from the component in your helper.
Calling a function from a helper in your component.
Create a model or use an existing model where you put the function, and you can use this function in your component or your help.
Option numbre 3:
In your helper and component, you need import a model, assuming that your function be in a model "StateList":
how you call the funcion of the model "StateList" in your helper, so:
App::import("Model", "StateList");
$model = new StateList();
$model->UsaStateList();
how you call the funcion of the model "StateList" in your component, so:
$model = ClassRegistry::init('StateList');
$model->UsaStateList();
ans if you want use the same function in a controller just:
$this->loadModel('StateList');
$this->StateList->UsaStateList();
I have a class that uses a lot of database internally, so I built the constructor with a $db handle that I am supposed to pass to it.
I am just getting started with PHPUnit, and I am not sure how I should go ahead and pass the database handle through setup.
// Test code
public function setUp(/*do I pass a database handle through here, using a reference? aka &$db*/){
$this->_acl = new acl;
}
// Construct from acl class
public function __construct(Zend_Db_Adapter_Abstract $db, $config = array()){
You would do it like this:
public class TestMyACL extends PHPUnit_Framework_TestCase {
protected $adapter;
protected $config;
protected $myACL;
protected function setUp() {
$this->adapter = // however you create a new ZendDbADapter
$this->config = // however you create a new config array
$this->myACL = new ACL($this->adapter, $this->config); // This is the System Under Test (SUT)
}
}
IMHO, you need to work on your naming conventions. See Zend Framework Naming Conventions, for a start. An example would be the underscore, look up variables in the link. Also class naming.
You can do normally without reference same as constructor because this method is simplest.