Autoloading a class in Symfony 2.1 - symfony-2.1

I'm porting a Symfony 1.2 project to Symfony 2.x. I'm currently running the latest 2.1.0-dev release.
From my old project I have a class called Tools which has some simple functions for things like munging arrays into strings and generating slugs from strings. I'd like to use this class in my new project but I'm unclear how to use this class outside of a bundle.
I've looked at various answers here which recommend changing app/autoload.php but my autoload.php looks different to the ones in the answers, maybe something has changed here between 2.0 and 2.1.
I'd like to keep my class in my src or app directories as they're under source control. My vendors directory isn't as I'm using composer to take care of that.
Any advice would be appreciated here.

Another way is to use the /app/config/autoload.php:
<?php
use Doctrine\Common\Annotations\AnnotationRegistry;
$loader = require __DIR__.'/../vendor/autoload.php';
$loader->add( 'YOURNAMESPACE', __DIR__.'/../vendor/YOURVENDOR/src' );
// intl
if (!function_exists('intl_get_error_code')) {
require_once _DIR__.'/../vendor/symfony/symfony/src/Symfony/Component/Locale/Resources/stubs/functions.php';
$loader->add('', __DIR__.'/../vendor/symfony/symfony/src/Symfony/Component/Locale/Resources/stubs');
}
AnnotationRegistry::registerLoader(array($loader, 'loadClass'));
return $loader;
Just replace YOURNAMESPACE and YOURVENDOR with your values. Works quite well for me, so far.
You're correct, I stumbled upon the changes in autoload from 2.0 to 2.1. The above code works fine with the latest version, to which I upgraded my project ;-)

For a simple case like this the quickest solution is creating a folder (for example Common) directly under src and put your class in it.
src
-- Common
-- Tools.php
Tools.php contains your class with proper namespace, for example
<?php
namespace Common;
class Tools
{
public static function slugify($string)
{
// ...
}
}
Before calling your function do not forget the use statement
use Common\Tools;
// ...
Tools::slugify('my test string');
If you put your code under src following the proper folder structure and namespace as above, it will work without touching app/autoload.php.

Related

Creating JHipster blueprint to extend the field type prompt

