Access to getDateFormat() from controller - Laravel - laravel

Is it possible to access the getDateFormat() method from a controller or command?
I can use it my models like this:
public function getCreatedAtAttribute($value)
{
$format = $this->getDateFormat();
return Carbon::createFromFormat($format, $value, 'UTC')->setTimezone(\Helper::getTimezone());
}
but when using it in my controller or command, like this $format = getDateFormat();, I get the following error:
local.ERROR: exception
'Symfony\Component\Debug\Exception\FatalErrorException' with message
'Call to undefined function App\Console\Commands\getDateFormat()'

Of course you cannot - cause it's a protected method of Model class.
/**
* Get the format for database stored dates.
*
* #return string
*/
protected function getDateFormat()
{
return $this->dateFormat ?: $this->getConnection()->getQueryGrammar()->getDateFormat();
}
And by default it's simply
/**
* Get the format for database stored dates.
*
* #return string
*/
public function getDateFormat()
{
return 'Y-m-d H:i:s';
}
Carbon instance uses this format as default so if you need to get Carbon date - just simply use Carbon::parse($value) - it will sure recognize this type of format. And by default doing (string)Carbon::parse($value) you will get date in this default format cause:
/**
* Format to use for __toString method when type juggling occurs.
*
* #var string
*/
protected static $toStringFormat = self::DEFAULT_TO_STRING_FORMAT;
/**
* Format the instance as a string using the set format
*
* #return string
*/
public function __toString()
{
return $this->format(static::$toStringFormat);
}
Also check Carbon documentation - there are a lot of modifiers like ->toDateString(), ->toDateTimeString()

getDateFormat() is not a native function in php if i remeber its use in drupal
so..
if in your $value you have a timestamp you can use getDate() this will return an array with minute seconde ...
or if your value isn't timestamp you can use dateTime() with format like
public function getCreatedAtAttribute($value)
{
$date = new DateTime($value);
$date->format('Y-m-d H:i:s');
return $date;
}
I hope this help you
good day

Related

how to save and retrieve base64 encoded data using Laravel model

I am doing a web app using Laravel 7 api.
I receive data with a json request that I must store in the db with a base64 encoding.
I store the data in this way:
public function create_request(Request $request)
{
$req_store = new Req;
$req_store->text = base64_encode($request->input('requestInformations.text'));
$req_store->save();
}
Then obviously to retrieve the data of the text column I must use everytime base64_decode().
My question is that: is there a way to say to Laravel that everytime that I store a new request the column text must be authomatically encoded to base64 and everytime that I retrieve that data from the database the field text must be authomatically base64 decoded? I suppose I must write something in the Req.php model...
Can help?
You should use Accessors & Mutators for this. Please follow the link https://laravel.com/docs/7.x/eloquent-mutators#accessors-and-mutators
public function getTextAttribute($value)
{
return base64_decode($value);
}
public function setTextAttribute($value)
{
$this->attributes['text'] = base64_encode($value);
}
You may use a custom caster
https://laravel.com/docs/7.x/eloquent-mutators#custom-casts
<?php
namespace App\Casts;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
class Base64 implements CastsAttributes
{
/**
* Cast the given value.
*
* #param \Illuminate\Database\Eloquent\Model $model
* #param string $key
* #param mixed $value
* #param array $attributes
* #return mixed
*/
public function get($model, $key, $value, $attributes)
{
return base64_decode($value);
}
/**
* Prepare the given value for storage.
*
* #param \Illuminate\Database\Eloquent\Model $model
* #param string $key
* #param array $value
* #param array $attributes
* #return string
*/
public function set($model, $key, $value, $attributes)
{
return base64_encode($value);
}
}
And in your model
use App\Casts\Base64;
/**
* The attributes that should be cast.
*
* #var array
*/
protected $casts = [
'text' => Base64::class,
];

Query to all contents of tabel in related model in laravel

Assume we have a model name "Article" in Laravel and want to make query for retrieving latest articles, so one way is to define a method in the "Article" model like this:
public function newArticle()
{
return static::where('created_at', '>', Carbon::subMonths(1));
}
The question is, why we should use
static::
in the above code?
Is it possible to use
$this or self::
instead of
"static::" ?
Thanks in advance,
You could but there is not interest because:
where method does not exist statically on Illuminate\Database\Eloquent\Model class, so it calls __callStatic magic method which delegates the call to an instance
/**
* Handle dynamic static method calls into the method.
*
* #param string $method
* #param array $parameters
* #return mixed
*/
public static function __callStatic($method, $parameters)
{
return (new static)->$method(...$parameters);
}
It calls where method on instance but it does not exist either, so it calls __call magic method which delegates it an Illuminate\Database\Eloquent\Builder instance.
/**
* Handle dynamic method calls into the model.
*
* #param string $method
* #param array $parameters
* #return mixed
*/
public function __call($method, $parameters)
{
if (in_array($method, ['increment', 'decrement'])) {
return $this->$method(...$parameters);
}
return $this->forwardCallTo($this->newQuery(), $method, $parameters);
}
/**
* Get a new query builder for the model's table.
*
* #return \Illuminate\Database\Eloquent\Builder
*/
public function newQuery()
{
return $this->registerGlobalScopes($this->newQueryWithoutScopes());
}

