Is it possible to use the Slugger interface other than in a constructor? - string

I'm looking to use the sluggerInterface in a class. But I want to keep:
public function __construct()
{
}
So I want to use sluggerInterface in my class without adding any argument in my constructor. (this is in order to automatically create 1 slug when creating an object).
So I want a code different from this one:
use Symfony\Component\String\Slugger\SluggerInterface;
class MyService
{
private $slugger;
public function __construct(SluggerInterface $slugger)
{
$this->slugger = $slugger;
}
public function someMethod()
{
$slug = $this->slugger->slug('...');
}
}
Thank you !

You do not want to use autowiring in your constructor ?
You could just create a new slugger, for example with Symfony\Component\String\Slugger\AsciiSlugger;
$slugger = new AsciiSlugger();
$slugger->slug('Please slug this.')->toString();
Or you could also use autowiring with another method using #required annotation (or attribute #[Required] for PHP 8+)
private $slugger;
#[Required]
public function setSlugger(SluggerInterface $slugger): void
{
$this->slugger= $slugger;
}
this is in order to automatically create 1 slug when creating an object
You may also want to look into event listener, using doctrine event prePersist to slug your entity when persisted could be another idea.
Finally, gedmo doctrine-extensions sluggable may interest you as well.

Related

Micronaut controller with pagination using Pageable

