public function aroundGetData(\Magento\Catalog\Ui\DataProvider\Product\ProductDataProvider $subject, callable $proceed)
{
// what is do here
}
it feels that did not dive deep enough,
For global use easies way is to use addField or even alter SQL to add data from some related table.
public function aroundGetData(\Magento\Catalog\Ui\DataProvider\Product\ProductDataProvider $subject, callable $proceed)
{
$subject->addField('field', 'alias'); // alias is optional
$collection = $subject->getCollection(); // Here you have access to all public methods of collection.
$select = $collection->getSelect(); // You can do whatever you want with Zend_DB_Select here
return $proceed();
}
DataProvider has addField and addFilter method uses Product Collection under the hood.
Related
I want to have _id in the database but want to output id when doing a query.
How can I achieve it?
You can try this (using an Accessor) :
Model
public function getIdAttribute() {
return $this->attributes['_id'];
}
Controller test
$user = User::find(1);
// this will call getIdAttribute which will return the `_id`
dd($user->id);
You can also override toArray() method if you want to show it :
Model
// ..
// getIdAttribute()
// ..
public function toArray()
{
$array = parent::toArray();
$array['id'] = $this->id;
unset($array['_id']);
return $array;
}
Controller Test
$user = User::find(1);
dd($user->toArray());
Another way to do this is using Transformers (http://fractal.thephpleague.com/transformers/). There is a service provider for Laravel here (https://github.com/gathercontent/laravel-fractal).
It will do that in a elegant way :)
Of course, if you need to do only with "id" field, I'll do like zorx told:
public function getIdAttribute() {
return $this->attributes['_id'];
}
But you'll probably put that in some BaseModel or abstractModel class, a parent for you models who need this.
I'm trying to create rest api for my application to get the data in my android app. This is my controller
<?php
namespace api\modules\v1\controllers;
use yii\rest\ActiveController;
use yii\filters\auth\QueryParamAuth;
/**
* Tk103 Controller API
*/
class Tk103Controller extends ActiveController
{
public $modelClass = 'api\modules\v1\models\Tk103CurrentLocation';
public function behaviors()
{
$behaviors = parent::behaviors();
$behaviors['authenticator'] = [
'class' => QueryParamAuth::className(),
];
return $behaviors;
}
}
I added access_token column in my user table, implemented findIdentityByAccessToken() in User Model and calling this URL
http://localhost:7872/api/v1/tk103s?access-token=abcd
This is working great and returning data if and only if access_token matches with any single user in the table.
I checked QueryParamAuth class and found that QueryParamAuth::authenticate() returns $identity after successful authentication.
Currently this url is returning whole data of my table.
What I want is(after authentication):
Get user id/username of the requester.
Based on that id/username, the data related to him as per relations of tables in db. (currently whole rows are being returned but I want only few that are matching with the current requester/user)
I tried but didn't getting any clue to catch returned $identity of user after authentication.
And I know it is possible too to make this work. Help me out folks to create magic.
Get user id/username of the requester.
That user instance you did return within the findIdentityByAccessToken method should be accessible any where inside your app within Yii::$app->user->identity. And should hold all the attributes retreived from DB. here is a quick example of using it to check access within the checkAccess method of the ActiveController class:
public function checkAccess($action, $model = null, $params = [])
{
// only an image owner can request the related 'delete' or 'update' actions
if ($action === 'update' or $action === 'delete') {
if ($model->user_id !== \Yii::$app->user->identity->id)
throw new \yii\web\ForbiddenHttpException('You can only '.$action.' images that you\'ve added.');
}
}
Note that the checkAccess is by default an empty method that is manually called inside all the built-in actions in ActiveController. the Idea is to pass the action ID and the model instance to it just after retrieving it from DB and before modifying it so we can do extra checks. If you just need to perform checks by actions ID then yii\filters\AccessControl may be enough but inside checkAccess you are expecting to also get the model instance itself so it is important to note that when building your own actions or overriding existing onces. be sure to manually invoke it the same way it is done in UpdateAction.php or DeleteAction.php.
whole rows are being returned but I want only few .. matching with .. current requester/user
It depends on how your data is structured. You can override ActiveController's actions to filter results before outputting them, it can be handled in the related SearchModel class if you are using one or it can be handled in model. A quick tip may be by simply overriding the find method inside your model:
public static function find()
{
return parent::find()->where(['user_id' => Yii::$app->user->getId()]); // or Yii::$app->user->identity->id
}
Note that this works only when using ActiveRecord. Which means when using this:
$images = Image::find()->all();
The find method we just overriden will be filtered by default by always including that where condition before generating the DB query. Also note the default built-in actions in ActiveController are using ActiveRecords but if you are using actions where you are constructing the SQL queries using the Query Builder then you should manually do the filtering.
The same can be done if using ActiveQuery (maybe better explained here) by doing this:
public static function find()
{
$query = new \app\models\Image(get_called_class());
return $query->andWhere(['user_id' => Yii::$app->user->getId()]);
}
Say I have tables A, B in MySQL and Doctrine entity classes with the same names. Those entities are managed by Doctrine and are basically created according to Symfony/Doctrine docs.
Now I want to create entity C with columns: x, y. Whenever this entity is created or updated, I want to set the column values:
x: select count(*) from A where (some condition)
y: select sum(y) from B where (other condition)
pull some other data from A or B and store it as column value for C.
I want to do this in PHP and not use mysql triggers. I can't achieve from inside the Entity classes, because they don't have access to entity manager. I don't want to do this in the controller, as I want insert/update operations to be standardized, and I will need to do it from multiple controllers, and I generally don't think the controller is a good place for logic like this.
So I need some kind of class which manages entity C.
My question is: How do I call this manager class and where do I place it in Symfony? I am pretty sure this is a common need in Symfony (to access multiple entities while creating another entity), but I don't know how it is called and if there is a standard practice with them.
you can define service in app/config/services.yml and pass Entity manager as argument
services:
app.service.some_service:
class: AppBundle\Service\SomeService
arguments: ["#doctrine.orm.default_entity_manager"]
place your logic inside service
use Doctrine\ORM\EntityManagerInterface;
use AppBundle\Entity\SomeEntity;
class SomeService
{
/**
* #var EntityManagerInterface
*/
protected $entityManager;
public function __construct(EntityManagerInterface $entityManager) {
$this->entityManager = $entityManager;
}
public function getSomeEntity($id) {
$entity = $this->entityManager->getRepository(SomeEntity::class);
// do some work, return result..
}
}
call it from controller
$someService = $this->get('app.service.some_service');
$someService->getSomeEntity($id);
:)
I think you should create a Doctrine Event Subscriber as described in the documentation
I'll try to explain the basics.
1) Declare the service
services:
c_entity_counter_subscriber:
class: AppBundle\EventListener\CounterSubscriber
tags:
- { name: doctrine.event_subscriber, connection: default }
2) In the Subscriber count A and B properties
namespace AppBundle\EventListener;
use Doctrine\Common\EventSubscriber;
use Doctrine\ORM\Event\LifecycleEventArgs;
use AppBundle\Entity\A;
use AppBundle\Entity\B;
use AppBundle\Entity\C;
class CounterSubscriber implements EventSubscriber
{
public function getSubscribedEvents()
{
return array(
'postPersist',
'postUpdate',
);
}
public function postUpdate(LifecycleEventArgs $args)
{
$this->count($args);
}
public function postPersist(LifecycleEventArgs $args)
{
$this->count($args);
}
public function count(LifecycleEventArgs $args)
{
$entity = $args->getEntity();
if (!$entity instanceof C) {
return;
}
$entityManager = $args->getEntityManager();
// ... count/sum entities from A/B classes using $entityManager and update $entity
}
}
I'm trying to dynamically generate my forms based on the user's permissions for that I have created a extension which adds listeners to forms and filters their fields accordingly.this works just fine However I'm having trouble with getting the typeName (returned from the getName method for classes which implement the FormTypeInterface) of each field (which is FormInterface).I've tried FormInterface::getName but that returns the field name that is given to the builder e.g: $builder->add('fieldName',new FooType()) when I call getName on a FormInterface that is constructed like this I get "fieldName".What I want is the returned value from FooType::getName.How can I do that?I have also checked FormInterface->getConfig->getName() but that also gave the same same Result.the code for the listener:
class FooListener implements EventSubscriberInterface{
public static function getSubscribedEvents()
{
//set low priority so it's run late
return array(
FormEvents::PRE_SET_DATA => array('removeForbiddenFields', -50),
);
}
public function removeForbiddenFields(FormEvent $event){
$form = $event->getForm();
$formName = $form->getName();/*what I want for this is to return the name of the
type of the form.e.g: for the field that is construced with the code below
it must return FooType::getName*/
$fields = $form->all();
if($fields){
$this->removeForbiddenFormFields($form, $formName, $fields);
}
}
}
class barType extends AbstractType{
public function buildForm(FormBuilderInterface $builder, array $options){
$builder->add('fieldName',new FooType());
}
....
}
For those of you using Symfony 3 this can now be done with:
$formClass = $form->getConfig()->getType()->getInnerType();
$formClass will be a stdClass representation of the class itself (not the instance of it though), and you can use get_class($formClass) to get a string for its FQCN, e.g. "App\Form\Type\SillyFormType".
I've not tested this on Symfony 4, though it'll likely be the same.
I found the answer.
$form->getConfig()->getType()->getName();
this will return a name returned from the FooType::getName through a ResolvedTypeDataCollectorProxy class.
From Symfony > 2.8 getName() is deprecated and removed.
You can now use:
$form->get('fieldName')->getConfig()->getInnerType()
To get specific FieldName Type.
not sure this is what you are looking for, this goes in the form FormName
public function __construct($permissions = null) {
$this->permissions = $permissions;
}
and this is how you create the form, while in buildForm you can use an if or some other logic
$myForm = $this->createForm(new FormName($user->getPermissions()));
I am implementing DAO pattern in my sample app and I have plain array that contains User(domain) fetched from UserMapper I want to use Zend_Paginator with array adapter, but it does not work it only works when I use Zend_DbTable adapter which I dont want to do because it defeats the purpose of DAO.
sample code below (Not Working)
$userMapper = new Application_Model_UserMapper();
$users = $userMapper->getUsers();
$paginator = Zend_Paginator::factory($users);
$paginator->setCurrentPageNumber($this->_getParam('page'));
$paginator->setItemCountPerPage(1);
$this->view->paginator = $paginator;
sample code below (Working)
$users = new Application_Model_DbTable_User();
$select = $users->fetchAll();
$paginator = Zend_Paginator::factory($select);
$paginator->setCurrentPageNumber($this->_getParam('page'));
$paginator->setItemCountPerPage(1);
$this->view->paginator = $paginator;
I was looking at the factory method and it takes 3 parameters
public static function factory($data, $adapter = self::INTERNAL_ADAPTER,
array $prefixPaths = null)
you may want to try
$paginator = Zend_Paginator::factory($users, 'Array');
at least this way if your data is somehow incorrect you should raise an exception.
I already solve my problem, in order for array containing plain PHP objects to be recognized by the partialLoop you need to implement a toArray() method in that class and return key value pair of the attributes
class Application_Model_User
{
private $id;
private $first_name;
private $last_name;
private $middle_name;
public function toArray()
{
return get_object_vars($this);
}
}