I have already created a test blueprint that works, so I kinda got the idea, but I would like to make sure that I am approaching this correctly.
I want to extend the field type prompt to offer custom types alongside String, int, boolean etc.
This means I need to modify the templates, like templates/src/main/java/package/domain/Entity.java.ejs
My blueprint only had generators/client and generators/entity-client, so I guess I have to:
create generators/entity-server
create index.js
create files.js (can I copy that from here https://github.com/jhipster/generator-jhipster/blob/master/generators/entity-server/files.js ?)
create the templates in entity-server/templates
create generators/entity
copy and modify generators/entity/prompts.js: do I have to just write a new prompts.js, or do I have to copy over everything in generators/entity and only change what I would like to change ?
For the templates, can I copy them from the JHipster repo ?
Should I ? If not, why not and what is the alternative ?
If copying them is the right move, do I have to copy everything ? Or just the ones I want to modify ? (I haven't checked yet if I will need to modify everything)
When JHipster is updated, I suppose either I manually merge the new files, or I risk that slowly my code will differ more and more from the JHipster code ?
Is there a simpler method to achieve what I am trying to do ?
It would be nice if I could just say I want to add TypeX and TypeY to that prompt and provide limited templates that only cover those types, like a template for the import, one for the field, and one for the setter and getter, and if only the import is provided, a generic template is used.
I'll try to answer to all your questions.
First to create Blueprint I suggest to use https://github.com/jhipster/generator-jhipster-blueprint even in another folder and copy all you need for your current project. I think it's easier and you could choose which generator you want to add e.g. entity-server and entity.
Prompts phase
If you want to modify prompt phase you can merge your phase with the JHipster one like that
get prompting() {
const phaseFromJHipster = super._prompting();
const phaseFromMe = {
askForTheme: prompts.askForTheme,
setMySharedConfigOptions() {
this.configOptions.theme = this.theme;
}
};
return { ...phaseFromJHipster, ...phaseFromMe };
}
(source: https://github.com/avdev4j/samSuffit/tree/master/generators/client)
But by doing this you can't modify existing questions, for this case you should copy all existing questions into your blueprint.
Templates management
Your blueprint is linked with a JHipster version. As I used to say (in my talks) is that you should copy and modify templates from JHipster except for configuration files because it's a bit tricky to handle. For them, I prefer to use JHipster API like 'replaceContent()' or the needle API which allowed you to insert some code into some files (like a dependency in the pom.xml file).
Of course you can use the way you want, but with experiences I prefer to control my templates and merge them when I upgrade the JHipster version.
You should only copy the templates you want to modify, merge JHipster and your writing phase. JHipster use yeoman, which use memfs to handle file generation. Every files are created in memory and dumped at the final step. You can easily override a file without performance compromise.
get writing() {
const phaseFromJHipster = super._writing();
/* eslint-disable */
const phaseFromSam = {
writeSamFiles() {
if (this.clientFramework === 'angularX') {
return writeAngularFiles.call(this);
}
}
};
/* eslint-enable */
return { ...phaseFromJHipster, ...phaseFromSam };
}
JHipster upgrade
I suggest you to check templates when upgrading JHipster and apply modifications if needed. Otherwise, you could have bugs. Also, I suggest to set a definitive (like 6.1.0) version of JHipster in your blueprint package.json.
As far I know there is no way to do what you want to do. I'm thinking of a way to modify prompts easily without copying all other questions, if you want to contribute ;).
You can check my blueprint sample I use to show in my talks:
https://github.com/avdev4j/samSuffit/
I hope It can help you can, feel free to ask more.
regards,

How are directory listings generated with ratpack?

I've just started looking at Ratpack, and my initial use case to as a simple development server. It seems quite trivial to get it to serve a directory of static files (in Groovy), I paraphrase this article:
#!/usr/bin/env groovy
#Grab('io.ratpack:ratpack-groovy:1.5.1')
import static ratpack.groovy.Groovy.ratpack
ratpack {
handlers {
files { dir "static" index }
}
}
I see there's an option to define an index page (for example, index.html), but this is static. I'd like it to serve a dynamic directory listing, as Apache can. I'd hoped this would simply require enabling a option, but I cannot find any indication such a thing exists.
I can't help feeling I have missed something. Can anyone point me in the right direction?
There's no built in directory listing feature. You would have to implement your own.

Botbuilder how to use default locale strings in case namespace hasn't defined it

I am using the botbuilder framework. I have defined several namespaces for the dialogs I have created, such as help or default. For all of these I have also created json files in my locale/en/ directory, and all is well.
However, I have a few sentences that are very common, and I don't feel like copying those over to each of the individual namespaces. I have tried using index.json as a 'fallback' in case the namespace file doesn't define the string. But it doesn't work for me. Contrary to what the documentation seems to suggest.
/locale
/en
/help.json
/default.json
/index.json <-- Doesn't work
/dialogs
/help.js
/default.js
bot.js
Say I have the following library in help.js, that :
lib = new builder.Library('help')
lib.dialog('/', (session) => {
session.send('custom_cancel')
}
module.exports = lib
The library is used in bot.js:
bot.library(require('./dialogs/help'))
And index.json has this content:
{
"custom_cancel": "My custom cancel"
}
Whereas help.json is empty:
{}
Because help.json does not have custom_cancel, the bot will actually send custom_cancel as the string.
Again. I can copy paste the strings to both locations and there is no more problem. But that seems like an ugly solution to me.
I have tried the more explicit version, which seems to help in more cases, but I am not fully convinced yet.
session.localizer.gettext(session.preferredLocale(), 'custom_cancel')
You can use the third argument for the namespace. It seems that '' will point to the index.json file.

What do I use to replace ToNullSafeString() removed from AutoMapper 3?

I have code using AutoMapper 3.2.1.0 that uses the method ToNullSafeString().
I upgraded the NUGet package to 4.1.1.0, and I can no longer find the method in their package.Does anyone know the recommended approach to replacing the function? Is there a new construct that is functionally equivalent? If so, I cannot figure what it is. Nor can I find any mention of why it was removed.
This question has actually been answered pretty well in a couple of comments below it. For completeness, here are a couple of actual implementations of solutions.
Short answer
Probably both the simplest and the best solution: Replace all instances of .ToNullSafeString() with ?.ToString(). This does the same, but uses functionality built into newer versions of .Net instead of relying on an external extension method.
Alternative answer
If you've got a bunch of calls to the ToNullSafeString() method from the earlier version Automapper, and for some reason or other you can't or don't want to go through all your code and edit it away right now, you can use this instead.
Add the following class to your project, and make sure it can be reached from any classes that previously called the Automapper-method. Those calls will then automatically point to this instead.
public static class NullSafeStringHelper
{
public static string ToNullSafeString(this object value)
{
return value?.ToString();
}
}

SearchDomainFactory.Instance is obsolete: 'Inject me!' ( Can't find out how to create instance)

I'm in the process of trying to migrate a R# extension project from R# 6 to R# 8. (I've taken over a project that someone wrote, and I'm new to writing extensions.)
In the existing v6 project there is a class that derives from RenameWorkflow, and the constructor used to look like this;
public class RenameStepWorkflow : RenameWorkflow
{
public RenameStepWorkflow(ISolution Solution, string ActionId)
: base(Solution, ActionId)
{
}
This used to work in R# SDK v 6, but now in V8, RenameWorkflow no longer has a constructor that takes Solution and actionId. The new constructor signature now looks like this;
public RenameWorkflow(
IShellLocks locks,
SearchDomainFactory searchDomainFactory,
RenameRefactoringService renameRefactoringService,
ISolution solution,
string actionId);
now heres my problem that I need help with (I think)
I've copied the constructor, and now the constructor of this class has to satisfy these new dependancies. Through some digging I've managed to find a way to satisfy all the dependencies, except for 'SearchDomainFactory'. The closest I can come to instantiating via the updated constructor is as follows;
new RenameStepWorkflow(Solution.Locks, JetBrains.ReSharper.Psi.Search.SearchDomainFactory.Instance, RenameRefactoringService.Instance, this.Solution, null)
All looks good, except that JetBrains.ReSharper.Psi.Search.SearchDomainFactory.Instance is marked as Obsolete, and gives me a compile error that I cannot work around, even using #pragma does not allow me to compile the code. The exact error message I get when I compile is Error 16 'JetBrains.ReSharper.Psi.Search.SearchDomainFactory.Instance' is obsolete: 'Inject me!'
Obvious next question..ok, how? How do I 'inject you'? I cannot find any documentation over this new breaking change, in fact, I cannot find any documentation (or sample projects) that even mentions DrivenRefactoringWorkflow or RenameWorkflow, (the classes that now require the new SearchDomainFactory), or any information on SearchDomainFactory.Instance suddenly now obsolete and how to satisfy the need to 'inject' it.
Any help would be most appreciated! Thank you,
regards
Alan
ReSharper has its own IoC container, which is responsible for creating instances of classes, and "injecting" dependencies as constructor parameters. Classes marked with attributes such as [ShellComponent] or [SolutionComponent] are handled by the container, created when the application starts or a solution is loaded, respectively.
Dependencies should be injected as constructor parameters, rather than using methods like GetComponent<TDependency> or static Instance properties, as this allows the container to control dependency lifetime, and ensure you're depending on appropriate components, and not creating leaks - a shell component cannot depend on a solution component for instance, it won't exist when the shell component is being created.
ReSharper introduced the IoC container a few releases ago, and a large proportion of the codebase has been updated to use it correctly, but there are a few hold-outs, where things are still done in a less than ideal manner - static Instance properties and calls to GetComponent. This is what you've encountered. You should be able to get an instance of SearchDomainFactory by putting it as a constructor parameter in your component.
You can find out more about the Component Model (the IoC container and related functionality) in the devguide: https://www.jetbrains.com/resharper/devguide/Platform/ComponentModel.html

Resources