I'm hoping to add a custom query parameter that can be used in a hook to process some results.
I'd like to add $foo=bar to the request. I can whitelist $foo and it appears in the request, but the service is using an ORM so it tries to query the database for $foo=bar.
In a before hook, I can strip $foo from the params.query, but is there somewhere else in the context of the hook that I could stash the value of $foo so that I can act on it in an after hook?
I used to delete the params once the functionality is over here we added customer variable $paginate in before find hook.
find: [
(hook) => {
if (hook.params.query && hook.params.query.$paginate) {
hook.params.paginate =
hook.params.query.$paginate === 'false' ||
hook.params.query.$paginate === false;
delete hook.params.query.$paginate;
}
return hook;
}
],
Related
I've got two services in Feathers.
For the sake of example, let's call them:
TodoLists
TodoItems
TodoItems have a N:1 association to TodoLists, and I include the TodoItems model in a find hook of the TodoLists service.
Now - on my frontend I have a listener that listens for 'update' event on TodoLists.
What is the right way to get the 'update' event emitted for TodoLists when any TodoItem is updated?
Try watching on all TodoItems updates and filter by your TodoList id.
const currentTodoList = 1;
app.service('TodoItems').on('updated', (item) => {
if (item.todolist === currentTodoList){
// update ui
}
});
If you additionally want to optimize the traffic send by the backend to only send needed data, you could use some subscribe pattern (TodoListSubscription join feathers channel in create and leave in remove).
YII not updating
Tried to GOOGLE but no difference.
public function actionEdit($id)
{
$model = AddMix::findOne($id);
if($model->load(Yii::$app->request->post()) && $model->save()){
Yii::$app->session->setFlash('detailssubmited');
return $this->redirect(['mixes','id'=>$model->id]);
}
return $this->render('editmix',['model'=>$model]);
}
It does not update instead it returns same view with changed value but not in database
It fail the validation so do not enter into the if and re-render the form.
New data are shown because of $model->load(Yii::$app->request->post())
check:
$model->getErrors();
see getErrors documentation
I would like to create a command akeneo into my bundle who query my products like this.
So, after multiple test, i have always this error:
In ProductQueryBuilderFactory.php line 68:
Token cannot be null on the instantiation of the Product Query
Builder.
Here is my code :
$pqbFactory = $this->getApplication()->getKernel()->getContainer()->get('pim_catalog.query.product_query_builder_factory');
$pqb = $pqbFactory->create(['default_locale' => 'fr_FR', 'default_scope' => 'ecommerce']); // error
To complete Julien's answer, note that this error comes only if you are using the Enterprise Edition (EE). Indeed, in the EE, we decorate the normal product_query_builder_factory to apply permission.
If you don't want to apply permission (and don't use any token), you can use the pim_catalog.query.product_query_builder_factory_without_permission:
<?php
require __DIR__.'/vendor/autoload.php';
$kernel = new AppKernel('dev', true);
$kernel->boot();
$pqbFactory = $kernel->getContainer()->get('pim_catalog.query.product_query_builder_factory_without_permission');
$pqb = $pqbFactory->create(['default_locale' => 'fr_FR', 'default_scope' => 'ecommerce']); // you won't have any error
The PQB needs to have an authenticated user to be able to apply right filters on the results. To authenticate a user in your command you can take inspiration from the get product command. We simply take a --username argument and manually add it to the token storage.
$userManager = $this->getContainer()->get('pim_user.manager');
$user = $userManager->findUserByUsername($username);
if (null === $user) {
$output->writeln(sprintf('<error>Username "%s" is unknown<error>', $username));
return false;
}
$token = new UsernamePasswordToken($user, null, 'main', $user->getRoles());
$this->getTokenStorage()->setToken($token);
I'm considering using Loopback to build a RESTFull API, internal usage. I'm currently prototyping a small portion of the API to evaluate limitations and workload.
I have a huge constraint : I'm allowed to Create/Read/Update, but to Delete, I have update the DB entry to mark it as 'deleted' (boolean in the database). I'm not allowed to physically deleted the DB entry.
I have a PersistedModel, and some relation between object (dependencies, like one object child from another).
My question is : Is there a way to override the DELETE actions done in the background and input some custom code :
mark the object as "deleted" (like an UPDATE table SET deleted = 1 WHERE id = XXX)
manually CASCADE to dependent objects
while using the DELETE api call ?
Thanks fro your advice.
To overwrite delete method you can use the next code. Create a mixin based on it and attach for every required model
module.exports = function(Model) {
Model.removeById = Model.deleteById = Model.destroyById = function(id, options, cb) {
if (cb === undefined) {
if (typeof options === 'function') {
// destroyById(id, cb)
cb = options;
}
}
cb = cb || createPromiseCallback();
Model.update({id: id, {deleted: true}, options, cb})
return cb.promise;
};
}
Here is a basic add action:
public function add()
{
$article = $this->Articles->newEntity();
if ($this->request->is('post')) {
$article = $this->Articles->patchEntity($article, $this->request->data);
if ($this->Articles->save($article)) {
$this->Flash->success('Success.');
return $this->redirect(['action' => 'index']);
} else {
$this->Flash->error('Fail.');
}
}
$this->set(compact('article'));
}
If a malicious user injects at form a field with name id and set the value of this field to 2. Since the user do that the id value will be in $this->request->data so at $this->Articles->patchEntity($article, $this->request->data) this id will be patched and at $this->Articles->save($article) the record 2 will be updated instead of create a new record??
Depends.
Entity::$_accessible
If you baked your models, then this shouldn't happen, as the primary key field will not be included in the entities _accessible property, which defines the fields that can be mass assigned when creating/patching entities. (this behavior changed lately)
If you baked your models, then this shouldn't happen, as the primary key field(s) will be set to be non-assignable in the entities _accessible property, which means that these the fields cannot be set via mass assignment when creating/patching entities.
If you didn't baked your models and haven't defined the _accessible property, or added the primary key field to it, then yes, in case the posted data makes it to the patching mechanism, then that is what will happen, you'll be left with an UPDATE instead of an INSERT.
The Security component
The Security component will prevent form tampering, and reject requests with modified forms. If you'd use it, then the form data wouldn't make it to the add() method in the first place.
There's also the fieldList option
The fieldList option can be used when creating/patching entities in order to specifiy the fields that are allowed to be set on the entity. Sparse out the id field, and it cannot be injected anymore.
$article = $this->Articles->patchEntity($article, $this->request->data, [
'fieldList' => [
'title',
'body',
//...
]
]);
And finally, validation
Validation can prevent injections too, however that might be considered a little wonky. A custom rule that simply returns false would for example do it, you could create an additional validator, something like
public function validationAdd(Validator $validator) {
return
$this->validationDefault($validator)
->add('id', 'mustNotBePresent', ['rule' => function() {
return false;
}]);
}
which could then be used when patching the entity like
$article = $this->Articles->patchEntity($article, $this->request->data, [
'validate' => 'add'
]);