Zend Forms and Ext.grid.Panel - json

I am working for a company who use tabulated html/JS interfaces. These are home grown (real honest to god s) with query events attached to each cell. For the old usage they were suitable, but the interactions required between rows and cells are becoming much more complex on the client side. Specifically they want both server and client side validation.
To facilitate this, the devs I report to are super keen on Zend_Forms, and insist that to use a framework like ExtJS, they don't want to have to write back end and front end code twice (please ignore that if it's all home grown they'll have to do this anyway).
So with that in mind, I'm trying to leverage Zend_Form decorators to create Ext.grid.Panel column defintions. For this, I would need to use decorators to export an array (and then json it using the ViewHelper), or render a JSON string directly.
So this would be something like:
$dateElement = new Zend_Form_Element_Text('startDate', array(
'label' => 'Start Date',
'validators' => array(
new Zend_Validate_Date()
)
));
echo (string)$dateElement;
would output:
{ text: 'Start Date', dataIndex:'startDate', xtype:'datecolumn'}
or (obviously not with string cast, but maybe with ->toArray() or something):
array( 'text' => 'Start Date', 'dataIndex' => 'startDate', 'xtype' => 'datecolumn')
I think if I could get it to this stage, I could get what I need out of it.
Has anyone here tried to do anything similiar to this (getting a JSON/XML/other markups output, rather than HTML from Zend_Forms using Decorators) or if they could point me to any resources?

I think I have a solution...
Make a decorator similar to this:
class My_Form_JSON_Decorator extends Zend_Form_Decorator_Abstract{
protected $xtype;
protected $dataIndex;
public function __construct($dataIndex,$xtype){
$this->xtype=$xtype;
$this->dataIndex=$dataIndex;
}
public function render($content){
$element=$this->getElement();
$label=$element->getLabel
//if you need errors here too do the same with $element->getMessages();
return 'array ("text"=>"'.$label.'","dataIndex"=>"'.$this->dataIndex.'","datecolumn"=>"'.$this->xtype.'")';
}
}
Then, on the form, use something similar to this:
$dateElement = new Zend_Form_Element_Text('startDate', array(
'label' => 'Start Date',
'validators' => array(
new Zend_Validate_Date()
)
$dateElement->setDecorators(array(
new My_Form_JSON_Decorator("startDate","datecolumn");
));
And finally, on the View, you should have this:
{
Date: <?php echo $this->form->startDate; ?>,
}
I didn't tried the code above but, I did it with a similar code I used once when I needed to change Decorators of a Form.
It could not be all correct but, I think that it shows you a way of doing that.
Good work =)

Related

The default remember_me token in Laravel is too long

TL;DR How can I use my own way of generating the remember_me token?
I have an old site, written without any framework, and I have been given the job to rewrite it in Laravel (5.4.23). The DB is untouchable, cannot be refactored, cannot be modified in any way.
I was able to customise the Laravel authentication process using a different User model, one that reflect the old DB. But when it comes to the "Remember me" functionality, I have an issue with the length of the token.
The old site already uses the "Remember me" functionality but its DB field has been defined as BINARY(25). The token generated by the SessionGuard class is 60 characters long.
My first attempt was to try and find a way to shorten the token before writing it into the DB, and expand it again after reading it from the DB. I couldn't find such a way (and I'm not even sure there is such a way).
Then I looked into writing my own guard to override the cycleRememberToken (where the token is generated). I couldn't make it work, I think because the SessionGuard class is actually instantiated in a couple of places (as opposed to instantiate a class based on configuration).
So, I am stuck. I need a shorten token and I don't know how to get it.
Well, I was on the right track at one point.
I had to create my own guard, register it and use it. My problem, when I tried the first time, was that I did not register it in the right way. Anyway, this is what I did.
I put the following in AuthServiceProvides
Auth::extend('mysession', function ($app, $name, array $config) {
$provider = Auth::createUserProvider($config['provider']);
$guard = new MyGuard('lrb', $provider, app()->make('session.store'));
$guard->setCookieJar($this->app['cookie']);
$guard->setDispatcher($this->app['events']);
$guard->setRequest($this->app->refresh('request', $guard, 'setRequest'));
return $guard;
});
I change the guard in config/auth.php as
'guards' => [
'web' => [
'driver' => 'mysession',
'provider' => 'users',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
],
],
and finally my new guard
class MyGuard extends SessionGuard implements StatefulGuard, SupportsBasicAuth
{
/**
* #inheritdoc
*/
protected function cycleRememberToken(AuthenticatableContract $user)
{
$user->setRememberToken($token = Str::random(25));
$this->provider->updateRememberToken($user, $token);
}
}

