forcing auto-increment id in sonata admin custom clone action - mysql

I'm making a clone action in sonata admin--following the recommendations of Sonata docs:
<?php // src/Acme/DemoBundle/Controller/CRUDController.php
namespace Acme\DemoBundle\Controller;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Sonata\AdminBundle\Controller\CRUDController as Controller;
use Symfony\Component\HttpFoundation\RedirectResponse;
class CRUDController extends Controller
{
public function cloneAction()
{
$id = $this->get('request')->get($this->admin->getIdParameter());
$object = $this->admin->getObject($id);
if (!$object) {
throw new NotFoundHttpException(sprintf('unable to find the object with id : %s', $id));
}
$clonedObject = clone $object;
$clonedObject->setName($object->getName()." (Clone)");
$this->admin->create($clonedObject);
$this->addFlash('sonata_flash_success', 'Cloned successfully');
return new RedirectResponse($this->admin->generateUrl('list'));
}
}
after setting an id on the $clonedobject I get a DBAL exception. primary keys with same id not allowed--
I've tried setting a unique id
no id with the hope that auto increment in my schema would force ++
thanks for your help

Geert is right, setting the id to null is the way to go with Doctrine.
However, rather than having to implement a setId method in your object, you may as well override the __clone method as follows:
public function __clone()
{
parent::__clone();
$this->id = null;
$this->name .= " (Clone)";
}
See How to re-save the entity as another row in Doctrine 2

I think the easy solution is to set your id to null and doctrine will generate an id for you while creating the cloned object...
$clonedObject = clone $object;
$clonedObject->setId(NULL);
$clonedObject->setName($object->getName()." (Clone)");

Related

Symfony 4 - update JSON user roles

