(Symfony 4) How to implement a constants class - symfony

I'm trying to have constants everywhere in my code so I don't have to just stick numbers, I know that's bad practice.
So in my root folder I put a class constants, like this:
namespace App;
class Constants{
public const FREE_TIER = 0;
}
So I include the "use App\Constants;" in my repository class.
Here is the function I try to access my constants class in:
use App\Constants; /* earlier on */
/**
* #param User $user
* #return array
*/
public function countFreeTiers() : array
{
$qb = $this->createQueryBuilder('t');
$qb->select('COUNT(t.tierNumber)')
->where('t.tierNumber = :freeTier')
->groupBy('t.tierNumber')
->orderBy('t.tierNumber', 'ASC')
->setParameter('freeTier', Constants::FREE_TIER /* error here */)
->setParameter('true', true);
$query = $qb->getQuery();
return $query->getResult();
}
This is the error I get:
Attempted to load class "Constants" from namespace "App".
Did you forget a "use" statement for another namespace?
Am I not allowed to just use the "App" namespace?

This is cerad's solution, not mine.
My problem was that my Constants.php was in the root folder of the project.
I had to move the Constants.php file to inside the src folder, so putting it at the root of src (as opposed to the root of the project) fixed it.

You can try to put the class file into 'src/Utilities' and symfony will auto load it.

Related

Class Not Found Error with custom Class Concrete5.8