I am trying to use a Micronaut controller with pagination. Micronaut-Data has this Spring inspired way to access the repositories using the Pageable class and returning a Page
The problem comes when you want to show this paginated data. I have not been able create a call the controller with pagination. Here I have a simple controller:
#Controller
public class PageableController {
private static final Logger LOGGER = LoggerFactory.getLogger(PageableController.class);
#Get(produces = APPLICATION_JSON, value = "/test{?pageable}")
public Page<String> getNames(#Nullable Pageable pageable) {
LOGGER.info("pageable {}", pageable);
if( pageable == null){
return Page.of(Arrays.asList("foo", "bar"), Pageable.UNPAGED, 2);
}else{
return Page.of(Arrays.asList("foo", "bar"), pageable, 2);
}
}
}
I would expect to be able to call it with something like this. But currently the logger shows that pageable is always null:
#MicronautTest
class PageableControllerTest {
#Inject
#Client("/")
private RxHttpClient client;
#Test
void callsWithPageable() {
String uri = "/test?size=20&number=2";
String orders = client.toBlocking().retrieve(HttpRequest.GET(uri));
//TODO, assert orders and pagination
}
It would be even better if we could test it with something like:
#Test
void callsWithPageableParsingJson() {
String uri = "/test?size=20&number=2";
//This fails to parse as it can't build pages.
Page<String> pages = client.toBlocking().retrieve(HttpRequest.GET(uri), pageOf(String.class));
assertThat(pages.getSize(), is(2));
assertThat(pages.getContent(), contains("foo", "bar"));
}
// Inspired by Argument.listOf
private static <T> Argument<Page<T>> pageOf(Class<T> type) {
return Argument.of((Class<Page<T>>) ((Class) Page.class), type);
}
And this Micronaut bug shows that the right way to paginate is with Micronaut Data
The problem was solved by adding the following dependecy:
<dependency>
<groupId>io.micronaut.data</groupId>
<artifactId>micronaut-data-runtime</artifactId>
<version>1.0.0.M1</version>
</dependency>
My controller layer had access to the micronaut-data-model but this jar contains the important class PageableRequestArgumentBinder. Just by being i the classpath it will automatically be injected as a binder with no need for extra configuration.
And yes, Free See was right and now I can remove the pageable argument from the path and the argument from the method does not need to be #Nullable :
#Controller
public class PageableController {
private static final Logger LOGGER = LoggerFactory.getLogger(PageableController.class);
#Get(produces = APPLICATION_JSON, value = "/test")
public Page<String> getNames(Pageable pageable) {
LOGGER.info("pageable {}", pageable);
return Page.of(Arrays.asList("foo", "bar", "baz"), pageable, 3);
}
To call it we new to use the standard parameters names defined in DataConfiguration.PageableConfiguration.
DEFAULT_PAGE_PARAMETER "page"
DEFAULT_SIZE_PARAMETER "size"
DEFAULT_SORT_PARAMETER "sort"
If you want to use different parameters you can change it with properties:
micronaut:
data:
pageable:
max-page-size: 500
And you can test it with
#Test
void callsWithPageable() {
String uri = "/test?page=1&size=2";
Page<String> pages = client.toBlocking().retrieve(HttpRequest.GET(uri), pageOf(String.class));
assertThat(pages.getPageNumber(), is(1));
assertThat(pages.getTotalPages(), is(2));
assertThat(pages.getSize(), is(2));
assertThat(pages.getContent(), contains("foo", "bar", "baz"));
}
And, to make things even better, the client can convert the result to a page using the pageOf method that returns Argument>
In my application, I accept Pageable as well and I dont have any issues with it. The difference between mine and yours are:
My path is just #Get("/test") i.e. no {pageable} part.
I dont make my Pageable as #Nullable. From what I can trace from the micronaut code, it does not treat Pageable like any other object. It has special handling for it (like testing if the argument type is Pageable and if it is, then do certain things).
Can you try those two things?
"/test{?pageable}" Means to bind to a single query value called pageable
"/test{?pageable*}" Means to bind all query values to an argument called pageable
You want the latter

Can I register Orchard resources in an HtmlHelper?

I am aware that this violates the MVC principle and best practices.
I have a whole bunch of custom Angular components that each take a whole bunch of optional parameters and each require a different remote stylesheet and javascript file. I would like to render these with an HtmlHelper without having to manually include the right resources everywhere I use them.
I was hoping that this would do the trick but it doesn't
public static class HtmlExtensions
{
private static IResourceManager _resourceManager;
// Executed in the Activated method of an OrchardShellEvents implementation
public static void SetResourceManager(IResourceManager resourceManager)
{
_resourceManager = resourceManager;
}
public static MvcHtmlString Angular(this HtmlHelper helper, CustomAngularComponent component)
{
// Require the resources
var _styleRegister = new ResourceRegister(helper.ViewDataContainer, _resourceManager, "Style");
var _scriptRegister = new ResourceRegister(helper.ViewDataContainer, _resourceManager, "Script");
_styleRegister.Require(component.StyleSheet).AtHead();
if (!string.IsNullOrEmpty(component.Script))
{
_scriptRegister.Require(component.Script).AtFoot();
}
// Create tag
var tag = new TagBuilder(component.Tag);
tag.MergeAttributes(component.Parameters);
return new MvcHtmlString(tag.ToString(TagRenderMode.SelfClosing));
}
}
I could use an arbitrary Shape as a helper, something like:
#Display(New.Angular(Model: new CustomAngularComponent(...)))
but a helper with strongly typed parameters feels a lot better.
This comment on another Orchard question tipped me off. As it turns out, simply injecting Work<IResourceManager> and using it directly was enough to make my setup work. Please note that this does not conform to best MVC practices, by doing this I sacrifice maintainability in favor of readability.
public static class HtmlExtensions
{
private static Work<IResourceManager> _resourceManager;
// Executed in the Activated method of an OrchardShellEvents implementation
public static void SetResourceManager(Work<IResourceManager> resourceManager)
{
_resourceManager = resourceManager;
}
public static MvcHtmlString Angular(this HtmlHelper helper, CustomAngularComponent component)
{
// Require the resources
_resourceManager.Value.Require("stylesheet", component.StyleSheet).AtHead();
if (!string.IsNullOrEmpty(component.Script))
{
_resourceManager.Value.Require("script", component.Script).AtFoot();
}
// Create tag
var tag = new TagBuilder(component.Tag);
tag.MergeAttributes(component.Parameters);
return new MvcHtmlString(tag.ToString(TagRenderMode.SelfClosing));
}
}

Code restricting: Create of more than one object in private constructor in C#

I want to create a code in C# for Private constructor.
I want that it should allow only one object to be created but when I try to create more than one a message showing no more object can be created should be shown.
I don't want to use static constructor in this code.
How do I do that in C#?
You may use static counter or flag that will be set in your private counstructor to show that at least one instance were created.
But first of all, I suggest you to pay attention to Singleton pattern.
Simple, this is the classic singleton pattern:
public class MyClass
{
public static MyClass Instance;
private MyClass()
{
if (Instance != null)
throw new InvalidOperationException("no more object can be created");
// do other constructor logic
Instance = this;
}
}
Please note that synchronization has been left out. This code need synchronization for thread safe purpose.

Add behavior to existing implementation - C# / Design Pattern

My current implementation for service and business layer is straight forward as below.
public class MyEntity { }
// Business layer
public interface IBusiness { IList<MyEntity> GetEntities(); }
public class MyBusinessOne : IBusiness
{
public IList<MyEntity> GetEntities()
{
return new List<MyEntity>();
}
}
//factory
public static class Factory
{
public static T Create<T>() where T : class
{
return new MyBusinessOne() as T; // returns instance based on T
}
}
//Service layer
public class MyService
{
public IList<MyEntity> GetEntities()
{
return Factory.Create<IBusiness>().GetEntities();
}
}
We needed some changes in current implementation. Reason being data grew over the time and service & client cannot handle the volume of data. we needed to implement pagination to the current service. We also expect some more features (like return fault when data is more that threshold, apply filters etc), so the design needs to be updated.
Following is my new proposal.
public interface IBusiness
{
IList<MyEntity> GetEntities();
}
public interface IBehavior
{
IEnumerable<T> Apply<T>(IEnumerable<T> data);
}
public abstract class MyBusiness
{
protected List<IBehavior> Behaviors = new List<IBehavior>();
public void AddBehavior(IBehavior behavior)
{
Behaviors.Add(behavior);
}
}
public class PaginationBehavior : IBehavior
{
public int PageSize = 10;
public int PageNumber = 2;
public IEnumerable<T> Apply<T>(IEnumerable<T> data)
{
//apply behavior here
return data
.Skip(PageNumber * PageSize)
.Take(PageSize);
}
}
public class MyEntity { }
public class MyBusinessOne : MyBusiness, IBusiness
{
public IList<MyEntity> GetEntities()
{
IEnumerable<MyEntity> result = new List<MyEntity>();
this.Behaviors.ForEach(rs =>
{
result = rs.Apply<MyEntity>(result);
});
return result.ToList();
}
}
public static class Factory
{
public static T Create<T>(List<IBehavior> behaviors) where T : class
{
// returns instance based on T
var instance = new MyBusinessOne();
behaviors.ForEach(rs => instance.AddBehavior(rs));
return instance as T;
}
}
public class MyService
{
public IList<MyEntity> GetEntities(int currentPage)
{
List<IBehavior> behaviors = new List<IBehavior>() {
new PaginationBehavior() { PageNumber = currentPage, }
};
return Factory.Create<IBusiness>(behaviors).GetEntities();
}
}
Experts please suggest me if my implementation is correct or I am over killing it. If it correct what design pattern it is - Decorator or Visitor.
Also my service returns JSON string. How can I use this behavior collections to serialize only selected properties rather than entire entity. List of properties comes from user as request. (Kind of column picker)
Looks like I don't have enough points to comment on your question. So, I am gonna make some assumption as I am not a C# expert.
Assumption 1: Looks like you are getting the data first and then applying the pagination using behavior object. If so, this is a wrong approach. Lets say there are 500 records and you are showing 50 records per fetch. Instead of simply fetching 50 records from DB, you are fetching 500 records for 10 times and on top of it you are adding a costly filter. DB is better equipped to do this job that C# or Java.
I would not consider pagination as a behavior with respect to the service. Its the behavior of the presentation layer. Your service should only worry about 'Data Granularity'. Looks like one of your customer wants all the data in one go and others might want a subset of that data.
Option 1: In DAO layer, have two methods: one for pagination and other for regular fetch. Based on the incoming params decide which method to call.
Option 2: Create two methods at service level. One for a small subset of data and the other for the whole set of data. Since you said JSON, this should be Restful service. Then based on the incoming URL, properly call the correct method. If you use Jersey, this should be easy.
In a service, new behaviors can be added by simply exposing new methods or adding new params to existing methods/functionalities (just make sure those changes are backward compatible). We really don't need Decorator or Visitor pattern. The only concern is no existing user should be affected.

How to force the order of Installer Execution

I have been building a new .NET solu­tion with Cas­tle per­form­ing my DI.
Its now at the stage where i would like to con­trol the order in which my installers run. I have built indi­vid­ual classes which implement IWind­sorIn­staller to han­dle my core types — eg IRepos­i­tory, IMap­per and ISer­vice to name a few.
I see that its suggested i implement my own Installer­Fac­tory (guessing i just override Select) in this class.
Then use this new factory in my call to:
FromAssembly.InDirectory(new AssemblyFilter("bin loca­tion"));
My ques­tion — when over­rid­ing the save method — what is the best way to force the order of my installers.
I know its already solved but I couldn't find any example on how to actually implement the InstallerFactory so here's a solution if anyone is googling for it.
How to use:
[InstallerPriority(0)]
public class ImportantInstallerToRunFirst : IWindsorInstaller
{
public void Install(IWindsorContainer container, Castle.MicroKernel.SubSystems.Configuration.IConfigurationStore store)
{
// do registrations
}
}
Just add the InstallerPriority attribute with a priority to your "install-order-sensitive" classes. Installers will be sorted by ascending. Installers without priority will default to 100.
How to implement:
public class WindsorBootstrap : InstallerFactory
{
public override IEnumerable<Type> Select(IEnumerable<Type> installerTypes)
{
var retval = installerTypes.OrderBy(x => this.GetPriority(x));
return retval;
}
private int GetPriority(Type type)
{
var attribute = type.GetCustomAttributes(typeof(InstallerPriorityAttribute), false).FirstOrDefault() as InstallerPriorityAttribute;
return attribute != null ? attribute.Priority : InstallerPriorityAttribute.DefaultPriority;
}
}
[AttributeUsage(AttributeTargets.Class)]
public sealed class InstallerPriorityAttribute : Attribute
{
public const int DefaultPriority = 100;
public int Priority { get; private set; }
public InstallerPriorityAttribute(int priority)
{
this.Priority = priority;
}
}
When starting application, global.asax etc:
container.Install(FromAssembly.This(new WindsorBootstrap()));
You can call your installers in the order they need to be instantiated in Global.asax.cs or e.g. in a Bootstrapper class, which is called from Global.asax.cs.
IWindsorContainer container = new WindsorContainer()
.Install(
new LoggerInstaller() // No dependencies
, new PersistenceInstaller() // --""--
, new RepositoriesInstaller() // Depends on Persistence
, new ServicesInstaller() // Depends on Repositories
, new ControllersInstaller() // Depends on Services
);
They are instantiated in this order, and you can add a breakpoint after and check the container for "Potentially misconfigured components".
If there are any, check their Status->details, if not, it's the correct order.
This solution is quick and easy, the documentation mentions using a InstallerFactory Class for tighter control over your installers so if you have a ton of installers the other solution may fit better. (Using code as convention should not require tons of installers?)
http://docs.castleproject.org/Windsor.Installers.ashx#codeInstallerFactorycode_class_4
In the end i had to use InstallerFactory and implement the ordering rules as suggested previously by returning the IEnumerable<Type> with my specific order

Resources