Item "AdminBundle\Entity\Prize:000000046fa222" has been successfully created - sonata

hi i want with sonata to have an item using 'name' label.
but not always the same.
i put this in admin class
public function toString($object) {
if (!is_object($object)) {
return '';
}
if (method_exists($object, '__toString') && null !== $object->__toString()) {
return (string) $object;
}
$cname = explode('\\', get_class($object));
return end($cname);
}
but it give always the same name. i want to have the label 'name' of each entity

If you want to get name of each entity, use:
public function __toString() {
return self::class;
}

You need to override the __toString() magic method in your entity class
public function __toString(){
return $this->name;
}

Related

Yii2 Rest Controller and public variable

I have made a REST controller with Yii2 framework. When I try to retrieve a record from my database through an ActiveRecord model, JsonFormatter give me only real attributes. How can configure JsonFormatter to give me also public variable?
This is my code:
Controller
class MyController extends yii\rest\ActiveController
{
...
public function actionView($id)
{
$struct = \common\models\Struct::find()->where(['id' => '285'])->One();
if ($struct) {
return $struct;
}
return false;
}
}
Model
/**
* property string $id;
* property string $name;
*/
class Struct extends \yii\db\ActiveRecord
{
public $test;
...
public function afterFind()
{
parent::afterFind();
$this->test = 'ok';
}
}
result of request
{"id":1,"name": "ciccio"}
but if I print variable with print_r(), I have all object
\app\models\Struct object
(
[test] => ok
[_attributes:yii\db\BaseActiveRecord:private] => Array
(
[id] => 1
[name] => ciccio
)
)
How can I get the variable test property without add an empty field on my database table?
You can override the ActiveRecord::fields() method to add the custom field that is declared as the public property of the class. The fields() method returns the names of the columns whose values have been populated into this record.
Looking at your code you are trying to set the test property inside the afterFind() and want that value to be reflected against all rows when you call the Model::find() method. If that is correct then add the following inside your model:
public function fields() {
$fields = parent::fields();
$fields['test'] = 'test';
return $fields;
}
Now when you call the \common\models\Struct::find() it will return
{"id":1,"name": "ciccio","test":"ok"}
Try this:
keep all you showed and then Override getAttributes
public function getAttributes($names = null, $except = [])
{
return array_merge(['test'=>$this->test], parent::getAttributes($names, $except));
}
and in your controller isted of return like this: return $struct;
do it like this: return $struct->attributes;

Laravel 5.3 : eager load with many to many relationship

I'm trying to use eloquent to retrieve 5 last messages and display them on the dashboard.
The problem is, I need to get those messages depending on the user->role. But the message is linked to an update log. This update log is use to dispatch every dashboard message, sms to notify and email.
There is how it work :
User
public function role()
{
return $this->belongsTo(Role::class);
}
Role
public function updatelogs()
{
return $this->belongsToMany(Updatelog::class, 'role_updatelog');
}
public function users()
{
return $this->hasMany(User::class);
}
Updatelog
public function roles()
{
return $this->belongsToMany(Role::class, 'role_updatelog');
}
public function dashboard_message()
{
return $this->hasOne(DashboardMessage::class);
}
DashboardMessage
public function updatelog()
{
return $this->belongsTo(Updatelog::class);
}
There is what I tried:
$dashmessages = DashboardMessage::with(array('updatelog' => function($q) use($user) {
$q->with(array('roles' => function($q2) use($user) {
$q2->whereHas($user->role_id);
}));
$q->whereHas('institution');
}))->with('updatelog.institution.rate_grids')->orderBy('updated_at', 'DESC')->take(5)->get();
I'm getting the last 5 DashboardMessages without the role constraint. What am I doing wrong?
EDIT---------------------------------------------------
I just tried something else and it work perfectly:
$updatelog = Updatelog::whereHas('roles', function ($query) use($user) {
$query->where('role_id', $user->role_id);
})
->whereHas('dashboard_message')
->with('dashboard_message')
->whereHas('institution')
->with('institution')
->with('rate_grid')
->take(5)->get();

Laravel redirect to post method