New to C5 and Namespaces. Trying to add my own class, but keep getting error that it can't find the class, even though PHPstorm seems to know where it is. Seems simple enough but I'm missing something.
Path to class application/src/cpi/funcs/Utils.php
Class
<?php
namespace Application\Src\Cpi\Funcs;
defined('C5_EXECUTE') or die(_("Access Denied."));
class Utils
{
public function Getcreditcard_year($y = 10)
{
$currentYear = date("Y");
$currentYearVal = date("y");
$year_list = array();
for ($i = 1; $i <= $y; $i++) {
$year_list[$currentYearVal] = $currentYear;
$currentYear = $currentYear + 1;
$currentYearVal = $currentYearVal + 1;
}
return $year_list;
}
}
?>
Code in View
<?php
use Application\Src\Cpi\Funcs\Utils;
$years = new Utils();
//$years->Getcreditcard_year();
?>
A few core features have been updated in Concrete5.8 that change the way you should use namespaces. You have two options to go about this.
Option 1:
Concrete5.8 has had some minor updates to its core Routing which now uses application/src/concrete/ instead of application/src/ to search for your custom classes, and is triggered to look in to that folder when a class has \Application\Concrete\ in its namespace. Basically, you would do the following:
Class
Update the namespace of your class and move it to application/src/Concrete/Cpi/Funcs/Utils.php
<?php
namespace Application\Concrete\Cpi\Funcs;
class Utils{
...
}
Code In View
use \Application\Concrete\Cpi\Funcs\Utils
...
Option 2
Re-enable the legacy Routing to read in application/src/ when \Application\Src\ is used in a class's namespace.
C5 core team have created a function to enable legacy namespaces, enableLegacyNamespace(), which you need call during the bootstrap. I've added the coded in my application/bootstrap/start.php file. Not sure if it is the best place to enable it but it works. The file now looks like this:
<?php
use Concrete\Core\Application\Application;
use Concrete\Core\Foundation\ClassLoader;
/*
* ----------------------------------------------------------------------------
* Instantiate concrete5
* ----------------------------------------------------------------------------
*/
// This line allows us now to use \Application\Src\ in our class namespace
ClassLoader::getInstance()->enableLegacyNamespace();
$app = new Application();
...
Using this option means you don't have to modify or move your class and can use as you have it set up currently.
Just sharing some advice
I have my concrete5.8 sites to use both options. For my custom classes, I use option 2 but when I want to overwrite or expand a core class I use option 1 and place the file inside application/src/concrete/ and use the \Application\Concrete\ namespacing.
e.g.
Say, I want to extend the core PageController class. First, I create the php file and add it under application/src/concrete/. The file path would look like this: application\src\Concrete\Page\Controller\PageController.php. I am trying to mimic the folder path of its core file which is found in concrete\src\Page\Controller\PageController.php.
Class
<?php
namespace Application\Concrete\Page\Controller;
...
class PageController extends \Concrete\Core\Page\Controller\PageController
{
...
}
Then overwrite the core alias pathing with your custom alias inside application/config/app.php so concrete knows to read from a custom class instead:
return [
'aliases' => [
// extend the page controller class
'PageController' => '\Application\Concrete\Page\Controller\PageController',
];
Hope this helps.
Cheers.
Gianni's answer is still valid on c5 8.5.1, incase anyone is wondering. The correct path is application/src/Concrete, not application/src/concrete. If the c is not capitalized, c5 will through an error for not being able to find your class.

Symfony Options Resolver allow Invalid Options

I am using the optionsResolver component in a silex project to resolve options for configuration. If I don't explicitly set options with setRequired, setOptional, or setDefaults I get an error Fatal error: Uncaught exception 'Symfony\Component\OptionsResolver\Exception\InvalidOptionsException' with message 'The option "option.key" does not exist. Known options are: ...
I want to allow options that are not defined with those methods. I tried to use my own class that extends the class but the class uses to many private methods that would require me to copy/paste most of the class.
Is there a better way to do this?
I use this component in ApiGen a I think you can't add options that aren't specified.
If you know all options, it is the best practice to name them all.
What is your specific use case?
I solved this by creating two resolvers. One with the fixed option list, the other is where I add options dynamically. I then split the incoming options array into two arrays using array_filter:
$dynamicOptions = array_filter($options, function($k) use ($fixedOptionKeys) {
if (!in_array($k, $fixedOptionKeys)) {
return true;
}
}, ARRAY_FILTER_USE_KEY);
$fixedOptions = array_filter($options, function($k) use ($fixedOptionKeys) {
if (in_array($k, $fixedOptionKeys)) {
return true;
}
}, ARRAY_FILTER_USE_KEY);
I think this solution will be more pretty and simplier.
Just create your own optionsResolver that extends the symfony base one and override the 'resolve' method
Hope it will help
use Symfony\Component\OptionsResolver\OptionsResolver;
class ExtraOptionsResolver extends OptionsResolver
{
/**
* Strip options that have been passed to
* this method to be resolved, and that have not been defined as default or required options
* The default behaviour is to throw an UndefinedOptionsException
*
* #author Seif
*/
public function resolve(array $options = array())
{
// passing by ref in loops is discouraged, we'll make a copy
$transformedInputOptions = $options;
foreach ($options as $key => $option) {
if (!in_array($key, $this->getDefinedOptions())) { // option was not defined
unset($transformedInputOptions[$key]); // we will eject it from options list
}
}
return parent::resolve($transformedInputOptions);
}
}

Symfony2 doesn't seem to recognize my repository class

I am encountering the error Undefined method 'findAllCtrs'. The method name must start with either findBy or findOneBy!
I've tried all the other solutions on StackOverflow regarding this problem. I've cleared cache, cleared meta data cache, checked the namespaces and folder entities but still no fix.
Here is my entity:
namespace CFS\Bundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Ref
*
* #ORM\Table(name="ref", indexes={#ORM\Index(name="refno", columns={"refno"}), #ORM\Index(name="ctrno", columns={"ctrno"})})
* #ORM\Entity(repositoryClass="CFS\Bundle\Entity\RefRepository")
*/
class Ref
{
My repository class:
namespace CFS\Bundle\Entity;
use Doctrine\ORM\EntityRepository;
class RefRepository extends EntityRepository
{
public function findAllCtrs()
{
$query = $this->getEntityManager()
->createQuery('
SELECT
r.refno, r.ctrno
FROM
CFSBundle:Ref r
ORDER BY
r.refno DESC
');
try {
return $query->getResult();
} catch(\Doctrine\ORM\NoResultException $e) {
return null;
}
}
}
And I tried calling the method in my controller with:
$em = $this->getDoctrine()->getManager();
$containers = $em->getRepository('CFSBundle:Ref')
->findAllCtrs();
I did noticed that when I generate entities in the command line php app/console doctrine:generate:entities CFSBundle it is not recognizing my RefRepository.php file. What else could I have missed?
I stuck with a similar error too, after spending a day searching for a solution I found a typo in my annotation referencing the repository class.
But I don't see a mistake in the code you provided, hence it should work…
Did you read https://stackoverflow.com/a/15184084/1781752 ?
There seemed to be problems mixing yml mappings and annotations.

Using distinct Doctrine2

I am developing an application in symfony2 and using doctrine2. I created a custom repository class that has one function:
<?php
namespace Anotatzailea\AnotatzaileaBundle\Repository;
use Doctrine\ORM\EntityRepository;
/**
* InterpretatzeaRepository
*
* This class was generated by the Doctrine ORM. Add your own custom
* repository methods below.
*/
class InterpretatzeaRepository extends EntityRepository
{
public function getInterpDesberdinak($value)
{
$qb = $this->createQueryBuilder('c')
->select('DISTINCT c.attribute')
->where('c.fer = :Value')
->setParameter('Value', $value);
$Emaitza = $qb->getQuery()->getResult();
return $Emaitza;
}
}
What I want to get with this function is an array of all the "Interpretatzea" objects that have a distinct c.attribute and all have c.fer = value. Is the query correct? I would also want to know how to pass the value parameter to the repository function. Thanks
A cursory look at your repository method suggests it looks okay :) IIRC, I think the use of DISTINCT there is fine. If you do have problems you can always do a GROUP BY instead.
As for calling the repo method in a controller and passing a $value variable to it, that's pretty straightforward; for example:
// in your controller
$value = 'foo';
// get doctrine connection from DI, etc.
$em = $this->getDoctrine()
->getEntityManager();
// get the repository object for your
// entity and call your repository method
$result = $em->getRepository('AnotatzaileaAnotatzaileaBundle:Interpretatzea')
->getInterpDesberdinak($value);
// ... do something with your $result here
Note you use a concatenated version of your namespace and bundle, followed by a colon and the entity; e.g: AcmeTestBundle:User
Hope this helps :)

How do I access a repository from the bundle class in symfony2?

So, I'm using the bundle class to do most of my work as I dont need controllers (src\CSFs\QuicklinksBundle\CSFsQuicklinksBundle.php).
From the FrontController of another bundle, I get the quicklinks bundle, inject the container object into the bundle class (above) and then, within the bundle class, extract templating to return HTML, this works fine. However, I'm having trouble with repositories.
/**
* Get the container object, so we can use all the symfony2 fun stuffs
*/
public function injectContainer($cont)
{
// Template
$this->tpl = $cont->get('templating');
// EM
$this->em = $cont->get('doctrine')->getEntityManager();
}
/**
*
**/
public function doStuff()
{
$products = $this->em->getRepository('QuicklinksBundle:Quicklinks')
->getUsersWithQuicklinks();
}
The error I get is:
Unknown Entity namespace alias 'QuicklinksBundle'.
I have both the generated entity file and a repository class with the getUsersWithQuicklinks() method defined.
How do I get the entity manager to know about my repositories?
Thanks,
Mike
Change:
$this->em->getRepository('QuicklinksBundle:Quicklinks')
To:
$this->em->getRepository('CSFsQuicklinksBundle:Quicklinks')
And I'm assuming you have an Entity named 'Quicklinks'

Resources