Doctrine ArrayCollection matching criteria function results in Undefined property: MyEntity::$1 (Symfony 3.4)

I defined an Entity "TrainingProgressEntry" as an #ORM\Entity and a "training" property like this:
/**
* #ORM\ManyToOne(targetEntity="Training", inversedBy="training_progress")
* #ORM\JoinColumn(name="training_id", referencedColumnName="id")
*/
protected $training;
The matching #ORM\Entity "Training" defines a property "training_progress" like
/**
* #ORM\OneToMany(targetEntity="TrainingProgressEntry", mappedBy="training", cascade={"remove"})
* #ORM\OrderBy({"entry_date" = "ASC"})
*/
protected $training_progress;
and a getter method for it like this
/**
* Get trainingProgress
*
* #return \Doctrine\Common\Collections\ArrayCollection
*/
public function getTrainingProgress()
{
return $this->training_progress;
}
Finaly I define a getter method intended to return only entries which have a date newer then some reference date:
/**
* #return \Doctrine\Common\Collections\ArrayCollection
*/
public function getTrainingProgressSinceStart()
{
$startTime = $this->getUser()->getStart();
$criteria = Criteria::create()
->andWhere(Criteria::expr()->gt('entry_date', $startTime))
->orderBy(['entry_date', 'ASC']);
return $this->getTrainingProgress()->matching($criteria);
}
When using this last function I get the following "ContextErrorException":
Notice: Undefined property: AppBundle\Entity\TrainingProgressEntry::$1
coming from
vendor\doctrine\collections\lib\Doctrine\Common\Collections\Expr\ClosureExpressionVisitor.php
when trying to "return $object->$field".
The trace shows that it is caused by the above mentioned function "getTrainingProgressSinceStart()" in the line
return $this->getTrainingProgress()->matching($criteria);
For some reason the matching function doesn't seem to be recognized ors something...
I don't really know what to look for now.
Any hints are very welcome.
You probably already solved this, but I will answer it either way for reference for other people.
The method: orderBy of criteria accepts an array with the Key, being the field and the sorting order being the value, so where you have:
/**
* #return \Doctrine\Common\Collections\ArrayCollection
*/
public function getTrainingProgressSinceStart()
{
$startTime = $this->getUser()->getStart();
$criteria = Criteria::create()
->andWhere(Criteria::expr()->gt('entry_date', $startTime))
->orderBy(['entry_date', 'ASC']);
return $this->getTrainingProgress()->matching($criteria);
}
It should really be ['entry_date' => 'ASC']:
/**
* #return \Doctrine\Common\Collections\ArrayCollection
*/
public function getTrainingProgressSinceStart()
{
$startTime = $this->getUser()->getStart();
$criteria = Criteria::create()
->andWhere(Criteria::expr()->gt('entry_date', $startTime))
->orderBy(['entry_date' => 'ASC']);
return $this->getTrainingProgress()->matching($criteria);
}
Source: https://github.com/doctrine/collections/blob/c23e14f69b6d2d1d1e389bc8868500efc447af7b/lib/Doctrine/Common/Collections/Criteria.php#L152

How where method works in Laravel Models?

