Plugin architecture, menu and services - Extensible context based menus - doctrine-orm

Currently I am writing an app that shall be extended using bundles.
Now the app registered the menu "related" as a service.
Bundle A shall be able to extend the menu and add a link to "imprint".
Bundle B shall be able to extend the menu by adding "disable" and "rename" menu items,
but only when the current doctrine entity is \App\Entity\User.
The target routes will need the ID of the current shown doctrine entity.
Currently I am doing this via events. But as those things above are not events the attempt is wrong.
In addition I don't know how to access or register the current shown doctrine repo / entity.
How to correctly solve this in Symfony?
Is there a neat way to save some performance?
I am thinking of code that will be executed with every request.
Someone in the IRC/Freenode told me, that Symfony has some solutions to avoid such calls for "almost static data".

Related

Dynamic database connection in Symfony 4

I am setting up a multi tenant Symfony 4 application where each tenant has it's own database.
I've set up two database connections in the doctrine.yaml config. One of the connections is static based on an env variable. The other one should have a dynamic URL based on a credential provider service.
doctrine:
dbal:
connections:
default:
url: "#=service('provider.db.credentials').getUrl()"
The above expression "#=service('provider.db.credentials').getUrl()" is not being parsed though.
When injecting "#=service('provider.db.credentials').getUrl()" as argument into another service the result of getUrl() on the provider.db.credentials service is injected. But when using it in the connection configuration for doctrine the expression is not being parsed.
Does anyone have an idea how to solve this?
You're trying to rely on ability of Symfony services definition to use expressions for defining certain aspects of services. However you need to remember that this functionality is part of Dependency Injection component which is able (but not limited to) to use configuration files for services. To be more precise - this functionality is provided by configuration loaders, you can take a look here for example of how it is handled by Yaml configuration loader.
On the other hand configuration for Doctrine bundle, you're trying to use is provided by Config component. A fact that Dependency Injection component uses same file formats as Config component do may cause an impression that these cases are handled in the same way, but actually they're completely different.
To sum it up: expression inside Doctrine configuration does not work as you expecting because Doctrine bundle configuration processor doesn't expect to get an Expression Language expression and doesn't have support for handling them.
While explanations given above are, hopefully, answers your question - you're probably expecting to get some information about how to actually solve your problem.
There is at least 2 possible ways to do it, but choosing correct way may require some additional information which is out of scope of this question.
In a case if you know which connection to choose at a time of container building (your code assumes that it is a case, but you may not be aware about it) - then you should use compiler pass mechanism yo update Doctrine DBAL services definitions (which may be quite tricky). Reason for this non-trivial process is that configurations are loaded at the early stages of container building process and provides no extension points. You can take a look into sources if necessary. Anyway, while possible, I would not recommend you to go in this way and most likely you will not need it because (I suppose) you need to select connection in runtime rather then in container building time.
Probably more correct approach is to create own wrapper of DBAL Connection class that will maintain list of actual connections and will provide required connection depending on your application's logic. You can refer to implementation details of DBAL sharding feature as example. Wrapper class can be defined directly through Doctrine bundle configuration by using wrapper_class key for dbal configuration

Sitecore 8: how to track Content Editors activity?

