I have an addAction like this:
public function addAction(Request $request)
{
$object = new Object();
$object->setAttrib('foo');
if($object->isValid())
{
$session->set('_object', $object);
return $this->redirect('confirmAction');
}
}
and in the confirmAction:
public function confirmAction($confirm = 'not_confirmed')
{
if($confirm == 'confirm')
{
$object = $session->get('_object');
if($object->isValid())
{
$entityManager->persist($object);
$session->remove('_object');
return $this->redirect('listAction');
}
}
$this->renderTemplate('with confirm link');
}
I dont like the $session->set part. What is the best practice for this create/confirm/persist things?
Well, you should ask yourself whether or not you want to use JavaScript. A confirmation box would be in my opinion the most sensible solution, since the client doesn't make another round-trip to the server.
If for some reason you don't want to use JavaScript, your method is the way to go. Instead of using $session->set('...');, you could use $session->setFlash('...'), which will store the value in the session for only one request and deletes it afterward.
If a user decides not to confirm the action, you could use $session->setFlash('...') yet again to display the previous state of a form. Using this method is better, because you won't be having any leftover session values just hanging there.
Related
good day, I am using Tucker-Eric/EloquentFilter Laravel.
I want to filter it by relationship using Models
I want to automate it, instead of using the following:
public function users($users)
{
// dd($users);
return $this->r('users', $users);
}
public function user($user)
{
// dd($user);
return $this->r('user', $user);
}
public function owner($owner)
{
// dd($owner);
return $this->r('owner', $owner);
}
I want to make it one function that based on the relationship
so that I want to add another relationship on the model I don't need anymore to add another function.
Thanks!
We specifically stayed away from the type of implicit functionality you're looking for and opted for explicit filter methods to avoid security issues if/when new relations/properties were added to a model they wouldn't implicitly be available to filter against.
With that, what you're looking for isn't recommended because of the security concerns above but it can still exist if you implement it.
It sounds like the setup method would be the best place to implement it since it would be called first every time ->filter() is called.
public function setup()
{
foreach($this->input() as $key => $val) {
if($this->getModel()->$key() instanceof \Illuminate\Database\Eloquent\Relations\Relation) {
// Your logic here
}
}
}
To give you a brief view: I am trying to make redirect based on conditions. If request satisfy conditions of given destination you will get redirect to certain destination.
I have Destination model which has many conditions (Condition model). I have many Conditions which extends basic Condition model like DateCondition, LocationCondition etc (made by polimorphic relation). Each of condition type should has 'service' which tells if given condition match do the request. Example DateCondition should has own DateConditionMatcher which implements ConditionMatcherInterface.
(just public function match($condition, $request)).
I would like to write it with Open Closed principle from SOLID. Firstly I thought to add getMatcher() function straight to condition model and return different ConditionMatcher for each condition type, but some of ConditionMatchers need some other services passed in contructor, so it would force me to inject them also in Condition models which is bad pratice.
Maybe using Contextual binding in ServiceProvider could resolve this but how?
I have no idea how to couple Model to to the right one ConditionMatcher to then use it freely like this:
foreach ($destination->conditions as $condition){
$isMatched = $this->conditionMatcher->match($condition, $request);
}
To always have correct ConditionMatcher under $this->conditionMatcher.
I hope someone understood my not very clear message.
I had an idea overnight to make service which keeps all the matchers. The only downside to this solution is injecting every matcher.
class ConditionResolver implements ConditionResolverInterface
{
/** #var ConditionMatcherInterface[] */
private $conditionMatchers = [];
public function __construct(
DateConditionMatcher $dateConditionMatcher,
TimeConditionMatcher $timeConditionMatcher,
LocationConditionMatcher $locationConditionMatcher
) {
$this->conditionMatchers[DateCondition::class] = $dateConditionMatcher;
$this->conditionMatchers[TimeCondition::class] = $timeConditionMatcher;
$this->conditionMatchers[LocationCondition::class] = $locationConditionMatcher;
}
}
so now I am able to use correct matcher to given condition in this way(simplified):
foreach ($model->conditions as $condition)
{
$this->conditionMatchers[get_class($condition)]->match($condition, $request);
}
It allows me to inject various of services into that matchers in AppServiceProvider.
$this->app->singleton(LocationServiceInterface::class, function($app){
return new LocationService();
});
$this->app->singleton(DateConditionMatcher::class, function($app){
return new DateConditionMatcher();
});
$this->app->singleton(TimeConditionMatcher::class, function($app){
return new TimeConditionMatcher();
});
$this->app->singleton(LocationConditionMatcher::class, function($app){
return new LocationConditionMatcher($app->make(LocationServiceInterface::class));
});
Overall I think I miessed something and it would be done in more elegant way, but for now I treat it as an answer. If you have better solution, please share :)
I have a question about obtaining parameters from Request object.
What is the difference between
$name = $request->name;
OR
$name = $request->input("name");
They show the same behavior. I am asking that from the typing perspective, it is faster to utilize #1 method. But I don't know the difference. Is #1 prone to SQL injections?
Basically, the first case is just a syntactic sugar for the second. In Laravel, Request implements __get magic function to access its internal properties.
public function all()
{
return array_replace_recursive($this->input(), $this->allFiles());
}
public function __get($key)
{
$all = $this->all();
if (array_key_exists($key, $all)) {
return $all[$key];
} else {
return $this->route($key);
}
}
In the first case, if any files were uploaded, Laravel first looks for a property amongst them. And if there is no such param in files or in input, in your first snippet, Laravel also looks for a value amongst route parameters:
To protect your code against SQL injections, you have to use prepared statements/query builder/ORM. You should not escape/change input, so both these functions don't protect you against SQL injections.
I want to pass a property of my model to the template, so I presume I need a serializeData function, I tried this
serializeData:function(){
return this.model.toJSON().extend({_schema:this.model.schema});
}
but it complained about not being able to extend the output of toJSON. This must be a standard trick, stick some value from the prototype into the serialised form so the template can get it's hands on it.
Use templateHelpers for this use case – serializeData works better for replacing the model attributes entirely, or scoping them down.
templateHelpers: function()
{
return { _schema: this.model.schema };
}
Harladson's answers is the best, but in case someone else comes looking different approach you can do this:
serializeData:function(){
var data = this.model.toJSON();
data._schema = this.model.schema;
return data;
}
Where and how I am overriding the save method in Joomla 3.0 custom component ?
Current situation:
Custom administrator component.
I have a list view that displays all people stored in table.
Clicking on one entry I get to the detailed view where a form is loaded and it's fields can be edited.
On save, the values are stored in the database. This all works fine.However, ....
When hitting save I wish to modify a field before storing it into the database. How do I override the save function and where? I have been searching this forum and googled quiet a bit to find ways to implement this. Anyone who give me a simple example or point me into the right direction ?
Thanks.
Just adding this for anyone who wants to know the answer to the question itself - this works if you explicitly wish to override the save function. However, look at the actual solution of how to manipulate values!
You override it in the controller, like this:
/**
* save a record (and redirect to main page)
* #return void
*/
function save()
{
$model = $this->getModel('hello');
if ($model->store()) {
$msg = JText::_( 'Greeting Saved!' );
} else {
$msg = JText::_( 'Error Saving Greeting' );
}
// Check the table in so it can be edited.... we are done with it anyway
$link = 'index.php?option=com_hello';
$this->setRedirect($link, $msg);
}
More details here: Joomla Docs - Adding Backend Actions
The prepareTable in the model (as mentioned above) is intended for that (prepare and sanitise the table prior to saving). In case you want to us the ID, though, you should consider using the postSaveHook in the controller:
protected function postSaveHook($model, $validData) {
$item = $model->getItem();
$itemid = $item->get('id');
}
The postSaveHook is called after save is done, thus allowing for newly inserted ID's to be used.
You can use the prepareTable function in the model file (administrator/components/yourComponent/models/yourComponent.php)
protected function prepareTable($table)
{
$table->fieldname = newvalue;
}