I'm totally new to the CakePhp framework, so I'm doing the basic tutorial. So far so good, I built the scaffolding for my models, authentication works fine, but I't a little excessive: I would like to allow one action ('index' for example) to be allowed even for non-authenticated users.
I suspect it must have something with "BeforeFilter()", but any solution I tried hasn't worked - probably because they'for CPHP 2.0, and/or I'm dumb
.
The code is here, though it's not particuolarily interesting since it's the one generated by the scaffolding mechanism.
<?php
namespace App\Controller;
use App\Controller\AppController;
/**
* Frutta Controller
*
* #property \App\Model\Table\FruttaTable $Frutta
*/
class FruttaController extends AppController
{
/**
* Index method
*
* #return void
*/
public function index()
{
$this->set('frutta', $this->paginate($this->Frutta));
$this->set('_serialize', ['frutta']);
}
//cut..
}
Use the following:
function beforeFilter() {
parent::beforeFilter();
$this->Auth->allow('index'); //allow index without authentication
}
Reference : http://book.cakephp.org/3.0/en/controllers/components/authentication.html#making-actions-public
Related
I am working with a 3rd party PHP server which has implemented its APIs via CakePHP 2.x
It looks like CakePHP accepts query parameters even if its not specifically been implemented in the controller side.
For example, when I invoke this URL in my browser
https://server/api/logs.json?sort=TimeKey&direction=desc
It returns a descending sorted list based on TimeKey like this:
{"logs":[{"Log":{"TimeKey":"1486576200.482136","Component":"zma_m5","ServerId":"0","Pid":"10931","Level":"0","Code":"INF","Message":"Deck Camera: 4138848 - Opening new event 66155, section start","File":"monitor.cpp","Line":"1532"}} <etc>
I was wondering if its possible to construct a query URL that can also apply a "condition", that is, only show fields where "Code=ERR" without having to change the controller code? Given its 3rd party, my first preference is not to have to change it and handle it via my URL I construct.
The controller implementation is here:
<?php
App::uses('AppController', 'Controller');
/**
* Logs Controller
*
* #property Log $Log
* #property PaginatorComponent $Paginator
*/
class LogsController extends AppController {
/**
* Components
*
* #var array
*/
public $components = array('Paginator', 'RequestHandler');
public $paginate = array(
'limit' => 100,
'order' => array( 'Log.TimeKey' => 'asc' ),
'paramType' => 'querystring'
);
/**
* index method
*
* #return void
*/
public function index() {
$this->Log->recursive = -1;
$this->Paginator->settings = $this->paginate;
$logs = $this->Paginator->paginate('Log');
$this->set(compact('logs'));
}
// ...
}
I've been trying various combinations (such as &Code=ERR &Log[Code]=ERR) which don't work. Thanks.
I was wondering if its possible to construct a query URL that can also apply a "condition" [...]
I'm not familiar with ZoneMinder, but normally that's not possible with the referenced code.
By default the paginator component only supports the sort, direction, limit and page options.
I have a File entity for handle files upload in other entities (news/blog/etc).
I point to it with a OneToOne relation and it works fine. But I would change the upload dir, for each relation entity :
upload/news
upload/blog
The upload path is set in my file entity so i dont know how to automaticaly update the path foreach relations...
do you have an idea on how to do it ?
Thanks
Of course you can do it.
On your file entity side, you can add a uploadDir attribute, and create a setter like this :
private $uploadDir;
public function setUploadDir($uploadDir)
{
if (!$this->uploadDir) {
$this->uploadDir = $uploadDir;
}
}
your comment suggest you use Symfony with Doctrine right ?
So you can edit the classical getUploadDir() method like this:
protected function getUploadDir()
{
return 'uploads/' . $this->uploadDir;
}
In the 'parent' entity you have to update this attribute (when it is created) before persist or update.
(I personally use life cycle callbacks but you can do it manually in your controller)
use Doctrine\ORM\Mapping as ORM;
/**
* News
*
* #ORM\Table(name="News")
* #ORM\HasLifecycleCallbacks
*/
class News
{
//....
/**
* #ORM\OneToOne(targetEntity="File",cascade={"persist","remove"})
*/
private $file;
/**
* #ORM\PrePersist()
* #ORM\PreUpdate()
*/
function setUploadDir()
{
$this->getFile()->setUploadDir('news');
}
// ....
You can also add a constant to make the code cleaner...
I hope it'll help you
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'm using this plugin with CakePHP --> TwitterBootstrap, everything works like a glow except I can't change the layouts. ie. index, add and such.
I have a model called Cinema and have created this with cake bake and the same thing with Views/Cinemas
This is my controller:
<?php
App::uses('AppController', 'Controller');
/**
* Cinemas Controller
*
*/
class CinemasController extends AppController {
/**
* Layout
*
* #var string
*/
public $layout = 'bootstrap';
/**
* Scaffold
*
* #var mixed
*/
public $scaffold;
}
Have i overridden CakePHPs routes into some special scaffolding template?
By defining public $scaffold; in your controller, you tell Cake that you want to enable Scaffolding mode, which allows you to easily insert/edit/delete some records. The scaffolding mode always uses your "default" layout.
In other words, by defining the public $scaffold; variable, you "overrule" your layout. Scaffolding mode doesn't adopt that setting. Simply remove the public $scaffold; line to get back to your bootstrap layout.
I'm running into a severe problem, In fact I'm not well understanding recess naming convention for relationship. I personally think it should be more documented with concrete examples. Hopefully, if i get to understand it, I can start to write some examples.Also, if someone has well understand Recess relationship convention well, in case, he can explain it here, it would be great
I have two table, all table names are in the database are the lower case of the model names. All fields names are same to the models' attributes
Post---->Comment(A Post can have several comments)
Model Post:
<?php
/**
* !Database Default
* !Table post
* !HasMany comment, Class:try.models.Comment,Key:postId
*/
class Post extends Model
{
/** !Column PrimaryKey, Integer, AutoIncrement */
public $postId;
/** !Column String */
public $name;
}
?>
Model Comment:
<?php
/**
* !Database Default
* !Table comment
* !BelongsTo post
*/
class Comment extends Model {
/** !Column PrimaryKey, Integer, AutoIncrement */
public $commentId;
/** !Column String */
public $name;
}
?>
However, when I'm doing the following, I'm getting an error
<?php
Library::import('try.models.Post');
Library::import('try.models.Comment');
Library::import('recess.framework.controllers.Controller');
/**
* !RespondsWith Layouts
* !Prefix Views: home/, Routes: /
*/
class TryHomeController extends Controller {
/** !Route GET */
function index()
{
$this->flash = 'Welcome to your new Recess application!';
$Post= new Post(5);
$Comments=$Post->comment();
}
}
?>
However, I'm getting this error
try.models.Comment has not been imported.
Look in your Post model at the Class line
**
* !Database Default
* !Table post
* !HasMany comment, **Class:try.models.Comment**,Key:postId
*/
Here you are including the full classpath, try.models.Comment. You only need to specify Comment as the class to include. Be sure that your file names follow the ClassName.class.php convention.