We have a website featuring Sitecore 8.1 with multiple content editors. Is there any way to log their activity, as in listing the actions they have performed in terms of editing/publishing/unpublishing?
We had a problem last week which I suspect being caused by someone unpublishing the wrong item, but I need to make sure this is the case, or at least I would like this ability in the future.
Do I need to create my own event-triggered logging?
There's nothing fully out of the box to provide those reports in Sitecore. You can take a look at the Sitecore Audit Trail module which will log all the "editor action" audit information into a separate log4net appender. You can find more information on the module in this blog post, but note that the module is only mark as compatible to Sitecore 7.5, it should not be hard to make this work with Sitecore 8.1, namely updating the appender config since the log4net config is now within the <sitecore> node in config.
Sitecore does log content editor actions out of the box in the normal log files (in Data\logs), they start with "AUDIT" so you can find them. It logs things such as items being saved, publishes starting, etc. Do a search in the log files to find them.
You can get these saved to a separate log file for easier review: https://sdn.sitecore.net/scrapbook/how%20to%20make%20sitecore%206%20write%20audit%20log%20to%20its%20own%20file.aspx
This still works in Sitecore 8 except the setting is in App_Config/Sitecore.config now.
You can use Sitecore Advanced System Reporter
Sitecore 6 ships with a very useful function called My Locked Items. At times, though, admin users may want to see all locked items, not just those locked by them. I wrote a little application to do just that. Then I thought of making it more generic, so that one could create other type of reports easily. The result is a little framework which allows to create many types of reports in very short time. In this module I provide this framework together with many useful example reports like:
items modified updated in the last X days
items that have more than X children
items that are publishable but either do not exist or have a different version in the web
database.
items that are based on a particular template
items with validation errors
which templates have been linked to a workflow
locked items
publishable items with broken links
audit information
errors in the log files
items that have stayed in the same workflow state for more than X days
and more.
You can now also parametrise those reports, save them as links in the desktop, export them, or even create a scheduled task that emails some of them automatically. In addition, you can also apply commands to the items reported.
You can download the module from : https://marketplace.sitecore.net/en/Modules/A/Advanced_System_Reporter.aspx
Module is available for Sitecore 6.4 to 8. I don't know if has the functionality you look but you can customize it.
You can check this blogpost how to extend it: http://www.seanholmesby.com/sitecore-auditing-with-the-advanced-system-reporter/
Update
Install the module
Run the module and choose reports like in picture.
Run the report
View the report or export it like csv, excel or xml .

sitecore is failing to publish language versions to web database

We have upgraded Sitecore to 7.1, but we are experiencing a problem with publishing.
We create a new item in the master database in English, then we publish this item, switch to the web database to check if it's there, which it is, however... The item does not have a version! Therefore the item is not displaying on the website.
Any ideas as to what could be causing this?
Thanks.
I was having the same issue with Sitecore 8+ where i was able to add language specific content but couldn't publish it. Figured out how to resolve it
1) First Language needs to be registered in \sitecore\system\languages by defining the language to be use.
2) Publish these language items first before publishing content else the behavior will be the same.
3) After publishing languages, then publish the content. In the publish window you will see the language under "Publishing language" section and select the language to publish the content.
Make sure that parent items have a version as well and are also in final state if they are part of a workflow.
I had problems with publishing because I didn't have a language version in one of my parents. In my case it was a parent folder under the content node.
Hope it helps.
Al
Please try republishing your entire site. In some cases, a part of the tree hierarchy might be missing in the Web DB, due to which, publishing the child nodes wouldnt work. Republishing the site can eliminate this chance.
This has been resolved.
It turns out that the SQL server did not have enough space for a full publish. A full publish had been attempted and failed due to the lack of space on the SQL server. subsequently this had corrupted the database.
We had to restore an earlier version of the database and ensure the SQL server had plenty of space for the full publish to finish.
I ran into this issue earlier with my Sitecore 7.2 upgrade. The key here is to ensure the items, templates and layouts (associated with the item) all has appropriate language+versions in master db. In my case, we were also using Partial Language fallback and needed to make that was working proper as well.
Once you identify the item (with missing versions), add them and republish the whole item. For few template types I noticed Sitecore was still not publishing properly. Ex: Items based off Sublayout Folder template. The fix was easy in this case as I changed the template type to Folder and republished.
Also switch to web database in sitecore client and ensure you are able to preview the item (from web db)
Hope this helps.

APEX 4.0 : how to copy page from one application to another application in APEX