We frequently use where method with our models but it's not defined in Base Model class so how laravel is doing this magic?
e.g MyModel::where('id, 2)->get();
The above where will definitely fetch the record having id equals 2 but where & how is this happening! I traced back to the Base Model in Laravel but didn't found where method!
Some of this magic resides behind a Facade Pattern https://www.tutorialspoint.com/design_pattern/facade_pattern.htm
But in Laravel case, they use Static methods in their Facades (\Illuminate\Support\Facades namespace), and create instance automatically to call those methods from instance, so you don't have to instantiate the Class yourself to start using the methods. For example when you use DB::, Cache::, Str:: to call static method.
However for Eloquent, Laravel uses this approach more internally without exposing the Model to \Illuminate\Support\Facades namespace, by configuring Eloquent Model to instantiate automatically the Model and creates\Illuminate\Database\Eloquent\Builder Eloquent Builder and forward those static methods call to the Eloquent Builder instance or to Query Builder one.
A model extends \Illuminate\Database\Eloquent\Model which has a special way to call any method statically at runtime.
/**
* Handle dynamic static method calls into the method.
*
* #param string $method
* #param array $parameters
* #return mixed
*/
public static function __callStatic($method, $parameters)
{
return (new static)->$method(...$parameters);
}
So at a certain point, the Builder classes an Eloquent use a Trait
use Illuminate\Support\Traits\ForwardsCalls;
to forward call to each others so that a Model can forward its static method to method from the created instance of Eloquent builder. So if model does not have where method, it will forward it to the where method of the newly created nstance of Eloquent Builder.
From a look of Facade Pattern, here is how Laravel calls a method from an instance but in a static way :
// \Illuminate\Support\Facades\Facade.php
/**
* Handle dynamic, static calls to the object.
*
* #param string $method
* #param array $args
* #return mixed
*
* #throws \RuntimeException
*/
public static function __callStatic($method, $args)
{
$instance = static::getFacadeRoot();
if (! $instance) {
throw new RuntimeException('A facade root has not been set.');
}
return $instance->$method(...$args);
}
So calling User::where() creates an instance of \Illuminate\Database\Eloquent\Builder and forward method call to that instance, here is the method :
// Illuminate\Database\Eloquent\Builder.php
/**
* Add a basic where clause to the query.
*
* #param string|array|\Closure $column
* #param mixed $operator
* #param mixed $value
* #param string $boolean
* #return $this
*/
public function where($column, $operator = null, $value = null, $boolean = 'and')
{
if ($column instanceof Closure) {
$column($query = $this->model->newModelQuery());
$this->query->addNestedWhereQuery($query->getQuery(), $boolean);
} else {
$this->query->where(...func_get_args());
}
return $this;
}
You can find the method here . framework/src/Illuminate/Database/Eloquent/Builder.php
public function where($column, $operator = null, $value = null, $boolean = 'and')
{
if ($column instanceof Closure) {
$column($query = $this->model->newModelQuery());
$this->query->addNestedWhereQuery($query->getQuery(), $boolean);
} else {
$this->query->where(...func_get_args());
}
return $this;
}
Some more info about it

What is the best way for reusable values throughout the application in Symfony 3?

I want to have a file or list that I can update easily with values that might change throughout my application.
I don't really want to hard code text values into the templates. I prefer to have all of these values in one place and labelled correctly.
Examples of values that might get updated are:
Page title
Logo text
Brand or company name
I have thought about two options:
Add them to the twig config in config.yml. This is a bit messy and doesn't seem organised if I decide to put a lot of values there.
Make a database table for these and include the entity in each controller where I need to use the values. This might be creating too much work.
Are there any other options or are one of these more suitable?
Thank you.
You need to create a twig function and use it to return the value you want. For example:
namespace AppBundle\Twig;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
use Symfony\Component\DependencyInjection\ContainerInterface;
class TwigExtension extends \Twig_Extension implements ContainerAwareInterface
{
use ContainerAwareTrait;
/**
* #var ContainerInterface
*/
protected $container;
public function getFunctions()
{
return array(
new \Twig_SimpleFunction('parameter', function($name)
{
try {
return $this->container->getParameter($name);
} catch(\Exception $exception) {
return "";
}
})
);
}
/**
* Returns the name of the extension.
*
* #return string The extension name
*/
public function getName()
{
return 'app.twig.extension';
}
}
This will create a function called parameter and once you call it in twig {{ parameter('my.parameter') }} it will return the parameter. You need to load it as a service, which you can do by adding the following to your services.yml file:
app.twig.extension:
class: AppBundle\Twig\TwigExtension
calls:
- [setContainer, ["#service_container"]]
tags:
- { name: twig.extension }
From personal experience people usually want to be able to change some of the parameters. This is why I usually prefer to create a Setting or Parameter entity which would look something like this:
/**
* Setting
*
* #ORM\Table(name="my_parameters")
* #ORM\Entity(repositoryClass="AppBundle\Repository\ParameterRepository")
*/
class Parameter
{
/**
* #var integer
*
* #ORM\Id
* #ORM\Column(name="parameter_id", type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* #var string
*
* #ORM\Column(name="value", type="text", nullable=true)
*/
private $value;
/**
* #param string|null $name
* #param string|null $value
*/
public function __construct($name = null, $value = null)
{
$this->setName($name);
$this->setValue($value);
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
*
* #return Parameter
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set value
*
* #param string $value
*
* #return Parameter
*/
public function setValue($value = null)
{
$this->value = serialize($value);
return $this;
}
/**
* Get value
*
* #return string
*/
public function getValue()
{
$data = #unserialize($this->value);
return $this->value === 'b:0;' || $data !== false ? $this->value = $data : null;
}
}
Then I would add a CompilerPass which will help get all of the parameters from the database and cache them so that your app doesn't make unnecessary sql queries to the database. That might look something similar to the following class:
// AppBundle/DependencyInjection/Compiler/ParamsCompilerPass.php
namespace AppBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
class ParamsCompilerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
$em = $container->get('doctrine.orm.default_entity_manager');
$settings = $em->getRepository('AppBundle:Parameter')->findAll();
foreach($settings as $setting) {
// I like to prefix the parameters with "app."
// to avoid any collision with existing parameters.
$container->setParameter('app.'.strtolower($setting->getName()), $setting->getValue());
}
}
}
And finally, in your bundle class (i.e. src/AppBundle/AppBundle.php) you add the compiler pass:
namespace AppBundle;
use AppBundle\DependencyInjection\Compiler\ParamsCompilerPass;
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class AppBundle extends Bundle
{
public function build(ContainerBuilder $builder)
{
parent::build($builder);
$builder->addCompilerPass(new ParamsCompilerPass(), , PassConfig::TYPE_AFTER_REMOVING);
}
}
Now you can create a DoctrineFixture template to load the parameters you use all the time. With the TwigExtension you will still be able to call the parameter from the twig template and you can create a web UI to change some of the parameters/settings.

Resources