I have entity User with field roles:
/**
* #ORM\Column(name="roles", type="json")
*/
private $roles = [];
public function getRoles(): array
{
return $roles = $this->roles;
}
public function setRoles($roles): self
{
$this->roles[] = $roles;
return $this;
}
I want to add functionality to update user role from ROLE_ADMIN to ROLE_USER. I tried this in my controller but instead of replacing ROLE_ADMIN with ROLE_USER it inerts this: "ROLE_ADMIN""ROLE_USER". This is my controller:
public function updateuser(Request $request, $id) {
$entityManager = $this->getDoctrine()->getManager();
$usr = $this->getDoctrine()->getRepository(User::class)->find($id);
$usr->setRoles("ROLE_USER");
$entityManager->persist($usr);
$entityManager->flush();
First of all its best practice that every users has at least a default role like ROLE_USER. If you want to give users extra roles then you add them with beside ROLE_USER, like for example ROLE_ADMIN.
Now take a close look how arrays work in PHP. Let's take the code of you setter function setRoles.
When you write the value assignment like this $this->roles[] = $roles, then a value is added to the array . Thats why you in you code you have both roles inside you array now. The already existing ROLE_ADMIN and after the function call you added ROLE_USER.
When you write the value assignment like this $this->roles = $roles, then the whole array is overwritten with the new value.
Conclusion:
Thats how you code should look like if you want a simple solution:
public function setRoles(array $roles): self
{
$this->roles = $roles;
return $this;
}
Then you can call it like this:
$user->setRoles(['ROLE_USER']);
The setRoles function only accepts array.
So your code should change accordingly:
$usr->setRoles(["ROLE_USER"]);
Furthermore, if you want to store it as json, you can use json_encode:
$usr->setRoles(json_encode(["ROLE_USER"]));

Symfony 3.4 : how to log the history of user actions?

I want to store in my database all the user actions done about an entity.
For example, for 1 entity, I want to store :
Created by (= author)
Updated by
Date of creation
Date of update
I want to store the history of the actions of a user, not the last ones. I thought I could create a table with these columns :
log_id
user_id
entity_id
action (= "create" or "update" or something else)
date
And then, I could easily get the last update of my entity and display the date and the user who did it.
Is there a Symfony bundle to do this ? Should I use Monolog ?
I will do this for many entities and I'm not sure if this is the correct way to do...
Is it possible to create only one logs table to store each log about each entity ? It bothers me to create 1 logs table per entity.
Since Doctrine is event based, it's easy:
Either use an extension, like Gedmo Loggable
Or hook into Doctrine's events and log, using Monolog, everything that happens in your app.
Personally I would prefer option 2 since I'm a control maniac, it's a little more complex though. Personally I would also use Monolog so I could abstract away the way how and where the log entries are stored.
When you decide how to approach this and you will need any assistance along the way, please ask another question.
Good luck.
I don't know if that would fit what you need, but you could easily add a Listener to the symfony kernel to log every controller used.
Something like this :
class UserLogListener {
protected $authChecker;
protected $tokenStorage;
protected $entityManager;
public function __construct(TokenStorageInterface $tokenStorage, AuthorizationChecker $authChecker, EntityManager $entityManager)
{
$this->authChecker = $authChecker;
$this->tokenStorage = $tokenStorage;
$this->entityManager = $entityManager;
}
public function onKernelRequest(GetResponseEvent $event)
{
if( $this->tokenStorage->getToken() != null){
$user = $this->tokenStorage->getToken()->getUser();
$currentDate = new \Datetime();
$action = $event->getRequest()->attributes->get('_controller');
$method = $event->getRequest()->getMethod();
$userIp = $event->getRequest()->getClientIp();
$userLogRepository = $this->entityManager->getRepository(UserLog::class);
if($user instanceof User){
$userLog = new UserLog();
$userLog->setUser($user);
$userLog->setIp($userIp);
$userLog->setAction($action);
$userLog->setMethode($method);
$userLog->setDate($currentDate);
if($event->getRequest()->request && $methode=='POST'){
$userLog->setData(json_encode($event->getRequest()->request->all()));
}else{
$userLog->setData($event->getRequest()->getPathInfo());
}
$this->entityManager->persist($userLog);
$this->entityManager->flush();
}
}
}
}
What it does is add to the database (with an entity called UserLog) information about every page called. So you can know which action is made by knowing which controller is called, and you can also log the request data so you can find out what modification/creation the user did.

Laravel Schema Default Value Function

I want the default value for my Server model's sid to be the uniqid() function to be run every time. Something like this, for example
$table->string('sid')->default(uniqid);
How can I achieve this result?
You can use an event listener to set the sid attribute on your model. You can do this using an event listener, model observer, or just a closure function inside your model's boot function.
// app\Models\YourModel.php
/**
* Define model event callbacks.
*
* #return void
*/
public static function boot()
{
parent::boot();
static::creating(function ($model) {
$model->sid = uniqid();
});
}
Unfortunately no, MySQL requires constants for the default. So, the default value must be a constant, it cannot be a function or an expression.
Only way is to allow the fields nullable and add uniqid() while creating records on the database like this:
$table->string('sid')->nullable();
Now, When you add records set sid value to uinqid() value
If you have model named Table then
$record = new Table();
$record-> -----
--------
--------
$record->sid = uniqid();
$record->save();
This is the way you can achieve.
UPDATE
You can set default value in model as well like this:
protected $attributes = array(
'sid' => uniqid(),
);
Hope you understand.
i think this is the easiest way
$table->unique('sid')->index()

Set user permissions on each module in Yii2

I would like to set user permissions on each module.
Each module would have its table with the permissions. What is the most recommended way to do this?
Reason: My application has some optional modules for only a few clients.
UPDATE
Something like:
Table: mod_inventory_permission
id int
User_id int
Read_permission boolean
Write_permission boolean
Admin_permission boolean
You can use RBAC for it! you can set different modules in it and different permission for each module.
Yes you can do it by using Rbac which facilitate you to restrict user in same application to limited modules,controllers, or actions
You have to follow the following step i hope it will help you.
I suggest you to use the auth_ tables provided by yii2 for rbac
step 1: import all auth tables
step 2: Create different roles in auth_item tables with type = 1 and all permission with type = 2
Note
Please make sure you enter your permission in some specific pattern,i am using module/controller/action,
its up to you how you are going to implement it.
step 3: Create generic controller and extend all of your controller from this generic controller,
In your generic controller you have to check whether the user is allow to access the module,controller or action he/she want to access of not.
public function beforeAction($action) {
$module = Yii::$app->controller->module->id;
$controller = ucfirst(Yii::$app->controller->id);
$action = Yii::$app->controller->action->id;
if (Yii::$app->user->can($module)) {
if (Yii::$app->user->can($module . '/' . $controller)) {
return true;
}
if (Yii::$app->user->can($module . '/' . $controller . '/' . $action)) {
return true;
}
else {
throw new \yii\web\HttpException(403, 'You are not allowed to view this page');
}
} else {
throw new \yii\web\HttpException(403, 'You are not allowed to view this page');
}
}
The beforeAction function implement 3 layer authentication you can change it according to your requirements....
i hope it will help you

Table name having additional underscores added

I have an API that grabs data from a table, serialises the data and then sends back via the service. The code is written using CakePHP using MySQL.
When I pass in the table name (such as RX_Scaled), an error is being returned that the table r_x_scaled can't be found (which don't surprise me, the table name in the database is rx_scaled).
My Model/Table for rx_scaled is defined like this
class rx_scaleds extends Table
{
public function initialize(array $config)
{
parent::initialize($config);
$this->table('rx_scaled');
}
With the Model/Entity
class rx_scaled extends Entity
{
}
My service API is set like this within the APIController.php file
public function getData($tablename, $id="", $filter = "-", $order = "-", $take = 0)
{
$the_table = $tablename;
$this->autoRender = false;
$table = TableRegistry::get($tablename);
$data = null;
switch (strtolower($the_table))
{
case "rx_scaled":
$data = $table->find();
echo $data;
break;
}
(this is truncated)
The odd thing is that this error does not occur in all tables.
I'm obviously not doing something correctly, but I'm not sure what
You named your table object rx_scaleds but then you pass RX_Scaled to the getData action
cake try not finding a Table Object named RX_Scaled try to inflect the name of the mysql table: so using cake's conventions RX_Scaled is mapped to r_x_scaled
So what can you do?
Use cake conventions
Name you table RxScaledsTable
class RxScaledsTable extends Table
Name you entity RxScaled
class RxScaled extends Entity
and pass the string 'RxScaled' to your action