Please help me how to copy a page from the existing application of Apex to another work space of Apex application.
You can't do this out of the box.
Beside workspace ids, the application id also matters. If you have 2 different workspaces and the same application in it but with different IDs, this further complicates things.
What you could always do is export the complete application, import it but use a different id so you don't overwrite the existing one, and then create a new page as a copy of the newly imported application's page.
Antoher way would be to edit the exported PAGE SQL file but, let me stress this, this is not recommended. And as so graciously stated in the OTN forums now and again, if you'd require support with an application/apex issue and they would find you were messing around in the sql files you'd not get support there. Only do this when you UNDERSTAND and KNOW what you're about to do! If you alter the code without understanding what you are doing you could be in a far worse situation than the one you started in. Any other case, follow the application export/import/copy line.
Anyway, I was in a position where workspace IDs differed but application IDs not. In this case altering the exported file is quite trivial and requires editing only 1 (one) line and concerns this piece of code:
begin
-- Assumes you are running the script connected to SQL*Plus as the Oracle user APEX_040200 or as the owner (parsing schema) of the application.
wwv_flow_api.set_security_group_id(p_security_group_id=>nvl(wwv_flow_application_install.get_workspace_id,27000294100083787867));
end;
/
This is one of the first pieces of code in the exported page file. As you can see, the workspace ID is set here. If attempted to be imported into an application (even if the app id matches the one you're trying to import to) you'd get an error. Change the ID to the one matching the workspace however and it'll work. Of course, you need to know the workspace IDs, and you can find these by executing this select on your apex environment(s?)
select workspace, workspace_display_name, workspace_id from apex_workspaces
Some good advice:
If you're still in the start-up phase of your apex installation, you might want to make sure that your workspace ids are identical. For example, with a test and production environment having identical workspace and application ids is very interesting. You'd have 2 instances (2 database installations on 2 different servers), but want the IDs to be the same.
To make sure of this, you can EXPORT the workspace from one environment and then IMPORT it into the other one. You can do that from the instance administration in apex, ie the internal workspace.
This is now supported in APEX version 4.2 - per Oracle doc...
7.3.4 Copying a Database Application Page
You can copy a page from the current application or from another application. During the copy process, you can also copy shared components or change mappings to shared components in the target application.
To copy a page:
Navigate to the application you want to copy to:
Navigate to the Workspace home page.
Click the Application Builder icon.
Select an application.
Select a page.
The Page Definition appears.
In Tree view:
Under Page Rendering, select the page name.
Right-click and select copy.
In Component view:
Under Page, click the Copy icon.
For Copy Page Option, select one of the following:
Page in this application
Page in another application
Follow the on-screen instructions.
In APEX 4.0 to copy a page from any Application:
Edit any page in your Application
Hit the Createâ–¼ button
Choose New page as a copy

Programmatically accessing sitecore layouts, templates and moving it to other site

We have a need to programmatically access the layouts/ templates of one sitecore site and move it to another site under different folders basically the intent is to restructure the existing site which is already in production.
Could anyone tell me how do we go about it?
Instead of writing a custom "one-time-use" tool for this, I would recommend you to get advantage of a standard "Transfer Items" application. You can find it in Sitecore Control Panel: go to Database > Transfer Items to Another Database.
So, what you basically need to do:
plug in the master database from the target new site to this older site, like "master_new" or something. This will require the web.config modification. The section on SDN about publishing targets should have a guideline how to do this
run the "Transfer Items" application, select the templates / layouts you needs on the first page, select this "master_new" database as a target database and the place in the content tree to transfer to on the second one
run the actual transfer
If your layouts / templates are groups into folders, this process will take the minimal time - much less comparing to creating your custom script...
UPDATE: Some sample code how to trigger this application programmatically:
UrlString url = new UrlString(UIUtil.GetUri("control:TransferToDatabase"));
Context.ClientPage.ClientResponse.ShowModalDialog(url.ToString());
I would look into using Sitecore Powershell Extensions (look at marketplace). It is a perfect fit for a usecase like this.