To stay basic I would like to create a bookmark app
I have a simple bookmarklet
javascript:location.href='http://zas.dev/add?url='+encodeURIComponent(location.href)
I created a rest controller
<?php
use zas\Repositories\DbLinkRepository;
class LinksController extends BaseController {
protected $link;
function __construct(DbLinkRepository $link) {
$this->link=$link;
// ...
//$this->beforeFilter('auth.basic', array('except' => array('index', 'show', 'store')));
// ...
}
public function index()
{
//return Redirect::to('home');
}
public function create()
{
}
public function store()
{
return 'hello';
//$this->link->addLink(Input::get('url'));
//return Redirect::to(Input::get('url'));
}
public function show($id)
{
//$url = $this->link->getUrl($id);
//return Redirect::to($url);
}
public function edit($id)
{
}
public function update($id){
}
public function destroy($id){
}
}
in the routes.php, I created a ressource
Route::resource('links','LinksController');
and as I want to redirect /add to the store method I added
Route::get('/add',function(){
return Redirect::action('LinksController#store');
});
but it never display the hello message, in place it redirects me to
http://zas.dev/links
I also tried with
return Redirect::route('links.store');
without much success
thanks for your help
Ok I now get what you are trying to do. This will work:
Route::get('add', 'LinksController#store');
Remove:
Route::resource('links','LinksController');
and remove:
Route::get('/add',function(){
return Redirect::action('LinksController#store');
});
Sorry it took so long!
The problem is that once you Redirect::, you loose all the Input values, so you should manually give them to your controller when you do the redirect, like so :
Redirect::route('links.store', ["url" => Input::get("url")]);
Finally add an $url parameter to your store method to receive the value we give it in the previous method, like this :
public function store($url) {
$this->link->addLink($url);
return Redirect::to($url);
}

Zend ACL Dynamic Assertion