Cakephp 3: Modifying Results from the database

In my database there is a content table and when fetching data from this table I would like to append field url to the results, which is based on slug field which is contained in the table. Anyway, I have seen a way to do this in the previous versions of cakephp using behavior for the model of this table and then modifying results in afterFind callback in the behavior class. But in version 3 there is no afterFind callback, and they recommend using mapReduce() method instead in the manual, but this method is poorly explained in the manual and I cant figure out how to achieve this using mapReduce().
After little bit of research I realized that the best way to append the url field field to find results is using formatResults method, So this is what I did in my finders:
$query->formatResults(function (\Cake\Datasource\ResultSetInterface $results) {
return $results->map(function ($row) {
$row['url'] = array(
'controller' => 'content',
'action' => 'view',
$row['slug'],
$row['content_type']['alias']
);
return $row;
});
});

Generate link in cakephp using Html helper

I am trying to simply create a link in my controller using the Html helper and I get the below error although I have added the necessary helper:
Call to a member function link() on a non-object
public $helpers = array('Html', 'Form');
$url = $this->Html->link(
'',
'http://www.example.com/',
['class' => 'button', 'target' => '_blank']
);
You can use Helpers inside your view files but not inside your controller
http://book.cakephp.org/2.0/en/views/helpers.html#using-helpers.
For example in your index.ctp
echo $this->Html->link(
__('My link'),
'http://www.example.com/',
array('class' => 'button', 'target' => '_blank')
);
Enabling Html Helper in your Controller is same as in your code.
class ExamplesController extends AppController {
$helpers = array('Html', 'Form');
public function index() {
//
}
}
This is a good question. I think your a little confused with MVC and the separation of concerns the design pattern provides. Take a look (again) at how CakePHP implements MVC: http://book.cakephp.org/2.0/en/cakephp-overview/understanding-model-view-controller.html.
The important thing to remember is that your controllers should never be concerned with creating anchor tags. That's the job of your views. Since helpers are a way to keep your views DRY (Don't Repeat Yourself) having one thats sole responsibility is to create HTML elements is really handy. Views are dependent on controllers to determine what variables are set, what their value is, as well as what helpers are loaded. For more information on Helpers as well as components for controllers and behaviors for models check out http://book.cakephp.org/2.0/en/getting-started/cakephp-structure.html as well as each of their individual documentation pages:
Helpers - http://book.cakephp.org/2.0/en/views/helpers.html
Components - http://book.cakephp.org/2.0/en/controllers/components.html,
Behaviors - http://book.cakephp.org/2.0/en/models/behaviors.html.
Now that you have a better understanding of MVC, let's take a look at your specific issue. Your wanting to create a link in your controller. I assume it might be dynamic depending on some other variables so I'm going to roll with that.
A common problem that you can solve you want to show a login/logout link depending on if the user is already logged in.
In app/Controller/ExampleController.php
class ExampleController extends AppController {
public $components = array('Auth');
public $helpers = array('Html', 'Form');
public function beforeRender() {
parent::beforeRender();
//if Auth::user() returns `null` the user is not logged in.
if ($this->Auth->user() != null) {
$logInOutText = 'Log out';
$logInOutUrl = array('controller' => 'users', 'action' => 'login');
} else {
$logInOutText = 'Log in';
$logInOutUrl = array('controller' => 'users', 'action' => 'logout');
}
$this->set(compact('logInOutText', 'logInOutUrl'));
}
}
You can then so something simple in your view. In this case I'm choosing the default layout because I want the links in every rendered page. app/View/Layouts/default.ctp
<!-- More HTML above -->
<?php
// "Html" in `$this->Html` refers to our HtmlHelper. Note that in a view file
// like a `.ctp`, `$this` referes to the View object, while above in the
// controller `$this` refers to the Controller object. In the case
// `$this->Html`, "Html" would refer to a component. The same goes for Models
// and behaviors.
echo $this->Html->link($logInOutText, $logInOutUrl); // Easy!
?>
<!-- More HTML below -->
I hope this helps. I know it's a lot to put together at one time.
Though it is not good practice. However still if you need this you can use following code in your controller
App::uses('HtmlHelper', 'View/Helper');
$yourTmpHtmlHelper = new HtmlHelper(new View());
$url=$yourTmpHtmlHelper->link(
'',
'http://www.example.com/',
['class' => 'button', 'target' => '_blank']
);
This should work for cakephp 2.*
Thanks

