I'm starting to user Gate in Laravel 5.1, and I got this code from some where in the internet.
<?php
public function boot(GateContract $gate)
{
$this->registerPolicies($gate);
/**
* NOTE!!
* First time migration will fails, because permissions table doesn't exists.
*/
foreach($this->getPermissions() as $permission) {
$gate->define($permission->path, function($user) use ($permission) {
return $user->hasRole($permission->roles);
});
}
}
My question is, what is function($user) use ($permission) { in $gate->define($permission->path, function($user) use ($permission) { ??? Why is there use after function()?
If there're some references, I'd love to know/ read it.
It has been described in document of PHP.
Please refer to the example 3 of http://php.net/manual/en/functions.anonymous.php.
Closures may also inherit variables from the parent scope. Any such variables must be passed to the use language construct.
Your case is
$user->hasRole($permission->roles)
is necessary in order to use the variable of $permission.
Related
I wonder if there's a language sugar/SDK utility function in Dart that allows to protect a certain code from running more than once?
E.g.
void onUserLogin() {
...
runOnce(() {
handleInitialMessage();
});
...
}
I know I can add a global or class static boolean flag to check but it would be accessible in other functions of the same scope with a risk of accidental mixup in the future.
In C++ I could e.g. use a local static bool for this.
There is no built-in functionality to prevent code from running more than once. You need some kind of external state to know whether it actually did run.
You can't just remember whether the function itself has been seen before, because you use a function expression ("lambda") here, and every evaluation of that creates a new function object which is not even equal to other function objects created by the same expression.
So, you need something to represent the location of the call.
I guess you could hack up something using stack traces. I will not recommend that (very expensive for very little advantage).
So, I'd recommend something like:
class RunOnce {
bool _hasRun = false;
void call(void Function() function) {
if (_hasRun) return;
// Set after calling if you don't want a throw to count as a run.
_hasRun = true;
function();
}
}
...
static final _runOnce = RunOnce();
void onUserLogin() {
_runOnce(handleInitialMessage);
}
It's still just a static global that can be accidentally reused.
I have two questions today. This is detailed because too many other replies rely on assumptions and have not been detailed enough. I hope that this is detailed and will be able to help lots of developers.
1st. The code below points to the real question I have. How do you call a Service outside of the controller since the $this->get() method is inside of the controller only? This is not in any of the documentation or on KNP University's tutorial on Services.
2nd. From what I have read, according to some, not all, if you call to a Repository, from anywhere, it should automatically instantiate the Entity Repository. I don't think this is so. Tell me if I am right or wrong.
See the following below....
My Default Controller, it's straightforward call a class and let it do some work. As an example, I called it with a Service and a conventional OO method:
<?php
// src/AppBundle/Controller/DefaultController.php
// Here is where I am starting. There is a service
// and there is a conventional OO call.
// Both should invoke the same thing.
namespace AppBundle\Controller;
use AppBundle\Service;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
class DefaultController extends Controller
{
/**
* #Route("/", name="homepage")
*/
public function indexAction(Request $request)
{
// Step 1.... Do a little of this.
// Step 2.... Do some of that.
// Step 3.... Call another class to do some logic and it will
// eventually call a query...
// Invoking my service
$obj_via_service = $this->get('app.services.process_question');
$result1 = $obj_via_service->submitQuestion();
// Invoking via Namespace and Call
$obj_via_new = new Service\ProcessQuestion();
$result2 = $obj_via_new->submitQuestion();
dump($result1);
dump($result2);
die();
}
}
My Service.yml File.
# src/app/config/services.yml
parameters:
services:
app.services.process_question:
class: AppBundle\Service\ProcessQuestion
app.rep.geo_state:
class: AppBundle\Entity\GeoStateRepository
arguments: ['#doctrine.orm.entity_manager']
This is my class that is doing the work for me. I want to be able to call the second service ^^above^^ but I can't because I can't use $this->get() outside of the controller.
<?php
// src/AppBundle/Service/ProcessQuestion.php
namespace AppBundle\Service;
class ProcessQuestion
{
public function submitQuestion()
{
// Step 1.... Do this.
// Step 2.... Do that.
// Step 3.... Query for some data...
// Invoke my repository class via a Service Call....
// but I cannot do that because 'get' is a part of the
// controller...
$obj_via_service = $this->get('app.rep.geo_state');
**^^ ^^**
**^^ This is what won't work ^^**
$results = $obj_via_service->selectStates();
return $results;
}
}
My Repository Class... Keep in mind I cannot reach this class yet, but I am throwing it in here so that other new Symfony 3 developers can see this.
<?php
// src/AppBundle/Repository/GeoState.php
// My Repository Class where I want to do some queries...
namespace AppBundle\Repository;
use Doctrine\ORM\EntityRepository;
class GeoStateRepository extends EntityRepository
{
/**
* #Mapping\Column(type="string")
*/
private $em;
public function __construct(EntityManager $em)
{
$this->em = $em;
}
public function selectStates()
{
$sql = "SELECT * FROM geo_state";
return $this->getEntityManager()->createQuery($sql)->getResult();
}
}
Why is this so hard to find an example? Also, I have followed a bunch of the Symfony 2.x documentation and the nuances are hard to port into Symfony 3 sometimes.
I think Fabian re purposed too much of the docs for 2.x to go into 3.x and there is not any good examples on coding that is between the New Developer level and the Hard Core Developer level. If you are at Sensio and reading this, please keep in mind that there is a middle ground we need to cover and most of the screencasts that out there and much of the better documentation is not in English.
You should really read more about Dependency Injection.
Symfony is very good at this .
Regarding your question about using app.rep.geo_state service in the app.services.process_question service .
In Symfony/ DI terminology it's can be termed as injecting a service into another service .
The documentation on how to do this is very good.
this is how it can be done.
services:
app.services.process_question:
class: AppBundle\Service\ProcessQuestion
arguments: ['#app.rep.geo_state']
app.rep.geo_state:
class: AppBundle\Entity\GeoStateRepository
arguments: ['#doctrine.orm.entity_manager']
And in the class
<?php
// src/AppBundle/Service/ProcessQuestion.php
namespace AppBundle\Service;
use AppBundle\Entity\GeoStateRepository;
class ProcessQuestion
{
private $geoRepository;
public function __construct(GeoStateRepository $geoRepository)
{
$this->geoRepository = $geoRepository;
}
public function submitQuestion()
{
//now you can call $this->geoRepository
}
}
Also note that $this->get() is only a shortcut function provided by the Symfony base Controller class to access the container.
To know more about DI, you can read Fabian's excellent articles about this in his blog .
We need to be able to rollback a complex transaction in a service, without throwing an exception to the caller. My understanding is that the only way to achieve this is to use withTransaction.
The question is:
why do I have to call this on a domain object, such as Books.withTransaction
What if there is no relevant domain object, what is the consequence of picking a random one?
Below is more or less what I am trying to do. The use case is for withdrawing from an account and putting it onto a credit card. If the transfer fails, we want to rollback the transaction, but not the payment record log, which must be committed in a separate transaction (using RequiresNew). In any case, the service method must return a complex object, not an exception.
someService.groovy
Class SomeService {
#NotTransactional
SomeComplexObject someMethod() {
SomeDomainObject.withTransaction{ status ->
DomainObject ob1 = new DomainObject.save()
LogDomainObject ob2 = insertAndCommitLogInNewTransaction()
SomeComplexObject ob3 = someAction()
if (!ob3.worked) {
status.setRollbackOnly() // only rollback ob1, not ob2!
}
return ob3
}
}
}
The above is flawed - I assume "return ob3" wont return ob3 from the method, as its in a closure. Not sure how to communicate from inside a closure to outside it.
To your primary question: you can pick a random domain object if you want, it won't do any harm. Or, if you prefer, you can find the current session and open a transaction on that instead:
grailsApplication.sessionFactory.currentSession.withTransaction { /* Do the things */ }
Stylistically I don't have a preference here. Others might.
Not sure how to communicate from inside a closure to outside it.
In general this could be hard; withTransaction could in principle return anything it wants, no matter what its closure argument returns. But it turns out that withTransaction returns the value returned by its closure. Here, watch:
groovy> println(MyDomainObject.withTransaction { 2 + 2 })
4
By convention, all withFoo methods which take a closure should work this way, precisely so that you can do the thing you're trying to do.
I'm assuming this question was from a grails 2 application and this problem from 2015 has been fixed before now.
I can't find this in any of the grails 2 documentation, but services have a magic transactionStatus variable injected into their methods. (at least in grails 2.3.11)
You can just leave all the annotations off and use that injected variable.
Class SomeService {
SomeComplexObject someMethod() {
DomainObject ob1 = new DomainObject.save()
LogDomainObject ob2 = insertAndCommitLogInNewTransaction()
SomeComplexObject ob3 = someAction()
if (!ob3.worked) {
transactionStatus.setRollbackOnly() // transactionStatus is magically injected.
}
return ob3
}
}
This feature is in grails 2, but not documented. It is documented in grails 3.
https://docs.grails.org/latest/guide/services.html#declarativeTransactions
search for transactionStatus.
I'm having a weird issue with the configureMetadataStore.
My model:
class SourceMaterial {
List<Job> Jobs {get; set;}
}
class Job {
public SourceMaterial SourceMaterial {get; set;}
}
class JobEditing : Job {}
class JobTranslation: Job {}
Module for configuring Job entities:
angular.module('cdt.request.model').factory('jobModel', ['breeze', 'dataService', 'entityService', modelFunc]);
function modelFunc(breeze, dataService, entityService) {
function Ctor() {
}
Ctor.extend = function (modelCtor) {
modelCtor.prototype = new Ctor();
modelCtor.prototype.constructor = modelCtor;
};
Ctor.prototype._configureMetadataStore = _configureMetadataStore;
return Ctor;
// constructor
function jobCtor() {
this.isScreenDeleted = null;
}
function _configureMetadataStore(entityName, metadataStore) {
metadataStore.registerEntityTypeCtor(entityName, jobCtor, jobInitializer);
}
function jobInitializer(job) { /* do stuff here */ }
}
Module for configuring JobEditing entities:
angular.module('cdt.request.model').factory(jobEditingModel, ['jobModel', modelFunc]);
function modelFunc(jobModel) {
function Ctor() {
this.configureMetadataStore = configureMetadataStore;
}
jobModel.extend(Ctor);
return Ctor;
function configureMetadataStore(metadataStore) {
return this._configureMetadataStore('JobEditing', metadataStore)
}
}
Module for configuring JobTranslation entities:
angular.module('cdt.request.model').factory(jobTranslationModel, ['jobModel', modelFunc]);
function modelFunc(jobModel) {
function Ctor() {
this.configureMetadataStore = configureMetadataStore;
}
jobModel.extend(Ctor);
return Ctor;
function configureMetadataStore(metadataStore) {
return this._configureMetadataStore('JobTranslation', metadataStore)
}
}
Then Models are configured like this :
JobEditingModel.configureMetadataStore(dataService.manager.metadataStore);
JobTranslationModel.configureMetadataStore(dataService.manager.metadataStore);
Now when I call createEntity for a JobEditing, the instance is created and at some point, breeze calls setNpValue and adds the newly created Job to the np SourceMaterial.
That's all fine, except that it is added twice !
It happens when rawAccessorFn(newValue); is called. In fact it is called twice.
And if I add a new type of job (hence I register a new type with the metadataStore), then the new Job is added three times to the np.
I can't see what I'm doing wrong. Can anyone help ?
EDIT
I've noticed that if I change:
metadataStore.registerEntityTypeCtor(entityName, jobCtor, jobInitializer);
to
metadataStore.registerEntityTypeCtor(entityName, null, jobInitializer);
Then everything works fine again ! So the problem is registering the same jobCtor function. Should that not be possible ?
Our Bad
Let's start with a Breeze bug, recently discovered, in the Breeze "backingStore" model library adapter.
There's a part of that adapter which is responsible for rewriting data properties of the entity constructor so that they become observable and self-validating and it kicks in when register a type with registerEntityTypeCtor.
It tries to keep track of which properties it has rewritten. The bug is that it records the fact of rewrite on the EntityType rather than on the constructor function. Consequently, every time you registered a new type, it failed to realize that it had already rewritten the properties of the base Job type and re-wrapped the property.
This was happening to you. Every derived type that you registered re-wrapped/re-wrote the properties of the base type (and of its base type, etc).
In your example, a base class Job property would be re-written 3 times and its inner logic executed 3 times if you registered three of its sub-types. And the problem disappeared when you stopped registering constructors of sub-types.
We're working on a revised Breeze "backingStore" model library adapter that won't have this problem and, coincidentally, will behave better in test scenarios (that's how we found the bug in the first place).
Your Bad?
Wow that's some hairy code you've got there. Why so complicated? In particular, why are you adding a one-time MetadataStore configuration to the prototypes of entity constructor functions?
I must be missing something. The code to register types is usually much smaller and simpler. I get that you want to put each type in its own file and have it self-register. The cost of that (as you've written it) is enormous bulk and complexity. Please reconsider your approach. Take a look at other Breeze samples, Zza-Node-Mongo for example.
Thanks for reporting the issue. Hang in there with us. A fix should be arriving soon ... I hope in the next release.
Coming from the java world I have difficulties to understand this code-fragment from the AngularDart pirate badge code lab:
Future _loadData() {
return _http.get('piratenames.json').then((HttpResponse response) {
PirateName.names = response.data['names'];
PirateName.appellations = response.data['appellations'];
});
}
}
From my understanding PirateName is a class and how can the line
PirateName.names = response.data['names'];
write a field of a class without referring to an actual instance?
Dart syntax allows static variables as does Java.
That is a static variable as defined in the source you provided Edit piratebadge.dart and you'll see where it is defined as static.