I am working on a small application with Laravel 4.1. I created an app/acme folder to contain most of my app specific code. I have a service provider named app/acme/AcmeServiceProvider.php where I am setting IoC bindings, Custom View templates and some Config variables.
My Custom Service Provider
...
View::addLocation(app('path').'/OneTimeNote/Views');
/* #TODO - Maybe a better place to put this would be in the app/config folder? */
Config::set('EXTERNAL_SITE_URL', 'http://www.example.com/#/');
/* #TODO - Probably could find a better spot for this, possibly in a lang folder? */
Config::set('EMAIL_SUBJECT', 'The note you created has been read and destroyed.');
...
I think having my custom View location in my service provider makes sense but what about the two entries below it?
The first Config is setting a value I can retrieve from my Controller so that I can build an external URL.
The second Config is setting a value I can use for an e-mail subject I'm sending the user. I thought about just hardcoding this value, but I wanted to put configurable text like this in one place for easy customization. I'd also like to utilize multiple languages in the future, so having some sort of 'lang' directory with different languages could be an answer I suppose?
My question: Is there a better place to put these two config statements rather than my Service Provider? Maybe they shouldn't be added to the Config at all but somewhere else? need advice.
Thanks!
Lets try by creating app/config/acme.php
and return array there e.g.
return array(
'EXTERNAL_SITE_URL' => 'SITE_URL',
'EMAIL_SUBJECT' => 'SUBJECt_VALUE'
);
try to access like that config::get('acme.EXTERNAL_SITE_URL'). I hope it should work for you. Please share you experience ....
#Edited: I have tested that is working for me, so should be for you as well :)
#Edited: Language Part
You can add file in app/lang/en/acme.php (e.g. for english)
if there is another language you can add app/lang/it/acme.php (e.g. for italian)
return array(
"abc" => "This is text",
"def" => array(
"sub1" => "this is fist sub message",
"sub2" => "this is on sencond number",
)
);
then you can get like App::setLocale('en');
echo Lang::get('acme.abc'); //output: This is text
echo Lang::get('acme.def.sub1'); //output: this is fist sub message
Related
2021: This was in fact an issue with the package. Regex link matching has since been implemented with the solution I created to solve it for myself. You can read about it in the documentation here.
I'm using Laravel 5.8 with AdminLTE for Laravel.
There's several options to create a menu, one of which is to create it in the provided config file, which I use.
You can specify an active key in the menu that allows you to make the menu have the class that makes the menu item active and activates the dropdown.
I have a menu item, which I would like to make active on these pages:
/posts (works with active => ['/posts'])
/posts/{post_id} (id are only numbers)
These URL's shouldn't match:
/posts/create
/posts/anyotherlink
/posts/1text
I can not use /posts/* because that would make the create page and some others active.
The readme suggest that you can also use regex to do this. I don't use regex at all, but I came to this, which, according tot regex101 seems to match what I need it to:
^\/posts\/[0-9]+$
I've tried to implement it like so:
[
'text' => 'Posts overview',
'url' => '/posts',
'icon' => 'list',
'active' => ['/posts', '^\/posts\/[0-9]+$'],
'active' => ['/posts', '/posts/[^0-9]'] // also tried this
],
Unfortunately, this does not seem to work as it doesn't make the menu item active on the pages listed above.
Edit: I've also created an issue in the GitHub repository as I suspect that this might be an issue with the package.
Am I missing something, or doing something wrong?
In the ActiveChecker.php class of the project you can find this piece of code
protected function checkPattern($pattern)
{
$fullUrlPattern = $this->url->to($pattern);
$fullUrl = $this->request->fullUrl();
return Str::is($fullUrlPattern, $fullUrl);
}
Based on laravel documentation, Str::is does not run regexp matching, but justs supports asterisks for wildcards.
In your case you could post a PR that will use regexo if the given pattern is a regular expression, otherwise, run Str::is
You can try using the below pattern in your code:
/^\/posts(\/[0-9]+)?$/
This will work for the below test scenarios:
/posts
/posts/3829
/posts/921
/posts/1
You can check the requirement with the provided solution on REGEX_Solution
Hope it works!
This is where route naming is really helpful. So, in my code this route would named something like admin:post.index. Then to check if it was active I could use the request helper and a method called routeIs().
Using the name I'd use, here's an example:
request()->routeIs('admin:post.index')
Now, if I wanted this link to be active for the create, edit, delete etc routes I'd do the following:
request()->routeIs('admin:post.*')
This would work since I apply route names following a dot notation hierarchy.
You can optionally provide multiple patterns to that method if there were specific routes you wanted to match.
I have created a solution for my problem, it's by no means the prettiest solution, but it'll work, for now.
I have edited the ActiveChecker.php file and edited the checkPattern() function, so it evaluates regex if the pattern in the config file starts with regex:.
protected function checkPattern($pattern)
{
$fullUrlPattern = $this->url->to($pattern);
$fullUrl = $this->request->fullUrl();
if(mb_substr($pattern, 0, 6) === "regex:") {
$regex = mb_substr($pattern, 6);
if(preg_match($regex, request()->path()) == 1) {
return true;
}
return false;
}
return Str::is($fullUrlPattern, $fullUrl);
}
In my config file, I can now just do this, to use a regex pattern, simply by using the regex: prefix.
'active' => ['/suppliers', 'regex:#^posts/[0-9]+$#'],
The path of the request which is posts/1 for example, will get compared with the regex, not the full URL.
The title may be confusing, but I'm not sure how to word it otherwise. So I want to be able to initialize a class and call methods from it without knowing the class name before getting it from an array.
What I want to do
$modules = array(
'Forums' => array(
'class'=>'Forums',
'classVar'=>'forum'
)
);
foreach($modules as $name => $module) if ($module['enabled']) {
require_once('include/scripts/'.$module['link']);
$$module['classVar'] = new $module['class'];
$$module['classVar'] = $module['classVar'];
global $$module['classVar'];
}
However, I know that this is a roundabout way to accomplish this, and I need to know if there's an easier way, and if this is even logical.
The reason I want to do this is because what I'm working on will be able to accept modules, and I need to be able to get all of the stats from the modules and display them in the main admin panel, but there's no way to know if a module is enabled and running if I didn't create it. For instance, if someone created module.php that tracked how many times someone clicked a specific link, the software wouldn't natively know about it, and I need it to be able to get stats from it.
Hmm, you might be interested in the Singleton design pattern (http://en.wikipedia.org/wiki/Singleton_pattern and http://www.phptherightway.com/pages/Design-Patterns.html).
In this case you'd have a list of classes in your configuration array and call "getInstance()" when you actually want to do something with the actual module.
Also, have a look at the Factory pattern, it might be useful for your purposes as well.
I don't understand the following. In the Book, they says:
Multiple word controllers can be any ‘inflected’ form which equals the controller name so:
/redApples
/RedApples
/Red_apples
/red_apples
will all resolve to the index of the RedApples controller. However, the convention is that your URLs are lowercase and underscored, therefore /red_apples/go_pick is the correct form to access the RedApplesController::go_pick action.
But if I write this on add.ctp view
echo $this->Html->link('Add Red Apples',
array('controller' => 'RedApples', 'action' => 'add'),
array('class' => 'button'));
it's create this html output:
www.site.com/RedApples/add
So, The correct way to access RedApplesController::add is /red_apples/add, but CakePHP html helper creates links like /RedApples/add? Which is the correct way to write my own links?
Thank you.
I'm confused as to what the issue is.
it says that you CAN use any form
you use a form other than the recommended
it displays the form you chose
What's the problem? The fact that it gives you a convention (but says it will accept non-conventional as well) and you've decided against using the convention doesn't equate to a problem IMO.
Maybe I'm misunderstanding the real question?
Which is the correct way to write my own links?
The "correct" way is the way you copy/pasted from the book where it almost literally says "the correct way is..."
However, the convention is that your URLs are lowercase and
underscored, therefore /red_apples/go_pick is the correct form to
access the RedApplesController::go_pick action.
If for some unknown reason you must use "RedApples" (a variable you can't change or something?) as your controller name in your link creation, you could wrap it in an inflector:
$myController = 'RedApples'; //unable to change to 'red_apples' for some reason
//...
'controller'=>Inflector::tableize($myController)
//...
I have a few general questions about modifying Magento's admin section and would be grateful to have them answered. I'm new to Magento so please bear with me.
My goal is to add a new column with a product attribute (e.g. "Size") to the "Category Products" table within the Catalog -> Manage Cateories section (see screenshot below).
Having little Magento dev experience, I'm not quite sure where to start. I had a look in some of the Grid.php files under the adminhtml directory, and while I see a bunch of statements like addColumn(...), I'm not sure where I'd slot in my new attribute column.
Also, I assume that instead of modifying any core files directly, I'd copy them to the same path under the local folder and edit or somehow extend them there? Do I have to edit any config files or do anything else for the change to be reflected? Am I - by doing this - in effect creating my own module?
I also read that I should disable "Compilation" before I make any changes. Why is this? Is there anything else to consider?
Again I am very grateful for any help and appreciate that my questions must seem basic. Any supplementary resources you could point me towards would be appreciated. Thanks.
Indeed you should start by understanding what file to edit and how to edit it. In this case you want to modify app/code/core/Mage/Adminhtml/Block/Catalog/Category/Tab/Product.php but, like you said, you should not modify the file in its current location. There are two ways to modify the file in the "correct" way.
(harder but more extensible) Create a new Module in local and tell Magento in the etc/config.xml that you are overwriting that Block (which is just a php class) with a different block in this new Module and have the new class extend the core Block class. Then you just need to overwrite one function (_prepareColumns).
(easier) Copy the file from app/code/core/Mage/Adminhtml/Block/Catalog/Category/Tab/Product.php to app/code/local/Mage/Adminhtml/Block/Catalog/Category/Tab/Product.php and modify the function you want (_prepareColumns)
If you are new to Magento, I recommend going with the second option because its easier. Magento will always load the file from local before it loads from core so the file in core will no longer be used and your version in local will be used. To find out more, read this article from Alan Storm
Now in order to add the column you want, do something similar to the SKU field
$this->addColumn('size', array(
'header' => Mage::helper('catalog')->__('Size'),
'index' => 'size'
));
in the order you want it (between Product Name and SKU). I am assuming that your Products have a field called size that you can retreive with $product->getSize()
Max solution was pretty spot on but missing some important steps, I'll elaborate on his original method
Create a new local override of the Product Tab by copying app/code/core/Mage/Adminhtml/Block/Catalog/Category/Tab/Product.php to app/code/local/Mage/Adminhtml/Block/Catalog/Category/Tab/Product.php
There are 2 functions involved in modifying the grid view. _prepareCollection and _prepareColumns
_prepareColumns by adding a call to the addColumn function just like:
$this->addColumn('size', array(
'header' => Mage::helper('catalog')->__('Size'),
'width' => '80',
'index' => 'size'
));
_prepareCollection, by default the product collection loaded in the grid only has a few attributes(name,sku,price) what you need to do add our now attribute by ->addAttributeToSelect('size') now if you are only working with a textfield attribute then this is the extend of the modifications you have to do however if your attribute is for example a dropdown you will need to do further changes to the prepare collection:
(optional) dropdown attributes only store the value of the option that was select so we need to provide an options array to the addColumns call so Magento can display the values correctly, we can do that in the following maner:
on your local copy of Products, add the following to the _prepareColumns functions
$attribute = Mage::getModel('eav/config')->getAttribute('catalog_product', 'colour');
$options = array();
foreach( $attribute->getSource()->getAllOptions(true, true) as $option ) {
$options[$option['value']] = $option['label'];
}
$this->addColumn('colour', array(
'header' => Mage::helper('catalog')->__('Colour'),
'width' => '80',
'index' => 'colour',
'type' => 'options',
'options' => $options
));
While those are some very thorough question and I'm sure you will learn a lot, there is a ready-made solution; Enhanced Admin Product Grid has the ability to add arbitrary attributes as columns.
I'm using HTMLPurifier in a current project and I'm not sure about the most efficient way to go about handling multiple configs. For the most part the only major thing changing is the allowed tags.
Currently I have a private method, in each class using HTMLPurifier, that gets called when a config is needed and it creates one from the default. I'm not really happy with this as if 2 classes are using the same config, that's duplicating code, and what if a class needs 2 configs? It just feels messy.
The one upside to it, is it's lazy in the sense that it's not creating anything until it's needed. The various classes could be used and never have to purify anything. So I don't want to be creating a bunch of config objects that might not even be used.
I just recently found out that you can create a new instance of HTMLPurifier and directly set config options like so:
$purifier = new HTMLPurifier();
$purifier->config->set('HTML.Allowed', '');
I'm not sure if that's bad form at all or not, and if it isn't I'm not really sure of a good way to put it to use.
My latest idea was to create a config handler class that would just return an HTMLPurifier config for use in subsequent purify calls. At some point it could probably be expanded to allow the setting of configs, but just from the start I figured they'd just be hardcoded and run a method parameter through a switch to grab the requested config. Perhaps I could just send the stored purifier instance as an argument and have the method directly set the config on it like shown above?
This to me seems the best of the few ways I thought of, though I'm not sure if such a task warrants me creating a class to handle it, and if so, if I'm handling it in the best way.
I'm not too familiar with the inner workings of HTMLPurifier so I'm not sure if there are any better mechanisms in place for handling multiple configs.
Thanks for any insight anyone can offer.
Configuration objects have one important invariant: after they've been used to perform a purification, they cannot be edited. You might be interested in some convenience methods that the class has, in particular, inherit, and you can load an array of values using loadArray.
I just wrote up a quick, simple config handler class.
You can view / use it # http://gist.github.com/358187/
It takes an array of configs at initialization.
$configs = array(
'HTML.Doctype' => 'HTML 4.01 Strict',
'posts' => array(
'HTML.Allowed' => 'p,a[href],img[src]'
),
'comments' => array(
'HTML.Allowed' => 'p'
),
'default' => array(
'HTML.Allowed' => ''
)
);
Directives put directly into the array are global and will be applied to all configs. If the same directive is set inside a named config, the value in the named config will be used.
Then you can grab a config like so:
$purifierConfig = new purifierConfig($configs);
$commentsConfig = $purifierConfig->getConfig('comments');
or, shorthand:
$commentsConfig = $purifierConfig['comments'];
If the requested config does not exist or no config is specified in the call, the default config will be returned.
I'll probably flesh it out at some point, but for now this works.
I was looking for how people handled such things in their projects or if there were any built in mechanisms that made something like this more steamlined, but I suppose my question was a bit too narrow in scope.