I generated model files successfully, but for some reason I cannot call on known record attributes as if they had concrete accessors, even though I should be able to so via Doctrine_Record::__call(). I checked the doctrine manual for build options but did not see anything relevant to my problem.
$conns['core_rw'] = Doctrine_Manager::connection('mysql://ccast:#127.0.0.1/core', 'core_rw');
Doctrine_Core::generateModelsFromDb('/path/to/lib/Hobis/App/Model', array_keys($conns),
array(
'baseClassPrefix' => 'Base_',
'baseClassesDirectory' => 'Base',
'classPrefix' => 'Hobis_App_Model_',
'classPrefixFiles' => false,
'generateBaseClasses' => true,
'generateTableClasses' => true
)
);
After models were generated, I tried this:
$conns['core_rw'] = Doctrine_Manager::connection('mysql://ccast:#127.0.0.1/core', 'core_rw');
$widget = Hobis_App_Model_WidgetTable::getInstance()->findOneById(1337);
// Works
var_dump($widget->get('id'));
// Does not work
var_dump($widget->getId());
Related
I'm developing a prestashop module and I'm trying to show a category tree in my backoffice configuration page.
I'm trying to follow this instructions below but I don't know exactly where to add this code.
It should be inside main module's php? or inside a separate .php file and call it from the main one (don't know how to do it either).
As much time I'm spending trying to figure out, how to implement the code in the link above, the more I think I'm losing my time.
I see that "use" files, and this JS, " /admin-dev/themes/new-theme/js/components/form/choice-tree.js " are not in any prestashop folders.
Well, you should invest some time and learn Symfony since this is what you need to build backend modules for Prestashop 1.7.
As a pointer, you need to create a form class extending the CommonAbstractType, add a build form method. e.g. :
public function buildForm(FormBuilderInterface $builder, array $options)
{
$this->context = Context::getContext();
$parents = [
['id_category' => 2, 'name' => 'Home', 'children' => $this->getSubCategories(1, true, 2)]
];
$builder->add('category', CategoryChoiceTreeType::class, [
'choices_tree' => $parents,
'choice_value' => 'id_category',
'choice_children' => 'children',
'choice_label' => 'name',
'disabled_values' => $disabledCategories,
'label' => 'Choose a category'
])
then add methods for retrieving the data to populate the form fields.
Then use this class in your controller and display the form:
$form = $this->createForm(YourFormForm::class);
Also add a processForm to process data.
As mentioned, this is not a copy/paste situation you need to understand the Symfony workflow.
The only way that I found to "paint" the categorytree in my configuration page is adding this code to the inputs form array:
Can anyone tell me how to retrieve users selection data to my database?
It does not work as any other form field.
array(
'type' => 'categories',
'label' => $this->l('Destination Category'),
'desc' => $this->l('Select ONE Category'),
'name' => 'CATEGORY_CATEGORY_TO',
'tree' => [
// 'selected_categories' => [],
'disabled_categories' => null,
'use_search' => false,
'use_checkbox' => false,
'id' => 'id_category_tree',
],
'required' => true
),
Well, it is SOLVED!!!! Finally it was very simple, but you must get the correct info for you particular case.
#Robertino's answer might be the best implementation, I don't know, but it became impossible to solve for me,
I uses this code below, and called $categoryTree from the form input. This input must be type=> categories_select
Thanks for your time, and for the help of another post from this forum.
$root = Category::getRootCategory();
//Generating the tree
$tree = new HelperTreeCategories('categories_1'); //The string in param is the ID used by the generated tree
$tree->setUseCheckBox(false)
->setAttribute('is_category_filter', $root->id)
->setRootCategory($root->id)
->setSelectedCategories(array((int)Configuration::get('CATEGORY_1'))) //if you wanted to be pre-carged
->setInputName('CATEGORY_1'); //Set the name of input. The option "name" of $fields_form doesn't seem to work with "categories_select" type
$categoryTree = $tree->render();
And the Form:
array(
'type' => 'categories_select',
'label' => $this->l('Category'),
'desc' => $this->l('Select Category '),
'name' => 'CATEGORY_1', //No ho podem treure si no, no passa la variable al configuration
'category_tree' => $categoryTree, //This is the category_tree called in form.tpl
'required' => true
I am using Silex 2.0 (I know - it's development version and not fully released yet) along with CNAM's JWT security provider (see: https://github.com/cnam/security-jwt-service-provider) to write an API for an open source application I am writing.
In short, there are three types of users that I care about:
Sitewide admins (ROLE_ADMIN) that have complete access
Commissioners (ROLE_COMMISH) who create objects they own, and can edit their own objects
Anonymous users who access read-only information.
As such, there are three sections of routes that go along with these "roles":
/admin/* where administrators can perform their uber actions
/commish/* where commissioners or admins can perform their actions on their objects
/* where all users can read information
The issue that I've come across is that while I can setup 3 firewalls, one for each, there are times in the 3rd route category (GET /object/1 for instance) where it needs to be accessibly anonymously, but if the user provides a valid JWT token, I need to access that user in order to perform some additional logic on the data I hand back in the response.
As I have it setup currently (more on my config below), it's all-or-nothing: I either restrict an entire firewall to only authenticated users with a certain role, or I open it up to anonymous users (and therefore cannot view user information).
Is it possible to have a route that anyone can hit, but logged in users can also be seen?
Current security configuration:
$app['users'] = function () use ($app) {
return new UserProvider($app);
};
$app['security.jwt'] = [
'secret_key' => AUTH_KEY,
'life_time' => 86400,
'algorithm' => ['HS256'],
'options' => [
'header_name' => 'X-Access-Token'
]
];
$app['security.firewalls'] = array(
'login' => [
'pattern' => 'login|register|verify|lostPassword|resetPassword',
'anonymous' => true,
],
'admin' => array(
'pattern' => '^/admin',
'logout' => array('logout_path' => '/logout'),
'users' => $app['users'],
'jwt' => array(
'use_forward' => true,
'require_previous_session' => false,
'stateless' => true,
)
),
'commish' => array(
'pattern' => '^/commish',
'logout' => array('logout_path' => '/logout'),
'users' => $app['users'],
'jwt' => array(
'use_forward' => true,
'require_previous_session' => false,
'stateless' => true,
)
)
);
$app['security.role_hierarchy'] = array(
'ROLE_ADMIN' => array('ROLE_MANAGER'),
);
$app->register(new Silex\Provider\SecurityServiceProvider());
$app->register(new Silex\Provider\SecurityJWTServiceProvider());
Additionally, I've attempted another approach where I match all routes under a single firewall, but then protect certain ones by using securty.access_rules configuration, but it does not work. An example of what I've tried:
$app['security.firewalls'] = array(
'api' => array(
'pattern' => '^/',
'logout' => array('logout_path' => '/logout'),
'anonymous' => true,
'jwt' => array(
'use_forward' => true,
'require_previous_session' => false,
'stateless' => true
)
)
);
$app['security.access_rules'] = array(
array('^/admin', 'ROLE_ADMIN'),
array('^/commish', 'ROLE_MANAGER'),
array('^/', 'IS_AUTHENTICATED_ANONYMOUSLY')
);
You can use $app['security.jwt.encoder'] to decode jwt and either create a custom trait and extending the route object or using midddlewareeeither on the route level or an easier way would be to use a middleware on the application level. I had similar issue and this is how i solved it, something like below
ex.
$app->before(function (Request $request, Application $app) {
$request->decodedJWT = $app['security.jwt.encoder']->
decode($request->headers->get('X-Access-Token'));
});
and then you can access the decoded jwt form any route by doing this
$app->get('/object/1', function(Request $request) {
$decodedJWT = $request->decodedJWT;
// do whatever logic you need here
})
So: so far I have not found this to be possible through the "normal" way, which is disappointing. I will not mark what I detail below as the "answer" for a few days, hoping that someone can chime in and offer a better, more "official" way to solve the dilemma.
TL;DR: I manually check the request headers for the access token string, then decode the token using the JWT classes in order to load the user account in routes outside of the firewall. It's incredibly hacky, it feels downright dirty, but it's the only solution to the issue that I see at the moment.
Technical Details: First, you must acquire the token value from the request header. Your controller method will have been handed a Symfony\Component\HttpFoundation\Request object, from which you can access $request->headers->get('X-Access-Token'). In most instances the user will not be authenticated, so this will be empty, and you can return null.
If not empty, you must then use Silex's instance of JWTEncoder to decode the token contents, create a new token instance of JWTToken, set the context to the decoded value from the encoder, and finally you can access the username property from said token - which can then be used to grab the corresponding user record. An example of what I came up with:
$request_token = $request->headers->get('X-Access-Token','');
if(empty($request_token)) {
return null;
}
try {
$decoded = $app['security.jwt.encoder']->decode($request_token);
$token = new \Silex\Component\Security\Http\Token\JWTToken();
$token->setTokenContext($decoded);
$userName = $token->getTokenContext()->name;
//Here, you'd use whatever "load by username" function you have at your disposal
}catch(\Exception $ex) {
return null;
}
And obviously, any code calling this function would need to know that because the request is outside of the firewall, there is zero guarantee that a user will be returned (hence the hacky try-catch that silences exceptions by just returning null).
Edit: I've updated the code here to use Silex's built-in DI container (provided by Pimple) so there's no need to create a new instance of the JWT encoder by hand. I'm also marking #user5117342 's answer as the correct one, as using some sort of Silex middleware approach is far more robust.
Edit (April 2016): Using the updated cnam/security-jwt-service 2.1.0 along with symfony/security 2.8, there's a slight update that makes the code above a little simpler:
$request_token = $request->headers->get('X-Access-Token','');
if(empty($request_token)) {
return null;
}
try {
$decodedToken = $app['security.jwt.encoder']->decode($request_token);
$userName = $decodedToken->name;
//Here, you'd use whatever "load by username" function you have at your disposal
}catch(\Exception $ex) {
return null;
}
The issue with the newer dependencies is that the JWTToken constructor requires 3 parameters which are difficult to obtain in most service layers, not to mention is quite out of place. As I was updating my Composer dependencies, I ended up finding out that I didn't actually need to create a JWTToken in order to get the username I needed.
Of course, it's to be noted I'm only using this method on public (anonymous) API routes to provide some niceties to users who are logged in - my app doesn't deal with sensitive data so I'm not overly concerned with this avenue outside of the firewalls. At worst a black hat user would end up seeing non-sensitive data that they normally wouldn't, but that's it. So YMMV.
Your are must be use regular expression e.g.
$app['security.firewalls'] = array(
'login' => [
'pattern' => 'login|register|oauth',
'anonymous' => true,
],
'secured' => array(
'pattern' => '^/api|/admin|/manager',
'logout' => array('logout_path' => '/logout'),
'users' => $app['users'],
'jwt' => array(
'use_forward' => true,
'require_previous_session' => false,
'stateless' => true,
)
),
);
Hi I am using a laravel package https://github.com/greggilbert/recaptcha and I have published the config files where I need to store my public and private keys for my recaptcha. I want to call this elsewhere in my app in an attempt to process this via AJAX . I've tried to call this as
dd(Config::get('packages.greggilbert.recaptcha')['public_key']);
however this returns as null. The array is kept in the following folder:
app/config/packages/greggilbert/recaptcha/config.php
the array is built as so:
<?php
return array(
'public_key' => 'publickey',
'private_key' => 'privatekey',
'template' => '',
'driver' => 'curl',
'options' => array(
'curl_timeout' => 1,
),
'version' => 2,
);
Any ideas how I can retrieve the public_key value??
Retrieving configs from a package works a bit different. You use a so-called namespace:
Config::get('recaptcha::public_key');
I'm using codeIgniter 2.1.4 with Datamapper and i worry about Datamapper performance.
My results are only 2 rows and return successfully!
But when i dumped $posts with var_dump($posts), I'm getting 20.000 code lines with included all data/relations/configs/tables/fields/languages etc..
Sorry, I couldnt paste dumped data because of excessive lines.
What's the problem? Where am I doing wrong?
Its my sample query:
$posts = new post_model();
$posts->where('active', 1)
->where('slug', $slug)
->include_related('users', '*', 'user', true)
->include_related('categories', '*', 'category', true)
->include_related('tags', '*', 'tag', true)
->include_related('groups', '*', 'group', true)
->get_paged($this->uri->segment(4), 50, TRUE);
Include Related Model Assignments:
public $has_one = array('users' =>
array(
'class' => 'users_m',
'other_field' => 'post',
'model_path' => 'application/modules/users',
),
'categories' => array(),
'tags' => array(),
'groups' => array(),
);
Posts Related Assignments:
public $has_one = array(
'request' => array(
'class' => 'posts_m',
'model_path' => 'application/modules/posts',
)
);
By the way..
I set instantiate as false and dumped data decreased to 3.000 lines.. I really didnt understand..
You aren't doing anything wrong -- this is just the way it is.
Try to understand how PHP, and CodeIgniter work.
In PHP5, all objects are assigned by reference. This means that
although you see them when you access a Datamapper object, they are
not copies, and don’t take up memory.
CodeIgniter works by assigning all objects as singletons to $this, so
a var_dump($this) will show you pages and pages of object information.
All other objects that access CI ( either via an automatic mechanism
or through get_instance() ) use references.
So obviously you’ll see all this when you dump a Datamapper object.
Because Datamapper accesses the database, language, and form
validation libraries, which in turn have links to several other
libraries.
http://ellislab.com/forums/viewthread/188420/#890508
$instantiate - If TRUE, then actual objects are instantiated and populated with the columns automatically.
http://datamapper.wanwizard.eu/pages/getadvanced.html
Instantiate TRUE means more data. Intantiate FALSE means less data.
I am trying to use the elasticsearch routing mapping to speed up some queries, but I am not getting the expected result set (not worried about the query performance just yet)
I am using Elastic to set up my mapping:
$index->create(array('number_of_shards' => 4,
'number_of_replicas' => 1,
'mappings'=>array("country"=>array("_routing"=>array("path"=>"countrycode"))),
'analysis' => array(
'analyzer' => array(
'indexAnalyzer' => array(
'type' => 'keyword',
'tokenizer' => 'nGram',
'filter' => array('shingle')
),
'searchAnalyzer' => array(
'type' => 'keyword',
'tokenizer' => 'nGram',
'filter' => array('shingle')
)
)
) ), true);
If I understand correctly, what should happen is that each result should now have a field called "countrycode" with the value of "country" in it.
The results of _mapping look like this:
{"postcode":
{"postcode":
{"properties":
{
"area1":{"type":"string"},
"area2":{"type":"string"},
"city":{"type":"string",
"include_in_all":true},
"country":{"type":"string"},
"country_iso":{"type":"string"},
"country_name":{"type":"string"},
"id":{"type":"string"},
"lat":{"type":"string"},
"lng":{"type":"string"},
"location":{"type":"geo_point"},
"region1":{"type":"string"},
"region2":{"type":"string"},
"region3":{"type":"string"},
"region4":{"type":"string"},
"state_abr":{"type":"string"},
"zip":{"type":"string","include_in_all":true}}},
"country":{
"_routing":{"path":"countrycode"},
"properties":{}
}
}
}
Once all the data is in the index if I run this command:
http://localhost:9200/postcode/_search?pretty=true&q=country:au
it responds with 15740 total items
what I was expecting is that if I run the query like this:
http://localhost:9200/postcode/_search?routing=au&pretty=true
Then I was expecting it to respond with 15740 results
instead it returns 120617 results, which includes results where country is != au
I did note that the number of shards in the results went from 4 to 1, so something is working.
I was expecting that in the result set there would be an item called "countrycode" (from the rounting mapping) which there isn't
So I thought at this point that my understand of routing was wrong. Perhaps all the routing does is tell it which shard to look in but not what to look for? in other words if other country codes happen to also land in that particular shard, the way those queries are written will just bring back all records in that shard?
So I tried the query again, this time adding some info to it.
http://localhost:9200/postcode/_search?routing=AU&pretty=true&q=country:AU
I thought by doing this it would force the query into giving me just the AU place names, but this time it gave me only 3936 results
So I Am not quite sure what I have done wrong, the examples I have read show the queries changing from needing a filter, to just using match_all{} which I would have thought would only being back ones matching the au country code.
Thanks for your help in getting this to work correctly.
Almost have this working, it now gives me the correct number of results in a single shard, however the create index is not working quite right, it ignores my number_of_shards setting, and possibly other ones too
$index = $client->getIndex($indexname);
$index->create(array('mappings'=>array("$indexname"=>array("_routing"=>array("required"=>true))),'number_of_shards' => 6,
'number_of_replicas' => 1,
'analysis' => array(
'analyzer' => array(
'indexAnalyzer' => array(
'type' => 'keyword',
'tokenizer' => 'nGram',
'filter' => array('shingle')
),
'searchAnalyzer' => array(
'type' => 'keyword',
'tokenizer' => 'nGram',
'filter' => array('shingle')
)
)
) ), true);
I can at least help you with more info on where to look:
http://localhost:9200/postcode/_search?routing=au&pretty=true
That query does indeed translate into "give me all documents on the shard where documents for country:AU should be sent."
Routing is just that, routing ... it doesn't filter your results for you.
Also i noticed you're mixing your "au"s and your "AU"s .. that might mix things up too.
You should try setting required on your routing element to true, to make sure that your documents are actually stored with routing information when being indexed.
Actually to make sure your documents are indexed with proper routing explicitly set the route to lowercase(countrycode) when indexing documents. See if that helps any.
For more information try reading this blog post:
http://www.elasticsearch.org/blog/customizing-your-document-routing/
Hope this helps :)