Use a widget in a statically-called method

Normally a widget is used by calling CController::widget() on an instance of CController, typically $this in a view.
But if I'm writing a static method, a helper, say, then I don't have access to an instance of CController. So how do I use a widget?
Let's say further that this helper method is invoked in the eval()’ed expression in a CDataColumn's value property. That poor expression has almost no context at all. How should the helper use a widget?
EDIT: Code example
As requested, a view example:
$this->widget('zii.widgets.grid.CGridView', array(
'dataProvider' => $model->search(),
'columns' => array(
array(
'name' => 'attrName',
'value' => '--USE WIDGET HERE--',
),
)
));
This answer doesn't answer the question in general but in the specific case—how to access the controller and use a widget in the context of the evaluated expression of CDataColumn::$value—you can use this:
$this->widget('zii.widgets.grid.CGridView', array(
'dataProvider' => $model->search(),
'columns' => array(
array(
'name' => 'attrName',
'value' => function ($data, $row, $column) {
$controller = $column->grid->owner;
$controller->widget(/* ... etc ... */);
},
),
)
));
The trick was discovering that CDataColumn::renderDataCellContent() uses CComponent::evaluateExpression(), which injects the component instance into the callback as the last parameter. In this case that omponent is the CDataColumn, which references the controller as shown.
I don't like writing PHP expressions as string literals so I'm pleased to find this option.
A comment on http://www.yiiframework.com/doc/api/1.1/CDataColumn#value-detail shows another way to us a widget in a column value that I haven't tried.
This one is working solution for calling widgets in static methods in Yii
Yii::app()->controller->widget('widget');
There's no direct way to call a widget out of controller because you shouldn't do so. It's all about MVC. Widgets are only needed and/or useful in views, and views are only accessed via controllers. That's the theory.
I guess you're approaching the problem mistakenly. A proper, MVC-friendly way to do what your're trying to do involves using renderPartial(). You know: you a have certain content and you want to decorate it (in your case you want to imbibe it inside a widget, right?) before displaying it to final user; so, from the view, you call renderPartial(). It will send your data to a file where it will properly decorated. renderPartial() returns the content properly formatted and now you can display it in the view.
Unfortunately, in your particular case, you're working with grid view (right?) and, at least from my point of view, it makes the things a bit harder. In order to decorate content for a CGridColumn-subclass element (like CDataColumn), you need to override the renderDataCellContent() method. Check it out here: http://www.yiiframework.com/doc/api/1.1/CDataColumn#renderDataCellContent-detail

Why Are My CakePHP AROs Not Being Created?

I followed the CakePHP Cookbook's simple ACL application tutorial and for a while all way fine and dandy. When I created a user, my AROs were automagically created too, and without too much effort I was able to give everyone permissions for the correct actions.
My application has become more complex now though. When I create a "Realtor", I create a user for them in the Realtor model's afterSave function, like so:
App::import( 'Component', 'Auth' );
$this->Auth = new AuthComponent();
$this->User->create();
$this->User->set(array(
'username' => $this->data['Realtor']['email'],
'password' => $this->Auth->password($this->data['Realtor']['password']),
'usergroup_id' => 2,
'realtor_num' => $this->id
));
if ($this->User->save()) {
$this->save(array('user_id'=>$this->User->id));
} else {
//error
}
Unfortunately, while this is successfully creating users, and the data all seems to match up with my expectations, I'm seemingly no longer getting AROs.
My Usergroup model contains the line
var $actsAs = array('Acl' => array('type' => 'requester'));
Beyond that, I have no idea how I would persuade my application to generate an ARO.
Is there anything I could have forgotten, that would help me get my ACL back on track?
EDIT:
I had this in the User model's afterSave which seems to have been causing various kinds of trouble:
function afterSave($created) {
if (!$created) {
$parent = $this->parentNode();
$parent = $this->node($parent);
$node = $this->node();
$aro = $node[0];
$aro['Aro']['parent_id'] = $parent[0]['Aro']['id'];
$this->Aro->save($aro);
}
}
(courtesy of this article: http://mark-story.com/posts/view/auth-and-acl-automatically-updating-user-aros) I don't know if that would have been fouling up my ARO creation somehow... probably teach me to add in random code snippets without fully understanding what they're doing, at the very least!
Ok I' m newbie
I can't understand your problem but
now I use Acl component with alaxos acl plugin
I try to understand of modified tree traversal algorithm
and set basic data for aro,aco,aro_aco,group table
and some requirement of plugin
I suggest you to use this