I want to restrict my users to edit/delete only the comments which they added. I found an example on youtube by a guy named intergral30 and followed his instruction. And now my admin account has the possibility to edit/delete everything, but my user has no access to his own comment.
Here's the code:
Resource
class Application_Model_CommentResource implements Zend_Acl_Resource_Interface{
public $ownerId = null;
public $resourceId = 'comment';
public function getResourceId() {
return $this->resourceId;
}
}
Role
class Application_Model_UserRole implements Zend_Acl_Role_Interface{
public $role = 'guest';
public $id = null;
public function __construct(){
$auth = Zend_Auth::getInstance();
$identity = $auth->getStorage()->read();
$this->id = $identity->id;
$this->role = $identity->role;
}
public function getRoleId(){
return $this->role;
}
}
Assertion
class Application_Model_CommentAssertion implements Zend_Acl_Assert_Interface
{
public function assert(Zend_Acl $acl, Zend_Acl_Role_Interface $user=null,
Zend_Acl_Resource_Interface $comment=null, $privilege=null){
// if role is admin, he can always edit a comment
if ($user->getRoleId() == 'admin') {
return true;
}
if ($user->id != null && $comment->ownerId == $user->id){
return true;
} else {
return false;
}
}
}
In my ACL I have a function named setDynemicPermissions, which is called in an access check plugin's preDispatch method.
public function setDynamicPermissions() {
$this->addResource('comment');
$this->addResource('post');
$this->allow('user', 'comment', 'modify', new Application_Model_CommentAssertion());
$this->allow('admin', 'post', 'modify', new Application_Model_PostAssertion());
}
public function preDispatch(Zend_Controller_Request_Abstract $request)
{
$this->_acl->setDynamicPermissions();
}
And I'm calling the ACL-s isAllowed method from my comment model where I return a list of comment objects.
public function getComments($id){
//loading comments from the DB
$userRole = new Application_Model_UserRole();
$commentResource = new Application_Model_CommentResource();
$comments = array();
foreach ($res as $comment) {
$commentResource->ownerId = $comment[userId];
$commentObj = new Application_Model_Comment();
$commentObj->setId($comment[id]);
//setting the data
$commentObj->setLink('');
if (Zend_Registry::get('acl')->isAllowed($userRole->getRoleId(), $commentResource->getResourceId(), 'modify')) {
$commentObj->setLink('Edit'.'Delete');
}
$comments[$comment[id]] = $commentObj;
}
}
Can anyone tell me what have I done wrong?
Or what should I use if I want to give my admins the right to start a post and other users the right to comment on them. Each user should have the chance to edit or delete his own comment and an admin should have all rights.
You seem to be using the dynamic assertions in a wrong manner, as you are still passing the roleId to isAllowed().
What these dynamic assertions really do, is take a complete object and work with it. Zend will determine which rule has to be used by calling getResourceId() and getRoleId() on your objects.
So all you have to do is pass your objects instead of the strings to isAllowed():
public function getComments($id){
//loading comments from the DB
$userRole = new Application_Model_UserRole();
$commentResource = new Application_Model_CommentResource();
$comments = array();
foreach ($res as $comment) {
$commentResource->ownerId = $comment[userId];
$commentObj = new Application_Model_Comment();
$commentObj->setId($comment[id]);
//setting the data
$commentObj->setLink('');
// This line includes the changes
if (Zend_Registry::get('acl')->isAllowed($userRole, $commentResource, 'modify')) {
$commentObj->setLink('Edit'.'Delete');
}
$comments[$comment[id]] = $commentObj;
}
}
But in can be done better
You would not have to implement a total new Application_Model_CommentResource, but instead you can use your actual Application_Model_Comment like this:
// we are using your normal Comment class here
class Application_Model_Comment implements Zend_Acl_Resource_Interface {
public $resourceId = 'comment';
public function getResourceId() {
return $this->resourceId;
}
// all other methods you have implemented
// I think there is something like this among them
public function getOwnerId() {
return $this->ownerId;
}
}
Assertion would then use this object and retrieve the owner to compare it with the actually logged in person:
class Application_Model_CommentAssertion implements Zend_Acl_Assert_Interface {
public function assert(Zend_Acl $acl, Zend_Acl_Role_Interface $user=null,
Zend_Acl_Resource_Interface $comment=null, $privilege=null){
// if role is admin, he can always edit a comment
if ($user->getRoleId() == 'admin') {
return true;
}
// using the method now instead of ->ownerId, but this totally depends
// on how one can get the owner in Application_Model_Comment
if ($user->id != null && $comment->getOwnerId() == $user->id){
return true;
} else {
return false;
}
}
And the usage is like this:
public function getComments($id) {
//loading comments from the DB
$userRole = new Application_Model_UserRole();
$comments = array();
foreach ($res as $comment) {
$commentObj = new Application_Model_Comment();
$commentObj->setId($comment[id]);
//setting the data
$commentObj->setLink('');
// no $commentResource anymore, just pure $comment
if (Zend_Registry::get('acl')->isAllowed($userRole, $comment, 'modify')) {
$commentObj->setLink('Edit'.'Delete');
}
$comments[$comment[id]] = $commentObj;
}
}

accessing request parameters from inside validator

Is there a proper way to access other form fields from inside a validator?
Is there another solution than:
context.getViewRoot().findComponent("formid:exampleField:example")?
f.e I want to validate a city field inside a custom validator and checking if country is US.
Re-read your question and I am going to interpret it as this:
"You would like to write a custom validator that checks that if a city field exists, the country field is equal to 'US'"
So, I would look at going about this in the following fashion:
First create a validator interface:
#Documented
#ValidatorClass(value=CountryEqualsUSValidator.class)
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
public #interface CountryEqualsUS {
String message() default "The country should be US for the city provided";
}
Then create a validator class:
public class CountryEqualsUSValidator implements Validator<CountryEqualsUS> {
public void initialize(CountryEqualsUS arg0) {
}
public boolean isValid(Object value) {
if(value != null && value instanceof YourBeanClass) {
YourBeanClass yourBeanClass = (YourBeanClass) value;
if(/*some test logic here*/) {
return true;
else {
return false;
}
}
return false;
}
}
Then on the class that you want to validate:
#CountryEqualsUS
public class YourBeanClass {
...
}
Then, finally, on your controller/action class, when the form is submitted, the city is a value for which you want to check the country, add this method and call it:
public boolean doValidation(YourBeanClass yourBeanClass) {
ClassValidator requestValidator = new ClassValidator(yourBeanClass.getClass());
InvalidValue[] validationMessages = requestValidator.getInvalidValues(yourBeanClass);
if (validationMessages != null && validationMessages.length > 0) {
for (int i = 0; i < validationMessages.length; i++) {
//Add a validation message to be displayed to the user
}
return false;
}
return true;
}